From 80ad364cd0d0d3ae6bf386c60d44b8ccbbd60c80 Mon Sep 17 00:00:00 2001 From: Lokesh2Arvind Date: Tue, 14 Oct 2025 14:40:23 +0530 Subject: [PATCH 1/3] added nansen action directory --- .../Portfolio/getDefiHoldingsAction.ts | 236 ++++++++++++++ .../actions/NansenAction/Portfolio/index.ts | 1 + .../Profiler/getCounterpartiesAction.ts | 233 ++++++++++++++ .../Profiler/getCurrentBalanceAction.ts | 213 +++++++++++++ .../Profiler/getHistoricalBalanceAction.ts | 224 ++++++++++++++ .../NansenAction/Profiler/getLabelsAction.ts | 220 +++++++++++++ .../NansenAction/Profiler/getPnlAction.ts | 238 +++++++++++++++ .../Profiler/getPnlSummaryAction.ts | 233 ++++++++++++++ .../Profiler/getRelatedWalletsAction.ts | 238 +++++++++++++++ .../Profiler/getTransactionLookupAction.ts | 228 ++++++++++++++ .../Profiler/getTransactionsAction.ts | 231 ++++++++++++++ .../actions/NansenAction/Profiler/index.ts | 9 + .../SmartMoney/getSmartMoneyDcasAction.ts | 234 ++++++++++++++ .../getSmartMoneyDexTradesAction.ts | 288 ++++++++++++++++++ .../SmartMoney/getSmartMoneyHoldingsAction.ts | 270 ++++++++++++++++ .../SmartMoney/getSmartMoneyNetflowAction.ts | 249 +++++++++++++++ .../actions/NansenAction/SmartMoney/index.ts | 4 + .../TokenGodMode/getDexTradesAction.ts | 257 ++++++++++++++++ .../TokenGodMode/getFlowIntelligenceAction.ts | 223 ++++++++++++++ .../TokenGodMode/getFlowsAction.ts | 245 +++++++++++++++ .../TokenGodMode/getHoldersAction.ts | 236 ++++++++++++++ .../TokenGodMode/getJupiterDcasAction.ts | 243 +++++++++++++++ .../TokenGodMode/getPnlLeaderboardAction.ts | 249 +++++++++++++++ .../TokenGodMode/getTokenScreenerAction.ts | 255 ++++++++++++++++ .../TokenGodMode/getTransfersAction.ts | 252 +++++++++++++++ .../TokenGodMode/getWhoBoughtSoldAction.ts | 244 +++++++++++++++ .../NansenAction/TokenGodMode/index.ts | 9 + .../src/actions/NansenAction/index.ts | 26 ++ agentkit-core/src/actions/index.ts | 52 ++++ 29 files changed, 5640 insertions(+) create mode 100644 agentkit-core/src/actions/NansenAction/Portfolio/getDefiHoldingsAction.ts create mode 100644 agentkit-core/src/actions/NansenAction/Portfolio/index.ts create mode 100644 agentkit-core/src/actions/NansenAction/Profiler/getCounterpartiesAction.ts create mode 100644 agentkit-core/src/actions/NansenAction/Profiler/getCurrentBalanceAction.ts create mode 100644 agentkit-core/src/actions/NansenAction/Profiler/getHistoricalBalanceAction.ts create mode 100644 agentkit-core/src/actions/NansenAction/Profiler/getLabelsAction.ts create mode 100644 agentkit-core/src/actions/NansenAction/Profiler/getPnlAction.ts create mode 100644 agentkit-core/src/actions/NansenAction/Profiler/getPnlSummaryAction.ts create mode 100644 agentkit-core/src/actions/NansenAction/Profiler/getRelatedWalletsAction.ts create mode 100644 agentkit-core/src/actions/NansenAction/Profiler/getTransactionLookupAction.ts create mode 100644 agentkit-core/src/actions/NansenAction/Profiler/getTransactionsAction.ts create mode 100644 agentkit-core/src/actions/NansenAction/Profiler/index.ts create mode 100644 agentkit-core/src/actions/NansenAction/SmartMoney/getSmartMoneyDcasAction.ts create mode 100644 agentkit-core/src/actions/NansenAction/SmartMoney/getSmartMoneyDexTradesAction.ts create mode 100644 agentkit-core/src/actions/NansenAction/SmartMoney/getSmartMoneyHoldingsAction.ts create mode 100644 agentkit-core/src/actions/NansenAction/SmartMoney/getSmartMoneyNetflowAction.ts create mode 100644 agentkit-core/src/actions/NansenAction/SmartMoney/index.ts create mode 100644 agentkit-core/src/actions/NansenAction/TokenGodMode/getDexTradesAction.ts create mode 100644 agentkit-core/src/actions/NansenAction/TokenGodMode/getFlowIntelligenceAction.ts create mode 100644 agentkit-core/src/actions/NansenAction/TokenGodMode/getFlowsAction.ts create mode 100644 agentkit-core/src/actions/NansenAction/TokenGodMode/getHoldersAction.ts create mode 100644 agentkit-core/src/actions/NansenAction/TokenGodMode/getJupiterDcasAction.ts create mode 100644 agentkit-core/src/actions/NansenAction/TokenGodMode/getPnlLeaderboardAction.ts create mode 100644 agentkit-core/src/actions/NansenAction/TokenGodMode/getTokenScreenerAction.ts create mode 100644 agentkit-core/src/actions/NansenAction/TokenGodMode/getTransfersAction.ts create mode 100644 agentkit-core/src/actions/NansenAction/TokenGodMode/getWhoBoughtSoldAction.ts create mode 100644 agentkit-core/src/actions/NansenAction/TokenGodMode/index.ts create mode 100644 agentkit-core/src/actions/NansenAction/index.ts diff --git a/agentkit-core/src/actions/NansenAction/Portfolio/getDefiHoldingsAction.ts b/agentkit-core/src/actions/NansenAction/Portfolio/getDefiHoldingsAction.ts new file mode 100644 index 0000000..c6a6286 --- /dev/null +++ b/agentkit-core/src/actions/NansenAction/Portfolio/getDefiHoldingsAction.ts @@ -0,0 +1,236 @@ +import { z } from "zod"; +import { AgentkitAction } from "../../../agentkit"; +import { ZeroXgaslessSmartAccount } from "@0xgasless/smart-account"; + +const GET_DEFI_HOLDINGS_PROMPT = ` +Retrieve DeFi holdings for a specific wallet address across multiple blockchains. This endpoint provides detailed information about DeFi positions including protocols, tokens, and values. + +Key Features: +- DeFi holdings for a specific wallet address +- Multi-chain support +- Protocol and token information +- Position values and metrics +- Comprehensive DeFi portfolio analysis + +This endpoint requires a Nansen API key to be configured. +`; + +/** + * Input schema for getting DeFi holdings data. + */ +export const GetDefiHoldingsInput = z + .object({ + wallet_address: z.string().describe("The wallet address to get DeFi holdings for"), + + chains: z + .array( + z.enum([ + "all", + "arbitrum", + "avalanche", + "base", + "berachain", + "blast", + "bnb", + "ethereum", + "goat", + "hyperevm", + "iotaevm", + "linea", + "mantle", + "optimism", + "plasma", + "polygon", + "ronin", + "sei", + "scroll", + "sonic", + "unichain", + "zksync", + "solana", + ]) + ) + .describe("Chains to include in the analysis. Use 'all' to include all available chains."), + + filters: z + .object({ + protocol_name: z.string().optional().describe("Protocol name filter"), + protocol_type: z.array(z.string()).optional().describe("Protocol type filter"), + token_address: z.string().optional().describe("Token address filter"), + token_symbol: z.string().optional().describe("Token symbol filter"), + position_type: z.array(z.string()).optional().describe("Position type filter"), + value_usd: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Value range filter in USD"), + timestamp: z + .object({ + from: z.string().optional(), + to: z.string().optional(), + }) + .optional() + .describe("Timestamp range filter"), + }) + .optional() + .describe("Additional filters to apply"), + + pagination: z + .object({ + page: z.number().min(1).default(1).describe("Page number (1-based)"), + per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + }) + .optional() + .describe("Pagination parameters"), + + order_by: z + .array( + z.object({ + field: z + .enum([ + "chain", + "wallet_address", + "protocol_name", + "protocol_type", + "token_address", + "token_symbol", + "position_type", + "value_usd", + "timestamp", + ]) + .describe("Field to sort by"), + direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), + }) + ) + .optional() + .describe("Custom sort order to override the endpoint's default ordering"), + }) + .strip() + .describe("Instructions for getting DeFi holdings data"); + +/** + * Response interface for DeFi holdings data. + */ +interface DefiHolding { + chain: string; + wallet_address: string; + protocol_name: string; + protocol_type: string; + token_address: string; + token_symbol: string; + position_type: string; + value_usd?: number; + timestamp: string; +} + +interface DefiHoldingsResponse { + data: DefiHolding[]; + pagination: { + page: number; + per_page: number; + is_last_page: boolean; + }; +} + +/** + * Fetches DeFi holdings data from Nansen API. + * + * @param _wallet - The smart account (not used for this action). + * @param args - The input arguments containing wallet address, chains, filters, pagination, and sorting options. + * @returns A formatted string containing the DeFi holdings data. + */ +export async function getDefiHoldings( + _wallet: ZeroXgaslessSmartAccount, + args: z.infer, +): Promise { + try { + const apiKey = process.env.NANSEN_API_KEY; + if (!apiKey) { + return "Error: NANSEN_API_KEY environment variable is required but not set."; + } + + const requestBody = { + wallet_address: args.wallet_address, + chains: args.chains, + ...(args.filters && { filters: args.filters }), + ...(args.pagination && { pagination: args.pagination }), + ...(args.order_by && { order_by: args.order_by }), + }; + + const response = await fetch("https://api.nansen.ai/api/v1/portfolio/defi-holdings", { + method: "POST", + headers: { + "Content-Type": "application/json", + apiKey: apiKey, + "User-Agent": "0xGasless-AgentKit/1.0", + }, + body: JSON.stringify(requestBody), + }); + + if (!response.ok) { + if (response.status === 401) { + return "Error: Invalid Nansen API key. Please check your NANSEN_API_KEY environment variable."; + } + if (response.status === 403) { + return "Error: Insufficient subscription tier for this endpoint."; + } + if (response.status === 429) { + return "Error: Rate limit exceeded. Please wait before making another request."; + } + return `Error fetching DeFi holdings: ${response.status} ${response.statusText}`; + } + + const data: DefiHoldingsResponse = await response.json(); + + if (!data.data || data.data.length === 0) { + return `No DeFi holdings found for wallet ${args.wallet_address}.`; + } + + let result = `🏦 DeFi Holdings for ${args.wallet_address}:\n\n`; + + data.data.forEach((holding, index) => { + const timestamp = new Date(holding.timestamp).toLocaleString(); + const protocolEmoji = holding.protocol_type === "lending" ? "💰" : + holding.protocol_type === "dex" ? "🔄" : + holding.protocol_type === "yield" ? "📈" : + holding.protocol_type === "staking" ? "🔒" : "🏛️"; + const positionEmoji = holding.position_type === "supply" ? "📤" : + holding.position_type === "borrow" ? "📥" : + holding.position_type === "liquidity" ? "💧" : "📊"; + + result += `${index + 1}. DeFi Position ${protocolEmoji}${positionEmoji}\n`; + result += ` • Protocol: ${holding.protocol_name}\n`; + result += ` • Type: ${holding.protocol_type}\n`; + result += ` • Position: ${holding.position_type}\n`; + result += ` • Token: ${holding.token_symbol} (${holding.token_address})\n`; + result += ` • Chain: ${holding.chain}\n`; + if (holding.value_usd) { + result += ` • Value: $${holding.value_usd.toLocaleString()}\n`; + } + result += ` • Last Updated: ${timestamp}\n`; + result += "\n"; + }); + + if (!data.pagination.is_last_page) { + result += `Page ${data.pagination.page} of results. Use pagination to get more results.\n`; + } + + return result; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : "An unknown error occurred"; + return `Error fetching DeFi holdings: ${errorMessage}`; + } +} + +/** + * Get DeFi Holdings action. + */ +export class GetDefiHoldingsAction implements AgentkitAction { + public name = "get_defi_holdings"; + public description = GET_DEFI_HOLDINGS_PROMPT; + public argsSchema = GetDefiHoldingsInput; + public func = getDefiHoldings; + public smartAccountRequired = false; +} diff --git a/agentkit-core/src/actions/NansenAction/Portfolio/index.ts b/agentkit-core/src/actions/NansenAction/Portfolio/index.ts new file mode 100644 index 0000000..2e91c31 --- /dev/null +++ b/agentkit-core/src/actions/NansenAction/Portfolio/index.ts @@ -0,0 +1 @@ +export { GetDefiHoldingsAction } from "./getDefiHoldingsAction"; diff --git a/agentkit-core/src/actions/NansenAction/Profiler/getCounterpartiesAction.ts b/agentkit-core/src/actions/NansenAction/Profiler/getCounterpartiesAction.ts new file mode 100644 index 0000000..06355ea --- /dev/null +++ b/agentkit-core/src/actions/NansenAction/Profiler/getCounterpartiesAction.ts @@ -0,0 +1,233 @@ +import { z } from "zod"; +import { AgentkitAction } from "../../../agentkit"; +import { ZeroXgaslessSmartAccount } from "@0xgasless/smart-account"; + +const GET_COUNTERPARTIES_PROMPT = ` +Retrieve counterparty information for a specific wallet address across multiple blockchains. This endpoint provides detailed information about entities that have interacted with the wallet, including transaction counts, volumes, and labels. + +Key Features: +- Counterparty information for a specific wallet +- Multi-chain support +- Transaction counts and volumes +- Entity labels and classifications +- Comprehensive interaction history + +This endpoint requires a Nansen API key to be configured. +`; + +/** + * Input schema for getting counterparties data. + */ +export const GetCounterpartiesInput = z + .object({ + wallet_address: z.string().describe("The wallet address to get counterparties for"), + + chains: z + .array( + z.enum([ + "all", + "arbitrum", + "avalanche", + "base", + "berachain", + "blast", + "bnb", + "ethereum", + "goat", + "hyperevm", + "iotaevm", + "linea", + "mantle", + "optimism", + "plasma", + "polygon", + "ronin", + "sei", + "scroll", + "sonic", + "unichain", + "zksync", + "solana", + ]) + ) + .describe("Chains to include in the analysis. Use 'all' to include all available chains."), + + filters: z + .object({ + counterparty_address: z.string().optional().describe("Counterparty address filter"), + counterparty_label: z.string().optional().describe("Counterparty label filter"), + counterparty_type: z.array(z.string()).optional().describe("Counterparty type filter"), + transaction_count: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Transaction count range filter"), + volume_usd: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Volume range filter in USD"), + timestamp: z + .object({ + from: z.string().optional(), + to: z.string().optional(), + }) + .optional() + .describe("Timestamp range filter"), + }) + .optional() + .describe("Additional filters to apply"), + + pagination: z + .object({ + page: z.number().min(1).default(1).describe("Page number (1-based)"), + per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + }) + .optional() + .describe("Pagination parameters"), + + order_by: z + .array( + z.object({ + field: z + .enum([ + "chain", + "counterparty_address", + "counterparty_label", + "counterparty_type", + "transaction_count", + "volume_usd", + "timestamp", + ]) + .describe("Field to sort by"), + direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), + }) + ) + .optional() + .describe("Custom sort order to override the endpoint's default ordering"), + }) + .strip() + .describe("Instructions for getting counterparties data"); + +/** + * Response interface for counterparties data. + */ +interface Counterparty { + chain: string; + counterparty_address: string; + counterparty_label: string; + counterparty_type: string; + transaction_count: number; + volume_usd?: number; + timestamp: string; +} + +interface CounterpartiesResponse { + data: Counterparty[]; + pagination: { + page: number; + per_page: number; + is_last_page: boolean; + }; +} + +/** + * Fetches counterparties data from Nansen API. + * + * @param _wallet - The smart account (not used for this action). + * @param args - The input arguments containing wallet address, chains, filters, pagination, and sorting options. + * @returns A formatted string containing the counterparties data. + */ +export async function getCounterparties( + _wallet: ZeroXgaslessSmartAccount, + args: z.infer, +): Promise { + try { + const apiKey = process.env.NANSEN_API_KEY; + if (!apiKey) { + return "Error: NANSEN_API_KEY environment variable is required but not set."; + } + + const requestBody = { + wallet_address: args.wallet_address, + chains: args.chains, + ...(args.filters && { filters: args.filters }), + ...(args.pagination && { pagination: args.pagination }), + ...(args.order_by && { order_by: args.order_by }), + }; + + const response = await fetch("https://api.nansen.ai/api/v1/profiler/counterparties", { + method: "POST", + headers: { + "Content-Type": "application/json", + apiKey: apiKey, + "User-Agent": "0xGasless-AgentKit/1.0", + }, + body: JSON.stringify(requestBody), + }); + + if (!response.ok) { + if (response.status === 401) { + return "Error: Invalid Nansen API key. Please check your NANSEN_API_KEY environment variable."; + } + if (response.status === 403) { + return "Error: Insufficient subscription tier for this endpoint."; + } + if (response.status === 429) { + return "Error: Rate limit exceeded. Please wait before making another request."; + } + return `Error fetching counterparties: ${response.status} ${response.statusText}`; + } + + const data: CounterpartiesResponse = await response.json(); + + if (!data.data || data.data.length === 0) { + return `No counterparties found for wallet ${args.wallet_address}.`; + } + + let result = `🤝 Counterparties for ${args.wallet_address}:\n\n`; + + data.data.forEach((counterparty, index) => { + const timestamp = new Date(counterparty.timestamp).toLocaleString(); + const typeEmoji = counterparty.counterparty_type === "exchange" ? "🏦" : + counterparty.counterparty_type === "defi" ? "🔄" : + counterparty.counterparty_type === "nft" ? "🎨" : "👤"; + + result += `${index + 1}. Counterparty ${typeEmoji}\n`; + result += ` • Address: ${counterparty.counterparty_address}\n`; + result += ` • Label: ${counterparty.counterparty_label}\n`; + result += ` • Type: ${counterparty.counterparty_type}\n`; + result += ` • Chain: ${counterparty.chain}\n`; + result += ` • Transactions: ${counterparty.transaction_count}\n`; + if (counterparty.volume_usd) { + result += ` • Volume: $${counterparty.volume_usd.toLocaleString()}\n`; + } + result += ` • Last Activity: ${timestamp}\n`; + result += "\n"; + }); + + if (!data.pagination.is_last_page) { + result += `Page ${data.pagination.page} of results. Use pagination to get more results.\n`; + } + + return result; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : "An unknown error occurred"; + return `Error fetching counterparties: ${errorMessage}`; + } +} + +/** + * Get Counterparties action. + */ +export class GetCounterpartiesAction implements AgentkitAction { + public name = "get_counterparties"; + public description = GET_COUNTERPARTIES_PROMPT; + public argsSchema = GetCounterpartiesInput; + public func = getCounterparties; + public smartAccountRequired = false; +} diff --git a/agentkit-core/src/actions/NansenAction/Profiler/getCurrentBalanceAction.ts b/agentkit-core/src/actions/NansenAction/Profiler/getCurrentBalanceAction.ts new file mode 100644 index 0000000..72a7db4 --- /dev/null +++ b/agentkit-core/src/actions/NansenAction/Profiler/getCurrentBalanceAction.ts @@ -0,0 +1,213 @@ +import { z } from "zod"; +import { AgentkitAction } from "../../../agentkit"; +import { ZeroXgaslessSmartAccount } from "@0xgasless/smart-account"; + +const GET_CURRENT_BALANCE_PROMPT = ` +Retrieve current token balances for a specific wallet address across multiple blockchains. This endpoint provides real-time balance information for all tokens held by the wallet. + +Key Features: +- Current token balances for a specific wallet +- Multi-chain support +- Real-time balance information +- Detailed token metadata +- USD value calculations + +This endpoint requires a Nansen API key to be configured. +`; + +/** + * Input schema for getting current balance data. + */ +export const GetCurrentBalanceInput = z + .object({ + wallet_address: z.string().describe("The wallet address to get balances for"), + + chains: z + .array( + z.enum([ + "all", + "arbitrum", + "avalanche", + "base", + "berachain", + "blast", + "bnb", + "ethereum", + "goat", + "hyperevm", + "iotaevm", + "linea", + "mantle", + "optimism", + "plasma", + "polygon", + "ronin", + "sei", + "scroll", + "sonic", + "unichain", + "zksync", + "solana", + ]) + ) + .describe("Chains to include in the analysis. Use 'all' to include all available chains."), + + filters: z + .object({ + include_stablecoins: z.boolean().optional().default(false).describe("Whether to include stablecoins in the results"), + include_native_tokens: z.boolean().optional().default(false).describe("Whether to include native tokens (e.g., ETH, SOL) in the results"), + value_usd: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Value range filter in USD"), + token_address: z.string().optional().describe("Token address filter"), + token_symbol: z.string().optional().describe("Token symbol filter"), + token_sectors: z.array(z.string()).optional().describe("Token sectors filter"), + }) + .optional() + .describe("Additional filters to apply"), + + pagination: z + .object({ + page: z.number().min(1).default(1).describe("Page number (1-based)"), + per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + }) + .optional() + .describe("Pagination parameters"), + + order_by: z + .array( + z.object({ + field: z + .enum([ + "chain", + "token_address", + "token_symbol", + "value_usd", + "balance", + "token_sectors", + ]) + .describe("Field to sort by"), + direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), + }) + ) + .optional() + .describe("Custom sort order to override the endpoint's default ordering"), + }) + .strip() + .describe("Instructions for getting current balance data"); + +/** + * Response interface for current balance data. + */ +interface CurrentBalance { + chain: string; + token_address: string; + token_symbol: string; + token_sectors: string[]; + balance: number; + value_usd?: number; +} + +interface CurrentBalanceResponse { + data: CurrentBalance[]; + pagination: { + page: number; + per_page: number; + is_last_page: boolean; + }; +} + +/** + * Fetches current balance data from Nansen API. + * + * @param _wallet - The smart account (not used for this action). + * @param args - The input arguments containing wallet address, chains, filters, pagination, and sorting options. + * @returns A formatted string containing the current balance data. + */ +export async function getCurrentBalance( + _wallet: ZeroXgaslessSmartAccount, + args: z.infer, +): Promise { + try { + const apiKey = process.env.NANSEN_API_KEY; + if (!apiKey) { + return "Error: NANSEN_API_KEY environment variable is required but not set."; + } + + const requestBody = { + wallet_address: args.wallet_address, + chains: args.chains, + ...(args.filters && { filters: args.filters }), + ...(args.pagination && { pagination: args.pagination }), + ...(args.order_by && { order_by: args.order_by }), + }; + + const response = await fetch("https://api.nansen.ai/api/v1/profiler/current-balance", { + method: "POST", + headers: { + "Content-Type": "application/json", + apiKey: apiKey, + "User-Agent": "0xGasless-AgentKit/1.0", + }, + body: JSON.stringify(requestBody), + }); + + if (!response.ok) { + if (response.status === 401) { + return "Error: Invalid Nansen API key. Please check your NANSEN_API_KEY environment variable."; + } + if (response.status === 403) { + return "Error: Insufficient subscription tier for this endpoint."; + } + if (response.status === 429) { + return "Error: Rate limit exceeded. Please wait before making another request."; + } + return `Error fetching current balance: ${response.status} ${response.statusText}`; + } + + const data: CurrentBalanceResponse = await response.json(); + + if (!data.data || data.data.length === 0) { + return `No balance data found for wallet ${args.wallet_address}.`; + } + + let result = `💰 Current Balance for ${args.wallet_address}:\n\n`; + + data.data.forEach((balance, index) => { + result += `${index + 1}. ${balance.token_symbol} (${balance.chain})\n`; + result += ` • Token Address: ${balance.token_address}\n`; + result += ` • Balance: ${balance.balance.toFixed(6)}\n`; + if (balance.value_usd) { + result += ` • Value: $${balance.value_usd.toLocaleString()}\n`; + } + if (balance.token_sectors && balance.token_sectors.length > 0) { + result += ` • Sectors: ${balance.token_sectors.join(", ")}\n`; + } + result += "\n"; + }); + + if (!data.pagination.is_last_page) { + result += `Page ${data.pagination.page} of results. Use pagination to get more results.\n`; + } + + return result; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : "An unknown error occurred"; + return `Error fetching current balance: ${errorMessage}`; + } +} + +/** + * Get Current Balance action. + */ +export class GetCurrentBalanceAction implements AgentkitAction { + public name = "get_current_balance"; + public description = GET_CURRENT_BALANCE_PROMPT; + public argsSchema = GetCurrentBalanceInput; + public func = getCurrentBalance; + public smartAccountRequired = false; +} diff --git a/agentkit-core/src/actions/NansenAction/Profiler/getHistoricalBalanceAction.ts b/agentkit-core/src/actions/NansenAction/Profiler/getHistoricalBalanceAction.ts new file mode 100644 index 0000000..4cd2062 --- /dev/null +++ b/agentkit-core/src/actions/NansenAction/Profiler/getHistoricalBalanceAction.ts @@ -0,0 +1,224 @@ +import { z } from "zod"; +import { AgentkitAction } from "../../../agentkit"; +import { ZeroXgaslessSmartAccount } from "@0xgasless/smart-account"; + +const GET_HISTORICAL_BALANCE_PROMPT = ` +Retrieve historical token balances for a specific wallet address across multiple blockchains. This endpoint provides balance information at specific timestamps, allowing you to track balance changes over time. + +Key Features: +- Historical token balances for a specific wallet +- Multi-chain support +- Balance information at specific timestamps +- Track balance changes over time +- Detailed token metadata + +This endpoint requires a Nansen API key to be configured. +`; + +/** + * Input schema for getting historical balance data. + */ +export const GetHistoricalBalanceInput = z + .object({ + wallet_address: z.string().describe("The wallet address to get historical balances for"), + + chains: z + .array( + z.enum([ + "all", + "arbitrum", + "avalanche", + "base", + "berachain", + "blast", + "bnb", + "ethereum", + "goat", + "hyperevm", + "iotaevm", + "linea", + "mantle", + "optimism", + "plasma", + "polygon", + "ronin", + "sei", + "scroll", + "sonic", + "unichain", + "zksync", + "solana", + ]) + ) + .describe("Chains to include in the analysis. Use 'all' to include all available chains."), + + filters: z + .object({ + include_stablecoins: z.boolean().optional().default(false).describe("Whether to include stablecoins in the results"), + include_native_tokens: z.boolean().optional().default(false).describe("Whether to include native tokens (e.g., ETH, SOL) in the results"), + value_usd: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Value range filter in USD"), + token_address: z.string().optional().describe("Token address filter"), + token_symbol: z.string().optional().describe("Token symbol filter"), + token_sectors: z.array(z.string()).optional().describe("Token sectors filter"), + timestamp: z + .object({ + from: z.string().optional(), + to: z.string().optional(), + }) + .optional() + .describe("Timestamp range filter"), + }) + .optional() + .describe("Additional filters to apply"), + + pagination: z + .object({ + page: z.number().min(1).default(1).describe("Page number (1-based)"), + per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + }) + .optional() + .describe("Pagination parameters"), + + order_by: z + .array( + z.object({ + field: z + .enum([ + "chain", + "token_address", + "token_symbol", + "value_usd", + "balance", + "token_sectors", + "timestamp", + ]) + .describe("Field to sort by"), + direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), + }) + ) + .optional() + .describe("Custom sort order to override the endpoint's default ordering"), + }) + .strip() + .describe("Instructions for getting historical balance data"); + +/** + * Response interface for historical balance data. + */ +interface HistoricalBalance { + chain: string; + token_address: string; + token_symbol: string; + token_sectors: string[]; + balance: number; + value_usd?: number; + timestamp: string; +} + +interface HistoricalBalanceResponse { + data: HistoricalBalance[]; + pagination: { + page: number; + per_page: number; + is_last_page: boolean; + }; +} + +/** + * Fetches historical balance data from Nansen API. + * + * @param _wallet - The smart account (not used for this action). + * @param args - The input arguments containing wallet address, chains, filters, pagination, and sorting options. + * @returns A formatted string containing the historical balance data. + */ +export async function getHistoricalBalance( + _wallet: ZeroXgaslessSmartAccount, + args: z.infer, +): Promise { + try { + const apiKey = process.env.NANSEN_API_KEY; + if (!apiKey) { + return "Error: NANSEN_API_KEY environment variable is required but not set."; + } + + const requestBody = { + wallet_address: args.wallet_address, + chains: args.chains, + ...(args.filters && { filters: args.filters }), + ...(args.pagination && { pagination: args.pagination }), + ...(args.order_by && { order_by: args.order_by }), + }; + + const response = await fetch("https://api.nansen.ai/api/v1/profiler/historical-balance", { + method: "POST", + headers: { + "Content-Type": "application/json", + apiKey: apiKey, + "User-Agent": "0xGasless-AgentKit/1.0", + }, + body: JSON.stringify(requestBody), + }); + + if (!response.ok) { + if (response.status === 401) { + return "Error: Invalid Nansen API key. Please check your NANSEN_API_KEY environment variable."; + } + if (response.status === 403) { + return "Error: Insufficient subscription tier for this endpoint."; + } + if (response.status === 429) { + return "Error: Rate limit exceeded. Please wait before making another request."; + } + return `Error fetching historical balance: ${response.status} ${response.statusText}`; + } + + const data: HistoricalBalanceResponse = await response.json(); + + if (!data.data || data.data.length === 0) { + return `No historical balance data found for wallet ${args.wallet_address}.`; + } + + let result = `📈 Historical Balance for ${args.wallet_address}:\n\n`; + + data.data.forEach((balance, index) => { + const timestamp = new Date(balance.timestamp).toLocaleString(); + result += `${index + 1}. ${balance.token_symbol} (${balance.chain})\n`; + result += ` • Token Address: ${balance.token_address}\n`; + result += ` • Balance: ${balance.balance.toFixed(6)}\n`; + if (balance.value_usd) { + result += ` • Value: $${balance.value_usd.toLocaleString()}\n`; + } + result += ` • Timestamp: ${timestamp}\n`; + if (balance.token_sectors && balance.token_sectors.length > 0) { + result += ` • Sectors: ${balance.token_sectors.join(", ")}\n`; + } + result += "\n"; + }); + + if (!data.pagination.is_last_page) { + result += `Page ${data.pagination.page} of results. Use pagination to get more results.\n`; + } + + return result; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : "An unknown error occurred"; + return `Error fetching historical balance: ${errorMessage}`; + } +} + +/** + * Get Historical Balance action. + */ +export class GetHistoricalBalanceAction implements AgentkitAction { + public name = "get_historical_balance"; + public description = GET_HISTORICAL_BALANCE_PROMPT; + public argsSchema = GetHistoricalBalanceInput; + public func = getHistoricalBalance; + public smartAccountRequired = false; +} diff --git a/agentkit-core/src/actions/NansenAction/Profiler/getLabelsAction.ts b/agentkit-core/src/actions/NansenAction/Profiler/getLabelsAction.ts new file mode 100644 index 0000000..74b8d21 --- /dev/null +++ b/agentkit-core/src/actions/NansenAction/Profiler/getLabelsAction.ts @@ -0,0 +1,220 @@ +import { z } from "zod"; +import { AgentkitAction } from "../../../agentkit"; +import { ZeroXgaslessSmartAccount } from "@0xgasless/smart-account"; + +const GET_LABELS_PROMPT = ` +Retrieve labels for a specific wallet address across multiple blockchains. This endpoint provides entity labels, classifications, and metadata associated with the wallet address. + +Key Features: +- Labels for a specific wallet address +- Multi-chain support +- Entity labels and classifications +- Wallet metadata and information +- Comprehensive address analysis + +This endpoint requires a Nansen API key to be configured. +`; + +/** + * Input schema for getting labels data. + */ +export const GetLabelsInput = z + .object({ + wallet_address: z.string().describe("The wallet address to get labels for"), + + chains: z + .array( + z.enum([ + "all", + "arbitrum", + "avalanche", + "base", + "berachain", + "blast", + "bnb", + "ethereum", + "goat", + "hyperevm", + "iotaevm", + "linea", + "mantle", + "optimism", + "plasma", + "polygon", + "ronin", + "sei", + "scroll", + "sonic", + "unichain", + "zksync", + "solana", + ]) + ) + .describe("Chains to include in the analysis. Use 'all' to include all available chains."), + + filters: z + .object({ + label_type: z.array(z.string()).optional().describe("Label type filter"), + label_category: z.array(z.string()).optional().describe("Label category filter"), + label_name: z.string().optional().describe("Label name filter"), + confidence_score: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Confidence score range filter (0-1)"), + timestamp: z + .object({ + from: z.string().optional(), + to: z.string().optional(), + }) + .optional() + .describe("Timestamp range filter"), + }) + .optional() + .describe("Additional filters to apply"), + + pagination: z + .object({ + page: z.number().min(1).default(1).describe("Page number (1-based)"), + per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + }) + .optional() + .describe("Pagination parameters"), + + order_by: z + .array( + z.object({ + field: z + .enum([ + "chain", + "label_type", + "label_category", + "label_name", + "confidence_score", + "timestamp", + ]) + .describe("Field to sort by"), + direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), + }) + ) + .optional() + .describe("Custom sort order to override the endpoint's default ordering"), + }) + .strip() + .describe("Instructions for getting labels data"); + +/** + * Response interface for labels data. + */ +interface Label { + chain: string; + label_type: string; + label_category: string; + label_name: string; + confidence_score: number; + timestamp: string; +} + +interface LabelsResponse { + data: Label[]; + pagination: { + page: number; + per_page: number; + is_last_page: boolean; + }; +} + +/** + * Fetches labels data from Nansen API. + * + * @param _wallet - The smart account (not used for this action). + * @param args - The input arguments containing wallet address, chains, filters, pagination, and sorting options. + * @returns A formatted string containing the labels data. + */ +export async function getLabels( + _wallet: ZeroXgaslessSmartAccount, + args: z.infer, +): Promise { + try { + const apiKey = process.env.NANSEN_API_KEY; + if (!apiKey) { + return "Error: NANSEN_API_KEY environment variable is required but not set."; + } + + const requestBody = { + wallet_address: args.wallet_address, + chains: args.chains, + ...(args.filters && { filters: args.filters }), + ...(args.pagination && { pagination: args.pagination }), + ...(args.order_by && { order_by: args.order_by }), + }; + + const response = await fetch("https://api.nansen.ai/api/v1/profiler/labels", { + method: "POST", + headers: { + "Content-Type": "application/json", + apiKey: apiKey, + "User-Agent": "0xGasless-AgentKit/1.0", + }, + body: JSON.stringify(requestBody), + }); + + if (!response.ok) { + if (response.status === 401) { + return "Error: Invalid Nansen API key. Please check your NANSEN_API_KEY environment variable."; + } + if (response.status === 403) { + return "Error: Insufficient subscription tier for this endpoint."; + } + if (response.status === 429) { + return "Error: Rate limit exceeded. Please wait before making another request."; + } + return `Error fetching labels: ${response.status} ${response.statusText}`; + } + + const data: LabelsResponse = await response.json(); + + if (!data.data || data.data.length === 0) { + return `No labels found for wallet ${args.wallet_address}.`; + } + + let result = `🏷️ Labels for ${args.wallet_address}:\n\n`; + + data.data.forEach((label, index) => { + const timestamp = new Date(label.timestamp).toLocaleString(); + const confidenceEmoji = label.confidence_score >= 0.8 ? "🎯" : + label.confidence_score >= 0.6 ? "⚖️" : "🎲"; + + result += `${index + 1}. Label ${confidenceEmoji}\n`; + result += ` • Name: ${label.label_name}\n`; + result += ` • Type: ${label.label_type}\n`; + result += ` • Category: ${label.label_category}\n`; + result += ` • Chain: ${label.chain}\n`; + result += ` • Confidence: ${confidenceEmoji} ${(label.confidence_score * 100).toFixed(1)}%\n`; + result += ` • Added: ${timestamp}\n`; + result += "\n"; + }); + + if (!data.pagination.is_last_page) { + result += `Page ${data.pagination.page} of results. Use pagination to get more results.\n`; + } + + return result; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : "An unknown error occurred"; + return `Error fetching labels: ${errorMessage}`; + } +} + +/** + * Get Labels action. + */ +export class GetLabelsAction implements AgentkitAction { + public name = "get_labels"; + public description = GET_LABELS_PROMPT; + public argsSchema = GetLabelsInput; + public func = getLabels; + public smartAccountRequired = false; +} diff --git a/agentkit-core/src/actions/NansenAction/Profiler/getPnlAction.ts b/agentkit-core/src/actions/NansenAction/Profiler/getPnlAction.ts new file mode 100644 index 0000000..82ac548 --- /dev/null +++ b/agentkit-core/src/actions/NansenAction/Profiler/getPnlAction.ts @@ -0,0 +1,238 @@ +import { z } from "zod"; +import { AgentkitAction } from "../../../agentkit"; +import { ZeroXgaslessSmartAccount } from "@0xgasless/smart-account"; + +const GET_PNL_PROMPT = ` +Retrieve detailed profit and loss information for a specific wallet address across multiple blockchains. This endpoint provides transaction-level PnL data including individual trade performance and detailed metrics. + +Key Features: +- Detailed PnL information for a specific wallet +- Multi-chain support +- Transaction-level PnL data +- Individual trade performance +- Detailed trading metrics + +This endpoint requires a Nansen API key to be configured. +`; + +/** + * Input schema for getting PnL data. + */ +export const GetPnlInput = z + .object({ + wallet_address: z.string().describe("The wallet address to get PnL data for"), + + chains: z + .array( + z.enum([ + "all", + "arbitrum", + "avalanche", + "base", + "berachain", + "blast", + "bnb", + "ethereum", + "goat", + "hyperevm", + "iotaevm", + "linea", + "mantle", + "optimism", + "plasma", + "polygon", + "ronin", + "sei", + "scroll", + "sonic", + "unichain", + "zksync", + "solana", + ]) + ) + .describe("Chains to include in the analysis. Use 'all' to include all available chains."), + + filters: z + .object({ + transaction_hash: z.string().optional().describe("Transaction hash filter"), + token_address: z.string().optional().describe("Token address filter"), + token_symbol: z.string().optional().describe("Token symbol filter"), + token_sectors: z.array(z.string()).optional().describe("Token sectors filter"), + pnl_usd: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("PnL range filter in USD"), + pnl_percent: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("PnL percentage range filter"), + timestamp: z + .object({ + from: z.string().optional(), + to: z.string().optional(), + }) + .optional() + .describe("Timestamp range filter"), + }) + .optional() + .describe("Additional filters to apply"), + + pagination: z + .object({ + page: z.number().min(1).default(1).describe("Page number (1-based)"), + per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + }) + .optional() + .describe("Pagination parameters"), + + order_by: z + .array( + z.object({ + field: z + .enum([ + "chain", + "transaction_hash", + "token_address", + "token_symbol", + "token_sectors", + "pnl_usd", + "pnl_percent", + "timestamp", + ]) + .describe("Field to sort by"), + direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), + }) + ) + .optional() + .describe("Custom sort order to override the endpoint's default ordering"), + }) + .strip() + .describe("Instructions for getting PnL data"); + +/** + * Response interface for PnL data. + */ +interface Pnl { + chain: string; + transaction_hash: string; + token_address: string; + token_symbol: string; + token_sectors: string[]; + pnl_usd?: number; + pnl_percent?: number; + timestamp: string; +} + +interface PnlResponse { + data: Pnl[]; + pagination: { + page: number; + per_page: number; + is_last_page: boolean; + }; +} + +/** + * Fetches PnL data from Nansen API. + * + * @param _wallet - The smart account (not used for this action). + * @param args - The input arguments containing wallet address, chains, filters, pagination, and sorting options. + * @returns A formatted string containing the PnL data. + */ +export async function getPnl( + _wallet: ZeroXgaslessSmartAccount, + args: z.infer, +): Promise { + try { + const apiKey = process.env.NANSEN_API_KEY; + if (!apiKey) { + return "Error: NANSEN_API_KEY environment variable is required but not set."; + } + + const requestBody = { + wallet_address: args.wallet_address, + chains: args.chains, + ...(args.filters && { filters: args.filters }), + ...(args.pagination && { pagination: args.pagination }), + ...(args.order_by && { order_by: args.order_by }), + }; + + const response = await fetch("https://api.nansen.ai/api/v1/profiler/pnl", { + method: "POST", + headers: { + "Content-Type": "application/json", + apiKey: apiKey, + "User-Agent": "0xGasless-AgentKit/1.0", + }, + body: JSON.stringify(requestBody), + }); + + if (!response.ok) { + if (response.status === 401) { + return "Error: Invalid Nansen API key. Please check your NANSEN_API_KEY environment variable."; + } + if (response.status === 403) { + return "Error: Insufficient subscription tier for this endpoint."; + } + if (response.status === 429) { + return "Error: Rate limit exceeded. Please wait before making another request."; + } + return `Error fetching PnL: ${response.status} ${response.statusText}`; + } + + const data: PnlResponse = await response.json(); + + if (!data.data || data.data.length === 0) { + return `No PnL data found for wallet ${args.wallet_address}.`; + } + + let result = `💰 PnL Details for ${args.wallet_address}:\n\n`; + + data.data.forEach((pnl, index) => { + const timestamp = new Date(pnl.timestamp).toLocaleString(); + const pnlEmoji = pnl.pnl_usd && pnl.pnl_usd >= 0 ? "📈" : "📉"; + + result += `${index + 1}. PnL Transaction ${pnlEmoji}\n`; + result += ` • Token: ${pnl.token_symbol} (${pnl.token_address})\n`; + result += ` • Chain: ${pnl.chain}\n`; + if (pnl.pnl_usd !== undefined) { + result += ` • PnL: $${pnl.pnl_usd.toLocaleString()}\n`; + } + if (pnl.pnl_percent !== undefined) { + result += ` • PnL %: ${pnl.pnl_percent.toFixed(2)}%\n`; + } + if (pnl.token_sectors && pnl.token_sectors.length > 0) { + result += ` • Sectors: ${pnl.token_sectors.join(", ")}\n`; + } + result += ` • Time: ${timestamp}\n`; + result += ` • Tx Hash: ${pnl.transaction_hash}\n`; + result += "\n"; + }); + + if (!data.pagination.is_last_page) { + result += `Page ${data.pagination.page} of results. Use pagination to get more results.\n`; + } + + return result; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : "An unknown error occurred"; + return `Error fetching PnL: ${errorMessage}`; + } +} + +/** + * Get PnL action. + */ +export class GetPnlAction implements AgentkitAction { + public name = "get_pnl"; + public description = GET_PNL_PROMPT; + public argsSchema = GetPnlInput; + public func = getPnl; + public smartAccountRequired = false; +} diff --git a/agentkit-core/src/actions/NansenAction/Profiler/getPnlSummaryAction.ts b/agentkit-core/src/actions/NansenAction/Profiler/getPnlSummaryAction.ts new file mode 100644 index 0000000..65e8353 --- /dev/null +++ b/agentkit-core/src/actions/NansenAction/Profiler/getPnlSummaryAction.ts @@ -0,0 +1,233 @@ +import { z } from "zod"; +import { AgentkitAction } from "../../../agentkit"; +import { ZeroXgaslessSmartAccount } from "@0xgasless/smart-account"; + +const GET_PNL_SUMMARY_PROMPT = ` +Retrieve profit and loss summary for a specific wallet address across multiple blockchains. This endpoint provides aggregated PnL information including total gains/losses, win rates, and performance metrics. + +Key Features: +- Profit and loss summary for a specific wallet +- Multi-chain support +- Aggregated PnL information +- Win rates and performance metrics +- Comprehensive trading performance analysis + +This endpoint requires a Nansen API key to be configured. +`; + +/** + * Input schema for getting PnL summary data. + */ +export const GetPnlSummaryInput = z + .object({ + wallet_address: z.string().describe("The wallet address to get PnL summary for"), + + chains: z + .array( + z.enum([ + "all", + "arbitrum", + "avalanche", + "base", + "berachain", + "blast", + "bnb", + "ethereum", + "goat", + "hyperevm", + "iotaevm", + "linea", + "mantle", + "optimism", + "plasma", + "polygon", + "ronin", + "sei", + "scroll", + "sonic", + "unichain", + "zksync", + "solana", + ]) + ) + .describe("Chains to include in the analysis. Use 'all' to include all available chains."), + + filters: z + .object({ + token_address: z.string().optional().describe("Token address filter"), + token_symbol: z.string().optional().describe("Token symbol filter"), + token_sectors: z.array(z.string()).optional().describe("Token sectors filter"), + pnl_usd: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("PnL range filter in USD"), + win_rate: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Win rate range filter (0-1)"), + timestamp: z + .object({ + from: z.string().optional(), + to: z.string().optional(), + }) + .optional() + .describe("Timestamp range filter"), + }) + .optional() + .describe("Additional filters to apply"), + + pagination: z + .object({ + page: z.number().min(1).default(1).describe("Page number (1-based)"), + per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + }) + .optional() + .describe("Pagination parameters"), + + order_by: z + .array( + z.object({ + field: z + .enum([ + "chain", + "token_address", + "token_symbol", + "token_sectors", + "pnl_usd", + "win_rate", + "timestamp", + ]) + .describe("Field to sort by"), + direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), + }) + ) + .optional() + .describe("Custom sort order to override the endpoint's default ordering"), + }) + .strip() + .describe("Instructions for getting PnL summary data"); + +/** + * Response interface for PnL summary data. + */ +interface PnlSummary { + chain: string; + token_address: string; + token_symbol: string; + token_sectors: string[]; + pnl_usd?: number; + win_rate: number; + timestamp: string; +} + +interface PnlSummaryResponse { + data: PnlSummary[]; + pagination: { + page: number; + per_page: number; + is_last_page: boolean; + }; +} + +/** + * Fetches PnL summary data from Nansen API. + * + * @param _wallet - The smart account (not used for this action). + * @param args - The input arguments containing wallet address, chains, filters, pagination, and sorting options. + * @returns A formatted string containing the PnL summary data. + */ +export async function getPnlSummary( + _wallet: ZeroXgaslessSmartAccount, + args: z.infer, +): Promise { + try { + const apiKey = process.env.NANSEN_API_KEY; + if (!apiKey) { + return "Error: NANSEN_API_KEY environment variable is required but not set."; + } + + const requestBody = { + wallet_address: args.wallet_address, + chains: args.chains, + ...(args.filters && { filters: args.filters }), + ...(args.pagination && { pagination: args.pagination }), + ...(args.order_by && { order_by: args.order_by }), + }; + + const response = await fetch("https://api.nansen.ai/api/v1/profiler/pnl-summary", { + method: "POST", + headers: { + "Content-Type": "application/json", + apiKey: apiKey, + "User-Agent": "0xGasless-AgentKit/1.0", + }, + body: JSON.stringify(requestBody), + }); + + if (!response.ok) { + if (response.status === 401) { + return "Error: Invalid Nansen API key. Please check your NANSEN_API_KEY environment variable."; + } + if (response.status === 403) { + return "Error: Insufficient subscription tier for this endpoint."; + } + if (response.status === 429) { + return "Error: Rate limit exceeded. Please wait before making another request."; + } + return `Error fetching PnL summary: ${response.status} ${response.statusText}`; + } + + const data: PnlSummaryResponse = await response.json(); + + if (!data.data || data.data.length === 0) { + return `No PnL summary found for wallet ${args.wallet_address}.`; + } + + let result = `📊 PnL Summary for ${args.wallet_address}:\n\n`; + + data.data.forEach((summary, index) => { + const timestamp = new Date(summary.timestamp).toLocaleString(); + const pnlEmoji = summary.pnl_usd && summary.pnl_usd >= 0 ? "📈" : "📉"; + const winRateEmoji = summary.win_rate >= 0.6 ? "🎯" : summary.win_rate >= 0.4 ? "⚖️" : "🎲"; + + result += `${index + 1}. PnL Summary ${pnlEmoji}\n`; + result += ` • Token: ${summary.token_symbol} (${summary.token_address})\n`; + result += ` • Chain: ${summary.chain}\n`; + if (summary.pnl_usd !== undefined) { + result += ` • PnL: $${summary.pnl_usd.toLocaleString()}\n`; + } + result += ` • Win Rate: ${winRateEmoji} ${(summary.win_rate * 100).toFixed(1)}%\n`; + if (summary.token_sectors && summary.token_sectors.length > 0) { + result += ` • Sectors: ${summary.token_sectors.join(", ")}\n`; + } + result += ` • Last Updated: ${timestamp}\n`; + result += "\n"; + }); + + if (!data.pagination.is_last_page) { + result += `Page ${data.pagination.page} of results. Use pagination to get more results.\n`; + } + + return result; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : "An unknown error occurred"; + return `Error fetching PnL summary: ${errorMessage}`; + } +} + +/** + * Get PnL Summary action. + */ +export class GetPnlSummaryAction implements AgentkitAction { + public name = "get_pnl_summary"; + public description = GET_PNL_SUMMARY_PROMPT; + public argsSchema = GetPnlSummaryInput; + public func = getPnlSummary; + public smartAccountRequired = false; +} diff --git a/agentkit-core/src/actions/NansenAction/Profiler/getRelatedWalletsAction.ts b/agentkit-core/src/actions/NansenAction/Profiler/getRelatedWalletsAction.ts new file mode 100644 index 0000000..e57b523 --- /dev/null +++ b/agentkit-core/src/actions/NansenAction/Profiler/getRelatedWalletsAction.ts @@ -0,0 +1,238 @@ +import { z } from "zod"; +import { AgentkitAction } from "../../../agentkit"; +import { ZeroXgaslessSmartAccount } from "@0xgasless/smart-account"; + +const GET_RELATED_WALLETS_PROMPT = ` +Retrieve related wallet addresses for a specific wallet address across multiple blockchains. This endpoint identifies wallets that are likely controlled by the same entity through various clustering techniques. + +Key Features: +- Related wallet addresses for a specific wallet +- Multi-chain support +- Wallet clustering and identification +- Relationship strength indicators +- Comprehensive wallet network analysis + +This endpoint requires a Nansen API key to be configured. +`; + +/** + * Input schema for getting related wallets data. + */ +export const GetRelatedWalletsInput = z + .object({ + wallet_address: z.string().describe("The wallet address to get related wallets for"), + + chains: z + .array( + z.enum([ + "all", + "arbitrum", + "avalanche", + "base", + "berachain", + "blast", + "bnb", + "ethereum", + "goat", + "hyperevm", + "iotaevm", + "linea", + "mantle", + "optimism", + "plasma", + "polygon", + "ronin", + "sei", + "scroll", + "sonic", + "unichain", + "zksync", + "solana", + ]) + ) + .describe("Chains to include in the analysis. Use 'all' to include all available chains."), + + filters: z + .object({ + related_wallet_address: z.string().optional().describe("Related wallet address filter"), + relationship_type: z.array(z.string()).optional().describe("Relationship type filter"), + relationship_strength: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Relationship strength range filter"), + transaction_count: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Transaction count range filter"), + volume_usd: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Volume range filter in USD"), + timestamp: z + .object({ + from: z.string().optional(), + to: z.string().optional(), + }) + .optional() + .describe("Timestamp range filter"), + }) + .optional() + .describe("Additional filters to apply"), + + pagination: z + .object({ + page: z.number().min(1).default(1).describe("Page number (1-based)"), + per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + }) + .optional() + .describe("Pagination parameters"), + + order_by: z + .array( + z.object({ + field: z + .enum([ + "chain", + "related_wallet_address", + "relationship_type", + "relationship_strength", + "transaction_count", + "volume_usd", + "timestamp", + ]) + .describe("Field to sort by"), + direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), + }) + ) + .optional() + .describe("Custom sort order to override the endpoint's default ordering"), + }) + .strip() + .describe("Instructions for getting related wallets data"); + +/** + * Response interface for related wallets data. + */ +interface RelatedWallet { + chain: string; + related_wallet_address: string; + relationship_type: string; + relationship_strength: number; + transaction_count: number; + volume_usd?: number; + timestamp: string; +} + +interface RelatedWalletsResponse { + data: RelatedWallet[]; + pagination: { + page: number; + per_page: number; + is_last_page: boolean; + }; +} + +/** + * Fetches related wallets data from Nansen API. + * + * @param _wallet - The smart account (not used for this action). + * @param args - The input arguments containing wallet address, chains, filters, pagination, and sorting options. + * @returns A formatted string containing the related wallets data. + */ +export async function getRelatedWallets( + _wallet: ZeroXgaslessSmartAccount, + args: z.infer, +): Promise { + try { + const apiKey = process.env.NANSEN_API_KEY; + if (!apiKey) { + return "Error: NANSEN_API_KEY environment variable is required but not set."; + } + + const requestBody = { + wallet_address: args.wallet_address, + chains: args.chains, + ...(args.filters && { filters: args.filters }), + ...(args.pagination && { pagination: args.pagination }), + ...(args.order_by && { order_by: args.order_by }), + }; + + const response = await fetch("https://api.nansen.ai/api/v1/profiler/related-wallets", { + method: "POST", + headers: { + "Content-Type": "application/json", + apiKey: apiKey, + "User-Agent": "0xGasless-AgentKit/1.0", + }, + body: JSON.stringify(requestBody), + }); + + if (!response.ok) { + if (response.status === 401) { + return "Error: Invalid Nansen API key. Please check your NANSEN_API_KEY environment variable."; + } + if (response.status === 403) { + return "Error: Insufficient subscription tier for this endpoint."; + } + if (response.status === 429) { + return "Error: Rate limit exceeded. Please wait before making another request."; + } + return `Error fetching related wallets: ${response.status} ${response.statusText}`; + } + + const data: RelatedWalletsResponse = await response.json(); + + if (!data.data || data.data.length === 0) { + return `No related wallets found for wallet ${args.wallet_address}.`; + } + + let result = `🔗 Related Wallets for ${args.wallet_address}:\n\n`; + + data.data.forEach((wallet, index) => { + const timestamp = new Date(wallet.timestamp).toLocaleString(); + const strengthEmoji = wallet.relationship_strength >= 0.8 ? "🔗" : + wallet.relationship_strength >= 0.6 ? "🔗" : "🔗"; + + result += `${index + 1}. Related Wallet ${strengthEmoji}\n`; + result += ` • Address: ${wallet.related_wallet_address}\n`; + result += ` • Relationship: ${wallet.relationship_type}\n`; + result += ` • Strength: ${(wallet.relationship_strength * 100).toFixed(1)}%\n`; + result += ` • Chain: ${wallet.chain}\n`; + result += ` • Transactions: ${wallet.transaction_count}\n`; + if (wallet.volume_usd) { + result += ` • Volume: $${wallet.volume_usd.toLocaleString()}\n`; + } + result += ` • Last Activity: ${timestamp}\n`; + result += "\n"; + }); + + if (!data.pagination.is_last_page) { + result += `Page ${data.pagination.page} of results. Use pagination to get more results.\n`; + } + + return result; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : "An unknown error occurred"; + return `Error fetching related wallets: ${errorMessage}`; + } +} + +/** + * Get Related Wallets action. + */ +export class GetRelatedWalletsAction implements AgentkitAction { + public name = "get_related_wallets"; + public description = GET_RELATED_WALLETS_PROMPT; + public argsSchema = GetRelatedWalletsInput; + public func = getRelatedWallets; + public smartAccountRequired = false; +} diff --git a/agentkit-core/src/actions/NansenAction/Profiler/getTransactionLookupAction.ts b/agentkit-core/src/actions/NansenAction/Profiler/getTransactionLookupAction.ts new file mode 100644 index 0000000..5fe53f6 --- /dev/null +++ b/agentkit-core/src/actions/NansenAction/Profiler/getTransactionLookupAction.ts @@ -0,0 +1,228 @@ +import { z } from "zod"; +import { AgentkitAction } from "../../../agentkit"; +import { ZeroXgaslessSmartAccount } from "@0xgasless/smart-account"; + +const GET_TRANSACTION_LOOKUP_PROMPT = ` +Retrieve detailed transaction information for a specific transaction hash across multiple blockchains. This endpoint provides comprehensive transaction details including transfers, swaps, and other blockchain activities. + +Key Features: +- Detailed transaction information for a specific transaction hash +- Multi-chain support +- Comprehensive transaction details +- Transfer and swap information +- Complete transaction metadata + +This endpoint requires a Nansen API key to be configured. +`; + +/** + * Input schema for getting transaction lookup data. + */ +export const GetTransactionLookupInput = z + .object({ + transaction_hash: z.string().describe("The transaction hash to look up"), + + chains: z + .array( + z.enum([ + "all", + "arbitrum", + "avalanche", + "base", + "berachain", + "blast", + "bnb", + "ethereum", + "goat", + "hyperevm", + "iotaevm", + "linea", + "mantle", + "optimism", + "plasma", + "polygon", + "ronin", + "sei", + "scroll", + "sonic", + "unichain", + "zksync", + "solana", + ]) + ) + .describe("Chains to include in the analysis. Use 'all' to include all available chains."), + + filters: z + .object({ + transaction_type: z.array(z.string()).optional().describe("Transaction type filter"), + token_address: z.string().optional().describe("Token address filter"), + token_symbol: z.string().optional().describe("Token symbol filter"), + token_sectors: z.array(z.string()).optional().describe("Token sectors filter"), + value_usd: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Value range filter in USD"), + timestamp: z + .object({ + from: z.string().optional(), + to: z.string().optional(), + }) + .optional() + .describe("Timestamp range filter"), + }) + .optional() + .describe("Additional filters to apply"), + + pagination: z + .object({ + page: z.number().min(1).default(1).describe("Page number (1-based)"), + per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + }) + .optional() + .describe("Pagination parameters"), + + order_by: z + .array( + z.object({ + field: z + .enum([ + "chain", + "transaction_type", + "token_address", + "token_symbol", + "token_sectors", + "value_usd", + "timestamp", + ]) + .describe("Field to sort by"), + direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), + }) + ) + .optional() + .describe("Custom sort order to override the endpoint's default ordering"), + }) + .strip() + .describe("Instructions for getting transaction lookup data"); + +/** + * Response interface for transaction lookup data. + */ +interface TransactionLookup { + chain: string; + transaction_type: string; + token_address: string; + token_symbol: string; + token_sectors: string[]; + value_usd?: number; + timestamp: string; +} + +interface TransactionLookupResponse { + data: TransactionLookup[]; + pagination: { + page: number; + per_page: number; + is_last_page: boolean; + }; +} + +/** + * Fetches transaction lookup data from Nansen API. + * + * @param _wallet - The smart account (not used for this action). + * @param args - The input arguments containing transaction hash, chains, filters, pagination, and sorting options. + * @returns A formatted string containing the transaction lookup data. + */ +export async function getTransactionLookup( + _wallet: ZeroXgaslessSmartAccount, + args: z.infer, +): Promise { + try { + const apiKey = process.env.NANSEN_API_KEY; + if (!apiKey) { + return "Error: NANSEN_API_KEY environment variable is required but not set."; + } + + const requestBody = { + transaction_hash: args.transaction_hash, + chains: args.chains, + ...(args.filters && { filters: args.filters }), + ...(args.pagination && { pagination: args.pagination }), + ...(args.order_by && { order_by: args.order_by }), + }; + + const response = await fetch("https://api.nansen.ai/api/v1/profiler/transaction-lookup", { + method: "POST", + headers: { + "Content-Type": "application/json", + apiKey: apiKey, + "User-Agent": "0xGasless-AgentKit/1.0", + }, + body: JSON.stringify(requestBody), + }); + + if (!response.ok) { + if (response.status === 401) { + return "Error: Invalid Nansen API key. Please check your NANSEN_API_KEY environment variable."; + } + if (response.status === 403) { + return "Error: Insufficient subscription tier for this endpoint."; + } + if (response.status === 429) { + return "Error: Rate limit exceeded. Please wait before making another request."; + } + return `Error fetching transaction lookup: ${response.status} ${response.statusText}`; + } + + const data: TransactionLookupResponse = await response.json(); + + if (!data.data || data.data.length === 0) { + return `No transaction details found for hash ${args.transaction_hash}.`; + } + + let result = `🔍 Transaction Lookup for ${args.transaction_hash}:\n\n`; + + data.data.forEach((tx, index) => { + const timestamp = new Date(tx.timestamp).toLocaleString(); + const typeEmoji = tx.transaction_type === "swap" ? "🔄" : + tx.transaction_type === "transfer" ? "📤" : + tx.transaction_type === "mint" ? "🪙" : "📄"; + + result += `${index + 1}. Transaction Detail ${typeEmoji}\n`; + result += ` • Type: ${tx.transaction_type}\n`; + result += ` • Chain: ${tx.chain}\n`; + result += ` • Token: ${tx.token_symbol} (${tx.token_address})\n`; + if (tx.value_usd) { + result += ` • Value: $${tx.value_usd.toLocaleString()}\n`; + } + if (tx.token_sectors && tx.token_sectors.length > 0) { + result += ` • Sectors: ${tx.token_sectors.join(", ")}\n`; + } + result += ` • Time: ${timestamp}\n`; + result += "\n"; + }); + + if (!data.pagination.is_last_page) { + result += `Page ${data.pagination.page} of results. Use pagination to get more results.\n`; + } + + return result; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : "An unknown error occurred"; + return `Error fetching transaction lookup: ${errorMessage}`; + } +} + +/** + * Get Transaction Lookup action. + */ +export class GetTransactionLookupAction implements AgentkitAction { + public name = "get_transaction_lookup"; + public description = GET_TRANSACTION_LOOKUP_PROMPT; + public argsSchema = GetTransactionLookupInput; + public func = getTransactionLookup; + public smartAccountRequired = false; +} diff --git a/agentkit-core/src/actions/NansenAction/Profiler/getTransactionsAction.ts b/agentkit-core/src/actions/NansenAction/Profiler/getTransactionsAction.ts new file mode 100644 index 0000000..7e168ab --- /dev/null +++ b/agentkit-core/src/actions/NansenAction/Profiler/getTransactionsAction.ts @@ -0,0 +1,231 @@ +import { z } from "zod"; +import { AgentkitAction } from "../../../agentkit"; +import { ZeroXgaslessSmartAccount } from "@0xgasless/smart-account"; + +const GET_TRANSACTIONS_PROMPT = ` +Retrieve transaction history for a specific wallet address across multiple blockchains. This endpoint provides detailed transaction information including transfers, swaps, and other blockchain activities. + +Key Features: +- Transaction history for a specific wallet +- Multi-chain support +- Detailed transaction information +- Transfer and swap activities +- Comprehensive transaction metadata + +This endpoint requires a Nansen API key to be configured. +`; + +/** + * Input schema for getting transactions data. + */ +export const GetTransactionsInput = z + .object({ + wallet_address: z.string().describe("The wallet address to get transactions for"), + + chains: z + .array( + z.enum([ + "all", + "arbitrum", + "avalanche", + "base", + "berachain", + "blast", + "bnb", + "ethereum", + "goat", + "hyperevm", + "iotaevm", + "linea", + "mantle", + "optimism", + "plasma", + "polygon", + "ronin", + "sei", + "scroll", + "sonic", + "unichain", + "zksync", + "solana", + ]) + ) + .describe("Chains to include in the analysis. Use 'all' to include all available chains."), + + filters: z + .object({ + transaction_hash: z.string().optional().describe("Transaction hash filter"), + transaction_type: z.array(z.string()).optional().describe("Transaction type filter"), + token_address: z.string().optional().describe("Token address filter"), + token_symbol: z.string().optional().describe("Token symbol filter"), + counterparty_address: z.string().optional().describe("Counterparty address filter"), + counterparty_label: z.string().optional().describe("Counterparty label filter"), + value_usd: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Value range filter in USD"), + timestamp: z + .object({ + from: z.string().optional(), + to: z.string().optional(), + }) + .optional() + .describe("Timestamp range filter"), + }) + .optional() + .describe("Additional filters to apply"), + + pagination: z + .object({ + page: z.number().min(1).default(1).describe("Page number (1-based)"), + per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + }) + .optional() + .describe("Pagination parameters"), + + order_by: z + .array( + z.object({ + field: z + .enum([ + "chain", + "transaction_hash", + "transaction_type", + "token_address", + "token_symbol", + "counterparty_address", + "counterparty_label", + "value_usd", + "timestamp", + ]) + .describe("Field to sort by"), + direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), + }) + ) + .optional() + .describe("Custom sort order to override the endpoint's default ordering"), + }) + .strip() + .describe("Instructions for getting transactions data"); + +/** + * Response interface for transactions data. + */ +interface Transaction { + chain: string; + transaction_hash: string; + transaction_type: string; + token_address: string; + token_symbol: string; + counterparty_address: string; + counterparty_label: string; + value_usd?: number; + timestamp: string; +} + +interface TransactionsResponse { + data: Transaction[]; + pagination: { + page: number; + per_page: number; + is_last_page: boolean; + }; +} + +/** + * Fetches transactions data from Nansen API. + * + * @param _wallet - The smart account (not used for this action). + * @param args - The input arguments containing wallet address, chains, filters, pagination, and sorting options. + * @returns A formatted string containing the transactions data. + */ +export async function getTransactions( + _wallet: ZeroXgaslessSmartAccount, + args: z.infer, +): Promise { + try { + const apiKey = process.env.NANSEN_API_KEY; + if (!apiKey) { + return "Error: NANSEN_API_KEY environment variable is required but not set."; + } + + const requestBody = { + wallet_address: args.wallet_address, + chains: args.chains, + ...(args.filters && { filters: args.filters }), + ...(args.pagination && { pagination: args.pagination }), + ...(args.order_by && { order_by: args.order_by }), + }; + + const response = await fetch("https://api.nansen.ai/api/v1/profiler/transactions", { + method: "POST", + headers: { + "Content-Type": "application/json", + apiKey: apiKey, + "User-Agent": "0xGasless-AgentKit/1.0", + }, + body: JSON.stringify(requestBody), + }); + + if (!response.ok) { + if (response.status === 401) { + return "Error: Invalid Nansen API key. Please check your NANSEN_API_KEY environment variable."; + } + if (response.status === 403) { + return "Error: Insufficient subscription tier for this endpoint."; + } + if (response.status === 429) { + return "Error: Rate limit exceeded. Please wait before making another request."; + } + return `Error fetching transactions: ${response.status} ${response.statusText}`; + } + + const data: TransactionsResponse = await response.json(); + + if (!data.data || data.data.length === 0) { + return `No transactions found for wallet ${args.wallet_address}.`; + } + + let result = `📋 Transactions for ${args.wallet_address}:\n\n`; + + data.data.forEach((tx, index) => { + const timestamp = new Date(tx.timestamp).toLocaleString(); + const typeEmoji = tx.transaction_type === "swap" ? "🔄" : tx.transaction_type === "transfer" ? "📤" : "📄"; + + result += `${index + 1}. Transaction ${typeEmoji}\n`; + result += ` • Type: ${tx.transaction_type}\n`; + result += ` • Chain: ${tx.chain}\n`; + result += ` • Token: ${tx.token_symbol} (${tx.token_address})\n`; + result += ` • Counterparty: ${tx.counterparty_label || tx.counterparty_address}\n`; + if (tx.value_usd) { + result += ` • Value: $${tx.value_usd.toLocaleString()}\n`; + } + result += ` • Time: ${timestamp}\n`; + result += ` • Tx Hash: ${tx.transaction_hash}\n`; + result += "\n"; + }); + + if (!data.pagination.is_last_page) { + result += `Page ${data.pagination.page} of results. Use pagination to get more results.\n`; + } + + return result; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : "An unknown error occurred"; + return `Error fetching transactions: ${errorMessage}`; + } +} + +/** + * Get Transactions action. + */ +export class GetTransactionsAction implements AgentkitAction { + public name = "get_transactions"; + public description = GET_TRANSACTIONS_PROMPT; + public argsSchema = GetTransactionsInput; + public func = getTransactions; + public smartAccountRequired = false; +} diff --git a/agentkit-core/src/actions/NansenAction/Profiler/index.ts b/agentkit-core/src/actions/NansenAction/Profiler/index.ts new file mode 100644 index 0000000..10a03e2 --- /dev/null +++ b/agentkit-core/src/actions/NansenAction/Profiler/index.ts @@ -0,0 +1,9 @@ +export { GetCurrentBalanceAction } from "./getCurrentBalanceAction"; +export { GetHistoricalBalanceAction } from "./getHistoricalBalanceAction"; +export { GetTransactionsAction } from "./getTransactionsAction"; +export { GetCounterpartiesAction } from "./getCounterpartiesAction"; +export { GetRelatedWalletsAction } from "./getRelatedWalletsAction"; +export { GetPnlSummaryAction } from "./getPnlSummaryAction"; +export { GetPnlAction } from "./getPnlAction"; +export { GetLabelsAction } from "./getLabelsAction"; +export { GetTransactionLookupAction } from "./getTransactionLookupAction"; diff --git a/agentkit-core/src/actions/NansenAction/SmartMoney/getSmartMoneyDcasAction.ts b/agentkit-core/src/actions/NansenAction/SmartMoney/getSmartMoneyDcasAction.ts new file mode 100644 index 0000000..fd9abec --- /dev/null +++ b/agentkit-core/src/actions/NansenAction/SmartMoney/getSmartMoneyDcasAction.ts @@ -0,0 +1,234 @@ +import { z } from "zod"; +import { AgentkitAction } from "../../../agentkit"; +import { ZeroXgaslessSmartAccount } from "@0xgasless/smart-account"; + +const GET_SMART_MONEY_DCAS_PROMPT = ` +Monitor DCA strategies employed by smart money on Solana through Jupiter DCA. This endpoint reveals systematic accumulation strategies used by smart money. + +Key Features: +- DCA strategies employed by smart money on Solana +- Jupiter DCA integration +- Systematic accumulation strategies +- Real-time monitoring of DCA orders +- Detailed DCA vault information + +This endpoint requires a Nansen API key to be configured. +`; + +/** + * Input schema for getting smart money DCAs data. + */ +export const GetSmartMoneyDcasInput = z + .object({ + filters: z + .object({ + include_smart_money_labels: z + .array(z.enum(["Fund", "Smart Trader", "30D Smart Trader", "90D Smart Trader", "180D Smart Trader"])) + .optional() + .describe("Smart money category filters to include"), + exclude_smart_money_labels: z + .array(z.enum(["Fund", "Smart Trader", "30D Smart Trader", "90D Smart Trader", "180D Smart Trader"])) + .optional() + .describe("Smart money category filters to exclude"), + dca_created_at: z + .object({ + from: z.string().optional(), + to: z.string().optional(), + }) + .optional() + .describe("Date range filter for DCA creation timestamps"), + transaction_hash: z.string().optional().describe("Transaction hash filter"), + trader_address: z.string().optional().describe("Trader address filter"), + trader_address_label: z.string().optional().describe("Trader name or label filter"), + input_token_symbol: z.string().optional().describe("Symbol filter for input tokens"), + output_token_symbol: z.string().optional().describe("Symbol filter for output tokens"), + deposit_token_amount: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Deposit amount range filter"), + token_spent_amount: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Token spent amount range filter"), + output_token_redeemed_amount: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Output token redeemed amount range filter"), + }) + .optional() + .describe("Additional filters to apply"), + + pagination: z + .object({ + page: z.number().min(1).default(1).describe("Page number (1-based)"), + per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + }) + .optional() + .describe("Pagination parameters"), + + order_by: z + .array( + z.object({ + field: z + .enum([ + "dca_created_at", + "dca_updated_at", + "input_token_symbol", + "output_token_symbol", + "deposit_token_amount", + "token_spent_amount", + "deposit_value_usd", + "output_token_redeemed_amount", + ]) + .describe("Field to sort by"), + direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), + }) + ) + .optional() + .describe("Custom sort order to override the endpoint's default ordering"), + }) + .strip() + .describe("Instructions for getting smart money DCAs data"); + +/** + * Response interface for smart money DCAs data. + */ +interface SmartMoneyDca { + dca_created_at: string; + dca_updated_at: string; + trader_address: string; + transaction_hash: string; + trader_address_label: string; + dca_vault_address: string; + input_token_address: string; + output_token_address: string; + deposit_token_amount?: number; + token_spent_amount?: number; + output_token_redeemed_amount?: number; + dca_status: string; + input_token_symbol: string; + output_token_symbol: string; + deposit_value_usd?: number; +} + +interface SmartMoneyDcasResponse { + data: SmartMoneyDca[]; + pagination: { + page: number; + per_page: number; + is_last_page: boolean; + }; +} + +/** + * Fetches smart money DCAs data from Nansen API. + * + * @param _wallet - The smart account (not used for this action). + * @param args - The input arguments containing filters, pagination, and sorting options. + * @returns A formatted string containing the smart money DCAs data. + */ +export async function getSmartMoneyDcas( + _wallet: ZeroXgaslessSmartAccount, + args: z.infer, +): Promise { + try { + const apiKey = process.env.NANSEN_API_KEY; + if (!apiKey) { + return "Error: NANSEN_API_KEY environment variable is required but not set."; + } + + const requestBody = { + ...(args.filters && { filters: args.filters }), + ...(args.pagination && { pagination: args.pagination }), + ...(args.order_by && { order_by: args.order_by }), + }; + + const response = await fetch("https://api.nansen.ai/api/v1/smart-money/dcas", { + method: "POST", + headers: { + "Content-Type": "application/json", + apiKey: apiKey, + "User-Agent": "0xGasless-AgentKit/1.0", + }, + body: JSON.stringify(requestBody), + }); + + if (!response.ok) { + if (response.status === 401) { + return "Error: Invalid Nansen API key. Please check your NANSEN_API_KEY environment variable."; + } + if (response.status === 403) { + return "Error: Insufficient subscription tier for this endpoint."; + } + if (response.status === 429) { + return "Error: Rate limit exceeded. Please wait before making another request."; + } + return `Error fetching smart money DCAs: ${response.status} ${response.statusText}`; + } + + const data: SmartMoneyDcasResponse = await response.json(); + + if (!data.data || data.data.length === 0) { + return "No smart money DCA orders found matching your criteria."; + } + + let result = "📈 Smart Money DCA Orders (Jupiter):\n\n"; + + data.data.forEach((dca, index) => { + const createdDate = new Date(dca.dca_created_at).toLocaleString(); + const updatedDate = new Date(dca.dca_updated_at).toLocaleString(); + const statusEmoji = dca.dca_status === "active" ? "🟢" : "🔴"; + + result += `${index + 1}. DCA Order ${statusEmoji}\n`; + result += ` • Trader: ${dca.trader_address_label || dca.trader_address}\n`; + result += ` • Strategy: ${dca.input_token_symbol} → ${dca.output_token_symbol}\n`; + result += ` • Status: ${dca.dca_status}\n`; + result += ` • Created: ${createdDate}\n`; + result += ` • Updated: ${updatedDate}\n`; + if (dca.deposit_token_amount) { + result += ` • Deposit Amount: ${dca.deposit_token_amount.toFixed(4)} ${dca.input_token_symbol}\n`; + } + if (dca.token_spent_amount) { + result += ` • Tokens Spent: ${dca.token_spent_amount.toFixed(4)} ${dca.input_token_symbol}\n`; + } + if (dca.output_token_redeemed_amount) { + result += ` • Tokens Redeemed: ${dca.output_token_redeemed_amount.toFixed(4)} ${dca.output_token_symbol}\n`; + } + if (dca.deposit_value_usd) { + result += ` • Deposit Value: $${dca.deposit_value_usd.toLocaleString()}\n`; + } + result += ` • DCA Vault: ${dca.dca_vault_address}\n`; + result += ` • Tx Hash: ${dca.transaction_hash}\n`; + result += "\n"; + }); + + if (!data.pagination.is_last_page) { + result += `Page ${data.pagination.page} of results. Use pagination to get more results.\n`; + } + + return result; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : "An unknown error occurred"; + return `Error fetching smart money DCAs: ${errorMessage}`; + } +} + +/** + * Get Smart Money DCAs action. + */ +export class GetSmartMoneyDcasAction implements AgentkitAction { + public name = "get_smart_money_dcas"; + public description = GET_SMART_MONEY_DCAS_PROMPT; + public argsSchema = GetSmartMoneyDcasInput; + public func = getSmartMoneyDcas; + public smartAccountRequired = false; +} diff --git a/agentkit-core/src/actions/NansenAction/SmartMoney/getSmartMoneyDexTradesAction.ts b/agentkit-core/src/actions/NansenAction/SmartMoney/getSmartMoneyDexTradesAction.ts new file mode 100644 index 0000000..2900e84 --- /dev/null +++ b/agentkit-core/src/actions/NansenAction/SmartMoney/getSmartMoneyDexTradesAction.ts @@ -0,0 +1,288 @@ +import { z } from "zod"; +import { AgentkitAction } from "../../../agentkit"; +import { ZeroXgaslessSmartAccount } from "@0xgasless/smart-account"; + +const GET_SMART_MONEY_DEX_TRADES_PROMPT = ` +Access real-time DEX trading activity from smart traders and funds over the last 24 hours. This endpoint provides granular transaction-level data showing exactly what sophisticated traders are buying and selling on decentralized exchanges. + +Key Features: +- Real-time DEX trading activity from smart traders and funds +- Last 24 hours of trading data +- Granular transaction-level information +- Shows exactly what sophisticated traders are buying and selling +- Detailed trade information including amounts, prices, and timing + +This endpoint requires a Nansen API key to be configured. +`; + +/** + * Input schema for getting smart money DEX trades data. + */ +export const GetSmartMoneyDexTradesInput = z + .object({ + chains: z + .array( + z.enum([ + "all", + "arbitrum", + "avalanche", + "base", + "berachain", + "blast", + "bnb", + "ethereum", + "goat", + "hyperevm", + "iotaevm", + "linea", + "mantle", + "optimism", + "plasma", + "polygon", + "ronin", + "sei", + "scroll", + "sonic", + "unichain", + "zksync", + "solana", + ]) + ) + .describe("Chains to include in the analysis (only smart money supported chains). Use 'all' to include all available chains."), + + filters: z + .object({ + include_smart_money_labels: z + .array(z.enum(["Fund", "Smart Trader", "30D Smart Trader", "90D Smart Trader", "180D Smart Trader"])) + .optional() + .describe("Smart money category filters to include"), + exclude_smart_money_labels: z + .array(z.enum(["Fund", "Smart Trader", "30D Smart Trader", "90D Smart Trader", "180D Smart Trader"])) + .optional() + .describe("Smart money category filters to exclude"), + chain: z.string().optional().describe("Blockchain network filter"), + transaction_hash: z.string().optional().describe("Transaction hash filter"), + trader_address: z.string().optional().describe("Trader address filter"), + trader_address_label: z.string().optional().describe("Trader name or label filter"), + token_bought_address: z.string().optional().describe("Token address filter for bought tokens"), + token_sold_address: z.string().optional().describe("Token address filter for sold tokens"), + token_bought_amount: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Amount range filter for bought tokens"), + token_sold_amount: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Amount range filter for sold tokens"), + token_bought_symbol: z.string().optional().describe("Symbol filter for bought tokens"), + token_sold_symbol: z.string().optional().describe("Symbol filter for sold tokens"), + token_bought_age_days: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Age range filter for bought tokens in days"), + token_sold_age_days: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Age range filter for sold tokens in days"), + token_bought_market_cap: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Market cap range filter for bought tokens"), + token_sold_market_cap: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Market cap range filter for sold tokens"), + trade_value_usd: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Trade value range filter in USD"), + }) + .optional() + .describe("Additional filters to apply"), + + pagination: z + .object({ + page: z.number().min(1).default(1).describe("Page number (1-based)"), + per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + }) + .optional() + .describe("Pagination parameters"), + + order_by: z + .array( + z.object({ + field: z + .enum([ + "chain", + "block_timestamp", + "transaction_hash", + "trader_address", + "trader_address_label", + "token_bought_address", + "token_sold_address", + "token_bought_amount", + "token_sold_amount", + "token_bought_symbol", + "token_sold_symbol", + "token_bought_age_days", + "token_sold_age_days", + "token_bought_market_cap", + "token_sold_market_cap", + "trade_value_usd", + ]) + .describe("Field to sort by"), + direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), + }) + ) + .optional() + .describe("Custom sort order to override the endpoint's default ordering"), + }) + .strip() + .describe("Instructions for getting smart money DEX trades data"); + +/** + * Response interface for smart money DEX trades data. + */ +interface SmartMoneyDexTrade { + chain: string; + block_timestamp: string; + transaction_hash: string; + trader_address: string; + trader_address_label: string; + token_bought_address: string; + token_sold_address: string; + token_bought_amount?: number; + token_sold_amount?: number; + token_bought_symbol: string; + token_sold_symbol: string; + token_bought_age_days: number; + token_sold_age_days: number; + token_bought_market_cap?: number; + token_sold_market_cap?: number; + trade_value_usd?: number; +} + +interface SmartMoneyDexTradesResponse { + data: SmartMoneyDexTrade[]; + pagination: { + page: number; + per_page: number; + is_last_page: boolean; + }; +} + +/** + * Fetches smart money DEX trades data from Nansen API. + * + * @param _wallet - The smart account (not used for this action). + * @param args - The input arguments containing chains, filters, pagination, and sorting options. + * @returns A formatted string containing the smart money DEX trades data. + */ +export async function getSmartMoneyDexTrades( + _wallet: ZeroXgaslessSmartAccount, + args: z.infer, +): Promise { + try { + const apiKey = process.env.NANSEN_API_KEY; + if (!apiKey) { + return "Error: NANSEN_API_KEY environment variable is required but not set."; + } + + const requestBody = { + chains: args.chains, + ...(args.filters && { filters: args.filters }), + ...(args.pagination && { pagination: args.pagination }), + ...(args.order_by && { order_by: args.order_by }), + }; + + const response = await fetch("https://api.nansen.ai/api/v1/smart-money/dex-trades", { + method: "POST", + headers: { + "Content-Type": "application/json", + apiKey: apiKey, + "User-Agent": "0xGasless-AgentKit/1.0", + }, + body: JSON.stringify(requestBody), + }); + + if (!response.ok) { + if (response.status === 401) { + return "Error: Invalid Nansen API key. Please check your NANSEN_API_KEY environment variable."; + } + if (response.status === 403) { + return "Error: Insufficient subscription tier for this endpoint."; + } + if (response.status === 429) { + return "Error: Rate limit exceeded. Please wait before making another request."; + } + return `Error fetching smart money DEX trades: ${response.status} ${response.statusText}`; + } + + const data: SmartMoneyDexTradesResponse = await response.json(); + + if (!data.data || data.data.length === 0) { + return "No smart money DEX trades found matching your criteria."; + } + + let result = "🔄 Smart Money DEX Trades (Last 24h):\n\n"; + + data.data.forEach((trade, index) => { + const timestamp = new Date(trade.block_timestamp).toLocaleString(); + result += `${index + 1}. DEX Trade\n`; + result += ` • Trader: ${trade.trader_address_label || trade.trader_address}\n`; + result += ` • Chain: ${trade.chain}\n`; + result += ` • Time: ${timestamp}\n`; + result += ` • Trade: ${trade.token_sold_amount?.toFixed(4) || "?"} ${trade.token_sold_symbol} → ${trade.token_bought_amount?.toFixed(4) || "?"} ${trade.token_bought_symbol}\n`; + if (trade.trade_value_usd) { + result += ` • Value: $${trade.trade_value_usd.toLocaleString()}\n`; + } + result += ` • Tx Hash: ${trade.transaction_hash}\n`; + result += ` • Token Ages: ${trade.token_sold_symbol} (${trade.token_sold_age_days}d), ${trade.token_bought_symbol} (${trade.token_bought_age_days}d)\n`; + if (trade.token_bought_market_cap || trade.token_sold_market_cap) { + result += ` • Market Caps: ${trade.token_sold_symbol} $${trade.token_sold_market_cap?.toLocaleString() || "N/A"}, ${trade.token_bought_symbol} $${trade.token_bought_market_cap?.toLocaleString() || "N/A"}\n`; + } + result += "\n"; + }); + + if (!data.pagination.is_last_page) { + result += `Page ${data.pagination.page} of results. Use pagination to get more results.\n`; + } + + return result; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : "An unknown error occurred"; + return `Error fetching smart money DEX trades: ${errorMessage}`; + } +} + +/** + * Get Smart Money DEX Trades action. + */ +export class GetSmartMoneyDexTradesAction implements AgentkitAction { + public name = "get_smart_money_dex_trades"; + public description = GET_SMART_MONEY_DEX_TRADES_PROMPT; + public argsSchema = GetSmartMoneyDexTradesInput; + public func = getSmartMoneyDexTrades; + public smartAccountRequired = false; +} diff --git a/agentkit-core/src/actions/NansenAction/SmartMoney/getSmartMoneyHoldingsAction.ts b/agentkit-core/src/actions/NansenAction/SmartMoney/getSmartMoneyHoldingsAction.ts new file mode 100644 index 0000000..6fa4f69 --- /dev/null +++ b/agentkit-core/src/actions/NansenAction/SmartMoney/getSmartMoneyHoldingsAction.ts @@ -0,0 +1,270 @@ +import { z } from "zod"; +import { AgentkitAction } from "../../../agentkit"; +import { ZeroXgaslessSmartAccount } from "@0xgasless/smart-account"; + +const GET_SMART_MONEY_HOLDINGS_PROMPT = ` +Retrieve aggregated token balances held by smart traders and funds across multiple blockchains. This endpoint provides insights into what tokens are being accumulated by sophisticated market participants, excluding whales, large holders, and influencers to focus specifically on trading expertise. + +Key Features: +- Aggregated balances (not per-wallet breakdowns) +- 24-hour balance change tracking updated in realtime +- Sector categorization for tokens +- Focus on trading expertise rather than size + +This endpoint requires a Nansen API key to be configured. +`; + +/** + * Input schema for getting smart money holdings data. + */ +export const GetSmartMoneyHoldingsInput = z + .object({ + chains: z + .array( + z.enum([ + "all", + "arbitrum", + "avalanche", + "base", + "berachain", + "blast", + "bnb", + "ethereum", + "goat", + "hyperevm", + "iotaevm", + "linea", + "mantle", + "optimism", + "plasma", + "polygon", + "ronin", + "sei", + "scroll", + "sonic", + "unichain", + "zksync", + "solana", + ]) + ) + .describe("Chains to include in the analysis (only smart money supported chains). Use 'all' to include all available chains."), + + filters: z + .object({ + include_smart_money_labels: z + .array(z.enum(["Fund", "Smart Trader", "30D Smart Trader", "90D Smart Trader", "180D Smart Trader"])) + .optional() + .describe("Smart money category filters to include"), + exclude_smart_money_labels: z + .array(z.enum(["Fund", "Smart Trader", "30D Smart Trader", "90D Smart Trader", "180D Smart Trader"])) + .optional() + .describe("Smart money category filters to exclude"), + include_stablecoins: z.boolean().optional().default(false).describe("Whether to include stablecoins in the results"), + include_native_tokens: z.boolean().optional().default(false).describe("Whether to include native tokens (e.g., ETH, SOL) in the results"), + value_usd: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Value range filter in USD"), + balance_24h_percent_change: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("24-hour balance change percentage range filter"), + holders_count: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Number of holders range filter"), + share_of_holdings_percent: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Share of holdings percentage range filter"), + token_age_days: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Token age range filter in days"), + market_cap_usd: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Market cap range filter in USD"), + token_address: z.string().optional().describe("Token address filter"), + token_symbol: z.string().optional().describe("Token symbol filter"), + token_sectors: z.array(z.string()).optional().describe("Token sectors filter"), + }) + .optional() + .describe("Additional filters to apply"), + + pagination: z + .object({ + page: z.number().min(1).default(1).describe("Page number (1-based)"), + per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + }) + .optional() + .describe("Pagination parameters"), + + order_by: z + .array( + z.object({ + field: z + .enum([ + "chain", + "token_address", + "token_symbol", + "value_usd", + "balance_24h_percent_change", + "holders_count", + "share_of_holdings_percent", + "token_age_days", + "market_cap_usd", + ]) + .describe("Field to sort by"), + direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), + }) + ) + .optional() + .describe("Custom sort order to override the endpoint's default ordering"), + }) + .strip() + .describe("Instructions for getting smart money holdings data"); + +/** + * Response interface for smart money holdings data. + */ +interface SmartMoneyHolding { + chain: string; + token_address: string; + token_symbol: string; + token_sectors: string[]; + value_usd?: number; + balance_24h_percent_change?: number; + holders_count: number; + share_of_holdings_percent?: number; + token_age_days: number; + market_cap_usd?: number; +} + +interface SmartMoneyHoldingsResponse { + data: SmartMoneyHolding[]; + pagination: { + page: number; + per_page: number; + is_last_page: boolean; + }; +} + +/** + * Fetches smart money holdings data from Nansen API. + * + * @param _wallet - The smart account (not used for this action). + * @param args - The input arguments containing chains, filters, pagination, and sorting options. + * @returns A formatted string containing the smart money holdings data. + */ +export async function getSmartMoneyHoldings( + _wallet: ZeroXgaslessSmartAccount, + args: z.infer, +): Promise { + try { + const apiKey = process.env.NANSEN_API_KEY; + if (!apiKey) { + return "Error: NANSEN_API_KEY environment variable is required but not set."; + } + + const requestBody = { + chains: args.chains, + ...(args.filters && { filters: args.filters }), + ...(args.pagination && { pagination: args.pagination }), + ...(args.order_by && { order_by: args.order_by }), + }; + + const response = await fetch("https://api.nansen.ai/api/v1/smart-money/holdings", { + method: "POST", + headers: { + "Content-Type": "application/json", + apiKey: apiKey, + "User-Agent": "0xGasless-AgentKit/1.0", + }, + body: JSON.stringify(requestBody), + }); + + if (!response.ok) { + if (response.status === 401) { + return "Error: Invalid Nansen API key. Please check your NANSEN_API_KEY environment variable."; + } + if (response.status === 403) { + return "Error: Insufficient subscription tier for this endpoint."; + } + if (response.status === 429) { + return "Error: Rate limit exceeded. Please wait before making another request."; + } + return `Error fetching smart money holdings: ${response.status} ${response.statusText}`; + } + + const data: SmartMoneyHoldingsResponse = await response.json(); + + if (!data.data || data.data.length === 0) { + return "No smart money holdings data found matching your criteria."; + } + + let result = "💼 Smart Money Holdings Analysis:\n\n"; + + data.data.forEach((item, index) => { + result += `${index + 1}. ${item.token_symbol} (${item.chain})\n`; + result += ` • Token Address: ${item.token_address}\n`; + if (item.value_usd) { + result += ` • Total Value: $${item.value_usd.toLocaleString()}\n`; + } + if (item.balance_24h_percent_change !== undefined) { + const changeEmoji = item.balance_24h_percent_change >= 0 ? "📈" : "📉"; + result += ` • 24h Change: ${changeEmoji} ${item.balance_24h_percent_change.toFixed(2)}%\n`; + } + result += ` • Smart Money Holders: ${item.holders_count}\n`; + if (item.share_of_holdings_percent !== undefined) { + result += ` • Share of Holdings: ${item.share_of_holdings_percent.toFixed(2)}%\n`; + } + result += ` • Token Age: ${item.token_age_days} days\n`; + if (item.market_cap_usd) { + result += ` • Market Cap: $${item.market_cap_usd.toLocaleString()}\n`; + } + if (item.token_sectors && item.token_sectors.length > 0) { + result += ` • Sectors: ${item.token_sectors.join(", ")}\n`; + } + result += "\n"; + }); + + if (!data.pagination.is_last_page) { + result += `Page ${data.pagination.page} of results. Use pagination to get more results.\n`; + } + + return result; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : "An unknown error occurred"; + return `Error fetching smart money holdings: ${errorMessage}`; + } +} + +/** + * Get Smart Money Holdings action. + */ +export class GetSmartMoneyHoldingsAction implements AgentkitAction { + public name = "get_smart_money_holdings"; + public description = GET_SMART_MONEY_HOLDINGS_PROMPT; + public argsSchema = GetSmartMoneyHoldingsInput; + public func = getSmartMoneyHoldings; + public smartAccountRequired = false; +} diff --git a/agentkit-core/src/actions/NansenAction/SmartMoney/getSmartMoneyNetflowAction.ts b/agentkit-core/src/actions/NansenAction/SmartMoney/getSmartMoneyNetflowAction.ts new file mode 100644 index 0000000..dbbcee7 --- /dev/null +++ b/agentkit-core/src/actions/NansenAction/SmartMoney/getSmartMoneyNetflowAction.ts @@ -0,0 +1,249 @@ +import { z } from "zod"; +import { AgentkitAction } from "../../../agentkit"; +import { ZeroXgaslessSmartAccount } from "@0xgasless/smart-account"; + +const GET_SMART_MONEY_NETFLOW_PROMPT = ` +Analyze net capital flows (inflows vs outflows) from smart traders and funds across different time periods. This endpoint helps identify which tokens are experiencing net accumulation or distribution by smart money. + +What are Net Flows? +Net flows represent the difference between smart money inflows and outflows for a token. This includes: +- DEX Trading Activity: Tokens bought vs sold on decentralized exchanges +- CEX Transfers: Tokens sent to or received from centralized exchanges +- Positive Net Flow: Smart money is accumulating (buying more than selling, or withdrawing from CEXs) +- Negative Net Flow: Smart money is distributing (selling more than buying, or depositing to CEXs) + +Key Features: +- Aggregated net flow calculations across all smart money activity +- Multiple time period analysis (24h, 7d, 30d) +- Sortable results by volume metrics +- Includes both DEX trades and CEX transfers + +This endpoint requires a Nansen API key to be configured. +`; + +/** + * Input schema for getting smart money netflow data. + */ +export const GetSmartMoneyNetflowInput = z + .object({ + chains: z + .array( + z.enum([ + "all", + "arbitrum", + "avalanche", + "base", + "berachain", + "blast", + "bnb", + "ethereum", + "goat", + "hyperevm", + "iotaevm", + "linea", + "mantle", + "optimism", + "plasma", + "polygon", + "ronin", + "sei", + "scroll", + "sonic", + "unichain", + "zksync", + "solana", + ]) + ) + .describe("Chains to include in the analysis (only smart money supported chains). Use 'all' to include all available chains."), + + filters: z + .object({ + include_smart_money_labels: z + .array(z.enum(["Fund", "Smart Trader", "30D Smart Trader", "90D Smart Trader", "180D Smart Trader"])) + .optional() + .describe("Smart money category filters to include"), + exclude_smart_money_labels: z + .array(z.enum(["Fund", "Smart Trader", "30D Smart Trader", "90D Smart Trader", "180D Smart Trader"])) + .optional() + .describe("Smart money category filters to exclude"), + token_address: z.string().optional().describe("Token address or symbol filter"), + include_stablecoins: z.boolean().optional().default(false).describe("Whether to include stablecoins in the results"), + include_native_tokens: z.boolean().optional().default(false).describe("Whether to include native tokens (e.g., ETH, SOL) in the results"), + token_sector: z.array(z.string()).optional().describe("Token sector filter"), + trader_count: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Trader count range filter"), + token_age_days: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Token age range filter in days"), + market_cap_usd: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Market cap range filter in USD"), + }) + .optional() + .describe("Additional filters to apply"), + + pagination: z + .object({ + page: z.number().min(1).default(1).describe("Page number (1-based)"), + per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + }) + .optional() + .describe("Pagination parameters"), + + order_by: z + .array( + z.object({ + field: z + .enum([ + "chain", + "token_address", + "token_symbol", + "net_flow_24h_usd", + "net_flow_7d_usd", + "net_flow_30d_usd", + "token_sectors", + "trader_count", + "token_age_days", + "market_cap_usd", + ]) + .describe("Field to sort by"), + direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), + }) + ) + .optional() + .describe("Custom sort order to override the endpoint's default ordering"), + }) + .strip() + .describe("Instructions for getting smart money netflow data"); + +/** + * Response interface for smart money netflow data. + */ +interface SmartMoneyNetflow { + token_address: string; + token_symbol: string; + net_flow_24h_usd: number; + net_flow_7d_usd: number; + net_flow_30d_usd: number; + chain: string; + token_sectors: string[]; + trader_count: number; + token_age_days: number; + market_cap_usd?: number; +} + +interface SmartMoneyNetflowResponse { + data: SmartMoneyNetflow[]; + pagination: { + page: number; + per_page: number; + is_last_page: boolean; + }; +} + +/** + * Fetches smart money netflow data from Nansen API. + * + * @param _wallet - The smart account (not used for this action). + * @param args - The input arguments containing chains, filters, pagination, and sorting options. + * @returns A formatted string containing the smart money netflow data. + */ +export async function getSmartMoneyNetflow( + _wallet: ZeroXgaslessSmartAccount, + args: z.infer, +): Promise { + try { + const apiKey = process.env.NANSEN_API_KEY; + if (!apiKey) { + return "Error: NANSEN_API_KEY environment variable is required but not set."; + } + + const requestBody = { + chains: args.chains, + ...(args.filters && { filters: args.filters }), + ...(args.pagination && { pagination: args.pagination }), + ...(args.order_by && { order_by: args.order_by }), + }; + + const response = await fetch("https://api.nansen.ai/api/v1/smart-money/netflow", { + method: "POST", + headers: { + "Content-Type": "application/json", + apiKey: apiKey, + "User-Agent": "0xGasless-AgentKit/1.0", + }, + body: JSON.stringify(requestBody), + }); + + if (!response.ok) { + if (response.status === 401) { + return "Error: Invalid Nansen API key. Please check your NANSEN_API_KEY environment variable."; + } + if (response.status === 403) { + return "Error: Insufficient subscription tier for this endpoint."; + } + if (response.status === 429) { + return "Error: Rate limit exceeded. Please wait before making another request."; + } + return `Error fetching smart money netflow: ${response.status} ${response.statusText}`; + } + + const data: SmartMoneyNetflowResponse = await response.json(); + + if (!data.data || data.data.length === 0) { + return "No smart money netflow data found matching your criteria."; + } + + let result = "📊 Smart Money Netflow Analysis:\n\n"; + + data.data.forEach((item, index) => { + result += `${index + 1}. ${item.token_symbol} (${item.chain})\n`; + result += ` • Token Address: ${item.token_address}\n`; + result += ` • Net Flow 24h: $${item.net_flow_24h_usd?.toLocaleString() || "N/A"}\n`; + result += ` • Net Flow 7d: $${item.net_flow_7d_usd?.toLocaleString() || "N/A"}\n`; + result += ` • Net Flow 30d: $${item.net_flow_30d_usd?.toLocaleString() || "N/A"}\n`; + result += ` • Smart Money Traders: ${item.trader_count}\n`; + result += ` • Token Age: ${item.token_age_days} days\n`; + if (item.market_cap_usd) { + result += ` • Market Cap: $${item.market_cap_usd.toLocaleString()}\n`; + } + if (item.token_sectors && item.token_sectors.length > 0) { + result += ` • Sectors: ${item.token_sectors.join(", ")}\n`; + } + result += "\n"; + }); + + if (!data.pagination.is_last_page) { + result += `Page ${data.pagination.page} of results. Use pagination to get more results.\n`; + } + + return result; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : "An unknown error occurred"; + return `Error fetching smart money netflow: ${errorMessage}`; + } +} + +/** + * Get Smart Money Netflow action. + */ +export class GetSmartMoneyNetflowAction implements AgentkitAction { + public name = "get_smart_money_netflow"; + public description = GET_SMART_MONEY_NETFLOW_PROMPT; + public argsSchema = GetSmartMoneyNetflowInput; + public func = getSmartMoneyNetflow; + public smartAccountRequired = false; +} diff --git a/agentkit-core/src/actions/NansenAction/SmartMoney/index.ts b/agentkit-core/src/actions/NansenAction/SmartMoney/index.ts new file mode 100644 index 0000000..7957ecf --- /dev/null +++ b/agentkit-core/src/actions/NansenAction/SmartMoney/index.ts @@ -0,0 +1,4 @@ +export { GetSmartMoneyNetflowAction } from "./getSmartMoneyNetflowAction"; +export { GetSmartMoneyHoldingsAction } from "./getSmartMoneyHoldingsAction"; +export { GetSmartMoneyDexTradesAction } from "./getSmartMoneyDexTradesAction"; +export { GetSmartMoneyDcasAction } from "./getSmartMoneyDcasAction"; diff --git a/agentkit-core/src/actions/NansenAction/TokenGodMode/getDexTradesAction.ts b/agentkit-core/src/actions/NansenAction/TokenGodMode/getDexTradesAction.ts new file mode 100644 index 0000000..bc66c06 --- /dev/null +++ b/agentkit-core/src/actions/NansenAction/TokenGodMode/getDexTradesAction.ts @@ -0,0 +1,257 @@ +import { z } from "zod"; +import { AgentkitAction } from "../../../agentkit"; +import { ZeroXgaslessSmartAccount } from "@0xgasless/smart-account"; + +const GET_DEX_TRADES_PROMPT = ` +Retrieve DEX trading activity for a specific token across multiple blockchains. This endpoint provides detailed information about decentralized exchange trades including trader information, amounts, and transaction details. + +Key Features: +- DEX trading activity for a specific token +- Multi-chain support +- Trader information and labels +- Trade amounts and values +- Comprehensive DEX trading analysis + +This endpoint requires a Nansen API key to be configured. +`; + +/** + * Input schema for getting DEX trades data. + */ +export const GetDexTradesInput = z + .object({ + token_address: z.string().describe("The token address to get DEX trades for"), + + chains: z + .array( + z.enum([ + "all", + "arbitrum", + "avalanche", + "base", + "berachain", + "blast", + "bnb", + "ethereum", + "goat", + "hyperevm", + "iotaevm", + "linea", + "mantle", + "optimism", + "plasma", + "polygon", + "ronin", + "sei", + "scroll", + "sonic", + "unichain", + "zksync", + "solana", + ]) + ) + .describe("Chains to include in the analysis. Use 'all' to include all available chains."), + + filters: z + .object({ + transaction_hash: z.string().optional().describe("Transaction hash filter"), + trader_address: z.string().optional().describe("Trader address filter"), + trader_label: z.string().optional().describe("Trader label filter"), + trader_type: z.array(z.string()).optional().describe("Trader type filter"), + dex_name: z.string().optional().describe("DEX name filter"), + token_bought_amount: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Token bought amount range filter"), + token_sold_amount: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Token sold amount range filter"), + trade_value_usd: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Trade value range filter in USD"), + timestamp: z + .object({ + from: z.string().optional(), + to: z.string().optional(), + }) + .optional() + .describe("Timestamp range filter"), + }) + .optional() + .describe("Additional filters to apply"), + + pagination: z + .object({ + page: z.number().min(1).default(1).describe("Page number (1-based)"), + per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + }) + .optional() + .describe("Pagination parameters"), + + order_by: z + .array( + z.object({ + field: z + .enum([ + "chain", + "token_address", + "transaction_hash", + "trader_address", + "trader_label", + "trader_type", + "dex_name", + "token_bought_amount", + "token_sold_amount", + "trade_value_usd", + "timestamp", + ]) + .describe("Field to sort by"), + direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), + }) + ) + .optional() + .describe("Custom sort order to override the endpoint's default ordering"), + }) + .strip() + .describe("Instructions for getting DEX trades data"); + +/** + * Response interface for DEX trades data. + */ +interface DexTrade { + chain: string; + token_address: string; + transaction_hash: string; + trader_address: string; + trader_label: string; + trader_type: string; + dex_name: string; + token_bought_amount?: number; + token_sold_amount?: number; + trade_value_usd?: number; + timestamp: string; +} + +interface DexTradesResponse { + data: DexTrade[]; + pagination: { + page: number; + per_page: number; + is_last_page: boolean; + }; +} + +/** + * Fetches DEX trades data from Nansen API. + * + * @param _wallet - The smart account (not used for this action). + * @param args - The input arguments containing token address, chains, filters, pagination, and sorting options. + * @returns A formatted string containing the DEX trades data. + */ +export async function getDexTrades( + _wallet: ZeroXgaslessSmartAccount, + args: z.infer, +): Promise { + try { + const apiKey = process.env.NANSEN_API_KEY; + if (!apiKey) { + return "Error: NANSEN_API_KEY environment variable is required but not set."; + } + + const requestBody = { + token_address: args.token_address, + chains: args.chains, + ...(args.filters && { filters: args.filters }), + ...(args.pagination && { pagination: args.pagination }), + ...(args.order_by && { order_by: args.order_by }), + }; + + const response = await fetch("https://api.nansen.ai/api/v1/token-god-mode/dex-trades", { + method: "POST", + headers: { + "Content-Type": "application/json", + apiKey: apiKey, + "User-Agent": "0xGasless-AgentKit/1.0", + }, + body: JSON.stringify(requestBody), + }); + + if (!response.ok) { + if (response.status === 401) { + return "Error: Invalid Nansen API key. Please check your NANSEN_API_KEY environment variable."; + } + if (response.status === 403) { + return "Error: Insufficient subscription tier for this endpoint."; + } + if (response.status === 429) { + return "Error: Rate limit exceeded. Please wait before making another request."; + } + return `Error fetching DEX trades: ${response.status} ${response.statusText}`; + } + + const data: DexTradesResponse = await response.json(); + + if (!data.data || data.data.length === 0) { + return `No DEX trades found for token ${args.token_address}.`; + } + + let result = `🔄 DEX Trades for ${args.token_address}:\n\n`; + + data.data.forEach((trade, index) => { + const timestamp = new Date(trade.timestamp).toLocaleString(); + const typeEmoji = trade.trader_type === "exchange" ? "🏦" : + trade.trader_type === "defi" ? "🔄" : + trade.trader_type === "smart_money" ? "🧠" : + trade.trader_type === "whale" ? "🐋" : "👤"; + + result += `${index + 1}. DEX Trade ${typeEmoji}\n`; + result += ` • Trader: ${trade.trader_label || trade.trader_address}\n`; + result += ` • Type: ${trade.trader_type}\n`; + result += ` • DEX: ${trade.dex_name}\n`; + result += ` • Chain: ${trade.chain}\n`; + if (trade.token_bought_amount) { + result += ` • Bought: ${trade.token_bought_amount.toFixed(6)}\n`; + } + if (trade.token_sold_amount) { + result += ` • Sold: ${trade.token_sold_amount.toFixed(6)}\n`; + } + if (trade.trade_value_usd) { + result += ` • Value: $${trade.trade_value_usd.toLocaleString()}\n`; + } + result += ` • Time: ${timestamp}\n`; + result += ` • Tx Hash: ${trade.transaction_hash}\n`; + result += "\n"; + }); + + if (!data.pagination.is_last_page) { + result += `Page ${data.pagination.page} of results. Use pagination to get more results.\n`; + } + + return result; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : "An unknown error occurred"; + return `Error fetching DEX trades: ${errorMessage}`; + } +} + +/** + * Get DEX Trades action. + */ +export class GetDexTradesAction implements AgentkitAction { + public name = "get_dex_trades"; + public description = GET_DEX_TRADES_PROMPT; + public argsSchema = GetDexTradesInput; + public func = getDexTrades; + public smartAccountRequired = false; +} diff --git a/agentkit-core/src/actions/NansenAction/TokenGodMode/getFlowIntelligenceAction.ts b/agentkit-core/src/actions/NansenAction/TokenGodMode/getFlowIntelligenceAction.ts new file mode 100644 index 0000000..06cd0ee --- /dev/null +++ b/agentkit-core/src/actions/NansenAction/TokenGodMode/getFlowIntelligenceAction.ts @@ -0,0 +1,223 @@ +import { z } from "zod"; +import { AgentkitAction } from "../../../agentkit"; +import { ZeroXgaslessSmartAccount } from "@0xgasless/smart-account"; + +const GET_FLOW_INTELLIGENCE_PROMPT = ` +Retrieve flow intelligence data for a specific token across multiple blockchains. This endpoint provides insights into token flows, including inflows, outflows, and net flows from different entity types. + +Key Features: +- Flow intelligence data for a specific token +- Multi-chain support +- Inflows, outflows, and net flows +- Entity type analysis +- Comprehensive flow metrics + +This endpoint requires a Nansen API key to be configured. +`; + +/** + * Input schema for getting flow intelligence data. + */ +export const GetFlowIntelligenceInput = z + .object({ + token_address: z.string().describe("The token address to get flow intelligence for"), + + chains: z + .array( + z.enum([ + "all", + "arbitrum", + "avalanche", + "base", + "berachain", + "blast", + "bnb", + "ethereum", + "goat", + "hyperevm", + "iotaevm", + "linea", + "mantle", + "optimism", + "plasma", + "polygon", + "ronin", + "sei", + "scroll", + "sonic", + "unichain", + "zksync", + "solana", + ]) + ) + .describe("Chains to include in the analysis. Use 'all' to include all available chains."), + + filters: z + .object({ + entity_type: z.array(z.string()).optional().describe("Entity type filter"), + flow_type: z.array(z.string()).optional().describe("Flow type filter (inflow, outflow, net)"), + value_usd: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Value range filter in USD"), + timestamp: z + .object({ + from: z.string().optional(), + to: z.string().optional(), + }) + .optional() + .describe("Timestamp range filter"), + }) + .optional() + .describe("Additional filters to apply"), + + pagination: z + .object({ + page: z.number().min(1).default(1).describe("Page number (1-based)"), + per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + }) + .optional() + .describe("Pagination parameters"), + + order_by: z + .array( + z.object({ + field: z + .enum([ + "chain", + "token_address", + "entity_type", + "flow_type", + "value_usd", + "timestamp", + ]) + .describe("Field to sort by"), + direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), + }) + ) + .optional() + .describe("Custom sort order to override the endpoint's default ordering"), + }) + .strip() + .describe("Instructions for getting flow intelligence data"); + +/** + * Response interface for flow intelligence data. + */ +interface FlowIntelligence { + chain: string; + token_address: string; + entity_type: string; + flow_type: string; + value_usd?: number; + timestamp: string; +} + +interface FlowIntelligenceResponse { + data: FlowIntelligence[]; + pagination: { + page: number; + per_page: number; + is_last_page: boolean; + }; +} + +/** + * Fetches flow intelligence data from Nansen API. + * + * @param _wallet - The smart account (not used for this action). + * @param args - The input arguments containing token address, chains, filters, pagination, and sorting options. + * @returns A formatted string containing the flow intelligence data. + */ +export async function getFlowIntelligence( + _wallet: ZeroXgaslessSmartAccount, + args: z.infer, +): Promise { + try { + const apiKey = process.env.NANSEN_API_KEY; + if (!apiKey) { + return "Error: NANSEN_API_KEY environment variable is required but not set."; + } + + const requestBody = { + token_address: args.token_address, + chains: args.chains, + ...(args.filters && { filters: args.filters }), + ...(args.pagination && { pagination: args.pagination }), + ...(args.order_by && { order_by: args.order_by }), + }; + + const response = await fetch("https://api.nansen.ai/api/v1/token-god-mode/flow-intelligence", { + method: "POST", + headers: { + "Content-Type": "application/json", + apiKey: apiKey, + "User-Agent": "0xGasless-AgentKit/1.0", + }, + body: JSON.stringify(requestBody), + }); + + if (!response.ok) { + if (response.status === 401) { + return "Error: Invalid Nansen API key. Please check your NANSEN_API_KEY environment variable."; + } + if (response.status === 403) { + return "Error: Insufficient subscription tier for this endpoint."; + } + if (response.status === 429) { + return "Error: Rate limit exceeded. Please wait before making another request."; + } + return `Error fetching flow intelligence: ${response.status} ${response.statusText}`; + } + + const data: FlowIntelligenceResponse = await response.json(); + + if (!data.data || data.data.length === 0) { + return `No flow intelligence data found for token ${args.token_address}.`; + } + + let result = `🌊 Flow Intelligence for ${args.token_address}:\n\n`; + + data.data.forEach((flow, index) => { + const timestamp = new Date(flow.timestamp).toLocaleString(); + const flowEmoji = flow.flow_type === "inflow" ? "📈" : + flow.flow_type === "outflow" ? "📉" : "⚖️"; + const entityEmoji = flow.entity_type === "exchange" ? "🏦" : + flow.entity_type === "defi" ? "🔄" : + flow.entity_type === "smart_money" ? "🧠" : "👤"; + + result += `${index + 1}. Flow Data ${flowEmoji}\n`; + result += ` • Entity: ${entityEmoji} ${flow.entity_type}\n`; + result += ` • Flow Type: ${flow.flow_type}\n`; + result += ` • Chain: ${flow.chain}\n`; + if (flow.value_usd) { + result += ` • Value: $${flow.value_usd.toLocaleString()}\n`; + } + result += ` • Time: ${timestamp}\n`; + result += "\n"; + }); + + if (!data.pagination.is_last_page) { + result += `Page ${data.pagination.page} of results. Use pagination to get more results.\n`; + } + + return result; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : "An unknown error occurred"; + return `Error fetching flow intelligence: ${errorMessage}`; + } +} + +/** + * Get Flow Intelligence action. + */ +export class GetFlowIntelligenceAction implements AgentkitAction { + public name = "get_flow_intelligence"; + public description = GET_FLOW_INTELLIGENCE_PROMPT; + public argsSchema = GetFlowIntelligenceInput; + public func = getFlowIntelligence; + public smartAccountRequired = false; +} diff --git a/agentkit-core/src/actions/NansenAction/TokenGodMode/getFlowsAction.ts b/agentkit-core/src/actions/NansenAction/TokenGodMode/getFlowsAction.ts new file mode 100644 index 0000000..5e30cbe --- /dev/null +++ b/agentkit-core/src/actions/NansenAction/TokenGodMode/getFlowsAction.ts @@ -0,0 +1,245 @@ +import { z } from "zod"; +import { AgentkitAction } from "../../../agentkit"; +import { ZeroXgaslessSmartAccount } from "@0xgasless/smart-account"; + +const GET_FLOWS_PROMPT = ` +Retrieve flow data for a specific token across multiple blockchains. This endpoint provides detailed information about token flows including transfers, swaps, and other movements. + +Key Features: +- Flow data for a specific token +- Multi-chain support +- Transfer and swap information +- Flow direction and amounts +- Comprehensive flow analysis + +This endpoint requires a Nansen API key to be configured. +`; + +/** + * Input schema for getting flows data. + */ +export const GetFlowsInput = z + .object({ + token_address: z.string().describe("The token address to get flows for"), + + chains: z + .array( + z.enum([ + "all", + "arbitrum", + "avalanche", + "base", + "berachain", + "blast", + "bnb", + "ethereum", + "goat", + "hyperevm", + "iotaevm", + "linea", + "mantle", + "optimism", + "plasma", + "polygon", + "ronin", + "sei", + "scroll", + "sonic", + "unichain", + "zksync", + "solana", + ]) + ) + .describe("Chains to include in the analysis. Use 'all' to include all available chains."), + + filters: z + .object({ + transaction_hash: z.string().optional().describe("Transaction hash filter"), + flow_type: z.array(z.string()).optional().describe("Flow type filter"), + from_address: z.string().optional().describe("From address filter"), + to_address: z.string().optional().describe("To address filter"), + from_label: z.string().optional().describe("From label filter"), + to_label: z.string().optional().describe("To label filter"), + amount: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Amount range filter"), + value_usd: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Value range filter in USD"), + timestamp: z + .object({ + from: z.string().optional(), + to: z.string().optional(), + }) + .optional() + .describe("Timestamp range filter"), + }) + .optional() + .describe("Additional filters to apply"), + + pagination: z + .object({ + page: z.number().min(1).default(1).describe("Page number (1-based)"), + per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + }) + .optional() + .describe("Pagination parameters"), + + order_by: z + .array( + z.object({ + field: z + .enum([ + "chain", + "token_address", + "transaction_hash", + "flow_type", + "from_address", + "to_address", + "from_label", + "to_label", + "amount", + "value_usd", + "timestamp", + ]) + .describe("Field to sort by"), + direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), + }) + ) + .optional() + .describe("Custom sort order to override the endpoint's default ordering"), + }) + .strip() + .describe("Instructions for getting flows data"); + +/** + * Response interface for flows data. + */ +interface Flow { + chain: string; + token_address: string; + transaction_hash: string; + flow_type: string; + from_address: string; + to_address: string; + from_label: string; + to_label: string; + amount: number; + value_usd?: number; + timestamp: string; +} + +interface FlowsResponse { + data: Flow[]; + pagination: { + page: number; + per_page: number; + is_last_page: boolean; + }; +} + +/** + * Fetches flows data from Nansen API. + * + * @param _wallet - The smart account (not used for this action). + * @param args - The input arguments containing token address, chains, filters, pagination, and sorting options. + * @returns A formatted string containing the flows data. + */ +export async function getFlows( + _wallet: ZeroXgaslessSmartAccount, + args: z.infer, +): Promise { + try { + const apiKey = process.env.NANSEN_API_KEY; + if (!apiKey) { + return "Error: NANSEN_API_KEY environment variable is required but not set."; + } + + const requestBody = { + token_address: args.token_address, + chains: args.chains, + ...(args.filters && { filters: args.filters }), + ...(args.pagination && { pagination: args.pagination }), + ...(args.order_by && { order_by: args.order_by }), + }; + + const response = await fetch("https://api.nansen.ai/api/v1/token-god-mode/flows", { + method: "POST", + headers: { + "Content-Type": "application/json", + apiKey: apiKey, + "User-Agent": "0xGasless-AgentKit/1.0", + }, + body: JSON.stringify(requestBody), + }); + + if (!response.ok) { + if (response.status === 401) { + return "Error: Invalid Nansen API key. Please check your NANSEN_API_KEY environment variable."; + } + if (response.status === 403) { + return "Error: Insufficient subscription tier for this endpoint."; + } + if (response.status === 429) { + return "Error: Rate limit exceeded. Please wait before making another request."; + } + return `Error fetching flows: ${response.status} ${response.statusText}`; + } + + const data: FlowsResponse = await response.json(); + + if (!data.data || data.data.length === 0) { + return `No flows found for token ${args.token_address}.`; + } + + let result = `🌊 Flows for ${args.token_address}:\n\n`; + + data.data.forEach((flow, index) => { + const timestamp = new Date(flow.timestamp).toLocaleString(); + const flowEmoji = flow.flow_type === "transfer" ? "📤" : + flow.flow_type === "swap" ? "🔄" : + flow.flow_type === "mint" ? "🪙" : "📄"; + + result += `${index + 1}. Flow ${flowEmoji}\n`; + result += ` • Type: ${flow.flow_type}\n`; + result += ` • Chain: ${flow.chain}\n`; + result += ` • From: ${flow.from_label || flow.from_address}\n`; + result += ` • To: ${flow.to_label || flow.to_address}\n`; + result += ` • Amount: ${flow.amount.toFixed(6)}\n`; + if (flow.value_usd) { + result += ` • Value: $${flow.value_usd.toLocaleString()}\n`; + } + result += ` • Time: ${timestamp}\n`; + result += ` • Tx Hash: ${flow.transaction_hash}\n`; + result += "\n"; + }); + + if (!data.pagination.is_last_page) { + result += `Page ${data.pagination.page} of results. Use pagination to get more results.\n`; + } + + return result; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : "An unknown error occurred"; + return `Error fetching flows: ${errorMessage}`; + } +} + +/** + * Get Flows action. + */ +export class GetFlowsAction implements AgentkitAction { + public name = "get_flows"; + public description = GET_FLOWS_PROMPT; + public argsSchema = GetFlowsInput; + public func = getFlows; + public smartAccountRequired = false; +} diff --git a/agentkit-core/src/actions/NansenAction/TokenGodMode/getHoldersAction.ts b/agentkit-core/src/actions/NansenAction/TokenGodMode/getHoldersAction.ts new file mode 100644 index 0000000..1a9753a --- /dev/null +++ b/agentkit-core/src/actions/NansenAction/TokenGodMode/getHoldersAction.ts @@ -0,0 +1,236 @@ +import { z } from "zod"; +import { AgentkitAction } from "../../../agentkit"; +import { ZeroXgaslessSmartAccount } from "@0xgasless/smart-account"; + +const GET_HOLDERS_PROMPT = ` +Retrieve holder information for a specific token across multiple blockchains. This endpoint provides detailed information about token holders including their balances, labels, and activity. + +Key Features: +- Holder information for a specific token +- Multi-chain support +- Holder balances and labels +- Activity and transaction data +- Comprehensive holder analysis + +This endpoint requires a Nansen API key to be configured. +`; + +/** + * Input schema for getting holders data. + */ +export const GetHoldersInput = z + .object({ + token_address: z.string().describe("The token address to get holders for"), + + chains: z + .array( + z.enum([ + "all", + "arbitrum", + "avalanche", + "base", + "berachain", + "blast", + "bnb", + "ethereum", + "goat", + "hyperevm", + "iotaevm", + "linea", + "mantle", + "optimism", + "plasma", + "polygon", + "ronin", + "sei", + "scroll", + "sonic", + "unichain", + "zksync", + "solana", + ]) + ) + .describe("Chains to include in the analysis. Use 'all' to include all available chains."), + + filters: z + .object({ + holder_address: z.string().optional().describe("Holder address filter"), + holder_label: z.string().optional().describe("Holder label filter"), + holder_type: z.array(z.string()).optional().describe("Holder type filter"), + balance: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Balance range filter"), + value_usd: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Value range filter in USD"), + timestamp: z + .object({ + from: z.string().optional(), + to: z.string().optional(), + }) + .optional() + .describe("Timestamp range filter"), + }) + .optional() + .describe("Additional filters to apply"), + + pagination: z + .object({ + page: z.number().min(1).default(1).describe("Page number (1-based)"), + per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + }) + .optional() + .describe("Pagination parameters"), + + order_by: z + .array( + z.object({ + field: z + .enum([ + "chain", + "token_address", + "holder_address", + "holder_label", + "holder_type", + "balance", + "value_usd", + "timestamp", + ]) + .describe("Field to sort by"), + direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), + }) + ) + .optional() + .describe("Custom sort order to override the endpoint's default ordering"), + }) + .strip() + .describe("Instructions for getting holders data"); + +/** + * Response interface for holders data. + */ +interface Holder { + chain: string; + token_address: string; + holder_address: string; + holder_label: string; + holder_type: string; + balance: number; + value_usd?: number; + timestamp: string; +} + +interface HoldersResponse { + data: Holder[]; + pagination: { + page: number; + per_page: number; + is_last_page: boolean; + }; +} + +/** + * Fetches holders data from Nansen API. + * + * @param _wallet - The smart account (not used for this action). + * @param args - The input arguments containing token address, chains, filters, pagination, and sorting options. + * @returns A formatted string containing the holders data. + */ +export async function getHolders( + _wallet: ZeroXgaslessSmartAccount, + args: z.infer, +): Promise { + try { + const apiKey = process.env.NANSEN_API_KEY; + if (!apiKey) { + return "Error: NANSEN_API_KEY environment variable is required but not set."; + } + + const requestBody = { + token_address: args.token_address, + chains: args.chains, + ...(args.filters && { filters: args.filters }), + ...(args.pagination && { pagination: args.pagination }), + ...(args.order_by && { order_by: args.order_by }), + }; + + const response = await fetch("https://api.nansen.ai/api/v1/token-god-mode/holders", { + method: "POST", + headers: { + "Content-Type": "application/json", + apiKey: apiKey, + "User-Agent": "0xGasless-AgentKit/1.0", + }, + body: JSON.stringify(requestBody), + }); + + if (!response.ok) { + if (response.status === 401) { + return "Error: Invalid Nansen API key. Please check your NANSEN_API_KEY environment variable."; + } + if (response.status === 403) { + return "Error: Insufficient subscription tier for this endpoint."; + } + if (response.status === 429) { + return "Error: Rate limit exceeded. Please wait before making another request."; + } + return `Error fetching holders: ${response.status} ${response.statusText}`; + } + + const data: HoldersResponse = await response.json(); + + if (!data.data || data.data.length === 0) { + return `No holders found for token ${args.token_address}.`; + } + + let result = `👥 Holders for ${args.token_address}:\n\n`; + + data.data.forEach((holder, index) => { + const timestamp = new Date(holder.timestamp).toLocaleString(); + const typeEmoji = holder.holder_type === "exchange" ? "🏦" : + holder.holder_type === "defi" ? "🔄" : + holder.holder_type === "smart_money" ? "🧠" : + holder.holder_type === "whale" ? "🐋" : "👤"; + + result += `${index + 1}. Holder ${typeEmoji}\n`; + result += ` • Address: ${holder.holder_address}\n`; + result += ` • Label: ${holder.holder_label}\n`; + result += ` • Type: ${holder.holder_type}\n`; + result += ` • Chain: ${holder.chain}\n`; + result += ` • Balance: ${holder.balance.toFixed(6)}\n`; + if (holder.value_usd) { + result += ` • Value: $${holder.value_usd.toLocaleString()}\n`; + } + result += ` • Last Activity: ${timestamp}\n`; + result += "\n"; + }); + + if (!data.pagination.is_last_page) { + result += `Page ${data.pagination.page} of results. Use pagination to get more results.\n`; + } + + return result; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : "An unknown error occurred"; + return `Error fetching holders: ${errorMessage}`; + } +} + +/** + * Get Holders action. + */ +export class GetHoldersAction implements AgentkitAction { + public name = "get_holders"; + public description = GET_HOLDERS_PROMPT; + public argsSchema = GetHoldersInput; + public func = getHolders; + public smartAccountRequired = false; +} diff --git a/agentkit-core/src/actions/NansenAction/TokenGodMode/getJupiterDcasAction.ts b/agentkit-core/src/actions/NansenAction/TokenGodMode/getJupiterDcasAction.ts new file mode 100644 index 0000000..657f754 --- /dev/null +++ b/agentkit-core/src/actions/NansenAction/TokenGodMode/getJupiterDcasAction.ts @@ -0,0 +1,243 @@ +import { z } from "zod"; +import { AgentkitAction } from "../../../agentkit"; +import { ZeroXgaslessSmartAccount } from "@0xgasless/smart-account"; + +const GET_JUPITER_DCAS_PROMPT = ` +Retrieve Jupiter DCA (Dollar Cost Averaging) orders for a specific token on Solana. This endpoint provides detailed information about DCA strategies including order details, amounts, and execution status. + +Key Features: +- Jupiter DCA orders for a specific token on Solana +- DCA strategy information +- Order details and execution status +- Amount and timing information +- Comprehensive DCA analysis + +This endpoint requires a Nansen API key to be configured. +`; + +/** + * Input schema for getting Jupiter DCAs data. + */ +export const GetJupiterDcasInput = z + .object({ + token_address: z.string().describe("The token address to get Jupiter DCA orders for"), + + filters: z + .object({ + dca_vault_address: z.string().optional().describe("DCA vault address filter"), + trader_address: z.string().optional().describe("Trader address filter"), + trader_label: z.string().optional().describe("Trader label filter"), + trader_type: z.array(z.string()).optional().describe("Trader type filter"), + dca_status: z.array(z.string()).optional().describe("DCA status filter"), + input_token_symbol: z.string().optional().describe("Input token symbol filter"), + output_token_symbol: z.string().optional().describe("Output token symbol filter"), + deposit_token_amount: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Deposit token amount range filter"), + token_spent_amount: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Token spent amount range filter"), + output_token_redeemed_amount: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Output token redeemed amount range filter"), + deposit_value_usd: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Deposit value range filter in USD"), + dca_created_at: z + .object({ + from: z.string().optional(), + to: z.string().optional(), + }) + .optional() + .describe("DCA creation date range filter"), + }) + .optional() + .describe("Additional filters to apply"), + + pagination: z + .object({ + page: z.number().min(1).default(1).describe("Page number (1-based)"), + per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + }) + .optional() + .describe("Pagination parameters"), + + order_by: z + .array( + z.object({ + field: z + .enum([ + "token_address", + "dca_vault_address", + "trader_address", + "trader_label", + "trader_type", + "dca_status", + "input_token_symbol", + "output_token_symbol", + "deposit_token_amount", + "token_spent_amount", + "output_token_redeemed_amount", + "deposit_value_usd", + "dca_created_at", + ]) + .describe("Field to sort by"), + direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), + }) + ) + .optional() + .describe("Custom sort order to override the endpoint's default ordering"), + }) + .strip() + .describe("Instructions for getting Jupiter DCAs data"); + +/** + * Response interface for Jupiter DCAs data. + */ +interface JupiterDca { + token_address: string; + dca_vault_address: string; + trader_address: string; + trader_label: string; + trader_type: string; + dca_status: string; + input_token_symbol: string; + output_token_symbol: string; + deposit_token_amount?: number; + token_spent_amount?: number; + output_token_redeemed_amount?: number; + deposit_value_usd?: number; + dca_created_at: string; +} + +interface JupiterDcasResponse { + data: JupiterDca[]; + pagination: { + page: number; + per_page: number; + is_last_page: boolean; + }; +} + +/** + * Fetches Jupiter DCAs data from Nansen API. + * + * @param _wallet - The smart account (not used for this action). + * @param args - The input arguments containing token address, filters, pagination, and sorting options. + * @returns A formatted string containing the Jupiter DCAs data. + */ +export async function getJupiterDcas( + _wallet: ZeroXgaslessSmartAccount, + args: z.infer, +): Promise { + try { + const apiKey = process.env.NANSEN_API_KEY; + if (!apiKey) { + return "Error: NANSEN_API_KEY environment variable is required but not set."; + } + + const requestBody = { + token_address: args.token_address, + ...(args.filters && { filters: args.filters }), + ...(args.pagination && { pagination: args.pagination }), + ...(args.order_by && { order_by: args.order_by }), + }; + + const response = await fetch("https://api.nansen.ai/api/v1/token-god-mode/jupiter-dcas", { + method: "POST", + headers: { + "Content-Type": "application/json", + apiKey: apiKey, + "User-Agent": "0xGasless-AgentKit/1.0", + }, + body: JSON.stringify(requestBody), + }); + + if (!response.ok) { + if (response.status === 401) { + return "Error: Invalid Nansen API key. Please check your NANSEN_API_KEY environment variable."; + } + if (response.status === 403) { + return "Error: Insufficient subscription tier for this endpoint."; + } + if (response.status === 429) { + return "Error: Rate limit exceeded. Please wait before making another request."; + } + return `Error fetching Jupiter DCAs: ${response.status} ${response.statusText}`; + } + + const data: JupiterDcasResponse = await response.json(); + + if (!data.data || data.data.length === 0) { + return `No Jupiter DCA orders found for token ${args.token_address}.`; + } + + let result = `📈 Jupiter DCA Orders for ${args.token_address}:\n\n`; + + data.data.forEach((dca, index) => { + const createdDate = new Date(dca.dca_created_at).toLocaleString(); + const statusEmoji = dca.dca_status === "active" ? "🟢" : "🔴"; + const typeEmoji = dca.trader_type === "exchange" ? "🏦" : + dca.trader_type === "defi" ? "🔄" : + dca.trader_type === "smart_money" ? "🧠" : + dca.trader_type === "whale" ? "🐋" : "👤"; + + result += `${index + 1}. DCA Order ${statusEmoji}\n`; + result += ` • Trader: ${typeEmoji} ${dca.trader_label || dca.trader_address}\n`; + result += ` • Type: ${dca.trader_type}\n`; + result += ` • Status: ${dca.dca_status}\n`; + result += ` • Strategy: ${dca.input_token_symbol} → ${dca.output_token_symbol}\n`; + if (dca.deposit_token_amount) { + result += ` • Deposit Amount: ${dca.deposit_token_amount.toFixed(4)} ${dca.input_token_symbol}\n`; + } + if (dca.token_spent_amount) { + result += ` • Tokens Spent: ${dca.token_spent_amount.toFixed(4)} ${dca.input_token_symbol}\n`; + } + if (dca.output_token_redeemed_amount) { + result += ` • Tokens Redeemed: ${dca.output_token_redeemed_amount.toFixed(4)} ${dca.output_token_symbol}\n`; + } + if (dca.deposit_value_usd) { + result += ` • Deposit Value: $${dca.deposit_value_usd.toLocaleString()}\n`; + } + result += ` • Created: ${createdDate}\n`; + result += ` • DCA Vault: ${dca.dca_vault_address}\n`; + result += "\n"; + }); + + if (!data.pagination.is_last_page) { + result += `Page ${data.pagination.page} of results. Use pagination to get more results.\n`; + } + + return result; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : "An unknown error occurred"; + return `Error fetching Jupiter DCAs: ${errorMessage}`; + } +} + +/** + * Get Jupiter DCAs action. + */ +export class GetJupiterDcasAction implements AgentkitAction { + public name = "get_jupiter_dcas"; + public description = GET_JUPITER_DCAS_PROMPT; + public argsSchema = GetJupiterDcasInput; + public func = getJupiterDcas; + public smartAccountRequired = false; +} diff --git a/agentkit-core/src/actions/NansenAction/TokenGodMode/getPnlLeaderboardAction.ts b/agentkit-core/src/actions/NansenAction/TokenGodMode/getPnlLeaderboardAction.ts new file mode 100644 index 0000000..f1b0927 --- /dev/null +++ b/agentkit-core/src/actions/NansenAction/TokenGodMode/getPnlLeaderboardAction.ts @@ -0,0 +1,249 @@ +import { z } from "zod"; +import { AgentkitAction } from "../../../agentkit"; +import { ZeroXgaslessSmartAccount } from "@0xgasless/smart-account"; + +const GET_PNL_LEADERBOARD_PROMPT = ` +Retrieve PnL leaderboard data for a specific token across multiple blockchains. This endpoint provides information about the top performers in terms of profit and loss for the token, including their trading performance and metrics. + +Key Features: +- PnL leaderboard data for a specific token +- Multi-chain support +- Top performers by profit/loss +- Trading performance metrics +- Comprehensive leaderboard analysis + +This endpoint requires a Nansen API key to be configured. +`; + +/** + * Input schema for getting PnL leaderboard data. + */ +export const GetPnlLeaderboardInput = z + .object({ + token_address: z.string().describe("The token address to get PnL leaderboard for"), + + chains: z + .array( + z.enum([ + "all", + "arbitrum", + "avalanche", + "base", + "berachain", + "blast", + "bnb", + "ethereum", + "goat", + "hyperevm", + "iotaevm", + "linea", + "mantle", + "optimism", + "plasma", + "polygon", + "ronin", + "sei", + "scroll", + "sonic", + "unichain", + "zksync", + "solana", + ]) + ) + .describe("Chains to include in the analysis. Use 'all' to include all available chains."), + + filters: z + .object({ + trader_address: z.string().optional().describe("Trader address filter"), + trader_label: z.string().optional().describe("Trader label filter"), + trader_type: z.array(z.string()).optional().describe("Trader type filter"), + pnl_usd: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("PnL range filter in USD"), + pnl_percent: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("PnL percentage range filter"), + win_rate: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Win rate range filter (0-1)"), + timestamp: z + .object({ + from: z.string().optional(), + to: z.string().optional(), + }) + .optional() + .describe("Timestamp range filter"), + }) + .optional() + .describe("Additional filters to apply"), + + pagination: z + .object({ + page: z.number().min(1).default(1).describe("Page number (1-based)"), + per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + }) + .optional() + .describe("Pagination parameters"), + + order_by: z + .array( + z.object({ + field: z + .enum([ + "chain", + "token_address", + "trader_address", + "trader_label", + "trader_type", + "pnl_usd", + "pnl_percent", + "win_rate", + "timestamp", + ]) + .describe("Field to sort by"), + direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), + }) + ) + .optional() + .describe("Custom sort order to override the endpoint's default ordering"), + }) + .strip() + .describe("Instructions for getting PnL leaderboard data"); + +/** + * Response interface for PnL leaderboard data. + */ +interface PnlLeaderboard { + chain: string; + token_address: string; + trader_address: string; + trader_label: string; + trader_type: string; + pnl_usd?: number; + pnl_percent?: number; + win_rate: number; + timestamp: string; +} + +interface PnlLeaderboardResponse { + data: PnlLeaderboard[]; + pagination: { + page: number; + per_page: number; + is_last_page: boolean; + }; +} + +/** + * Fetches PnL leaderboard data from Nansen API. + * + * @param _wallet - The smart account (not used for this action). + * @param args - The input arguments containing token address, chains, filters, pagination, and sorting options. + * @returns A formatted string containing the PnL leaderboard data. + */ +export async function getPnlLeaderboard( + _wallet: ZeroXgaslessSmartAccount, + args: z.infer, +): Promise { + try { + const apiKey = process.env.NANSEN_API_KEY; + if (!apiKey) { + return "Error: NANSEN_API_KEY environment variable is required but not set."; + } + + const requestBody = { + token_address: args.token_address, + chains: args.chains, + ...(args.filters && { filters: args.filters }), + ...(args.pagination && { pagination: args.pagination }), + ...(args.order_by && { order_by: args.order_by }), + }; + + const response = await fetch("https://api.nansen.ai/api/v1/token-god-mode/pnl-leaderboard", { + method: "POST", + headers: { + "Content-Type": "application/json", + apiKey: apiKey, + "User-Agent": "0xGasless-AgentKit/1.0", + }, + body: JSON.stringify(requestBody), + }); + + if (!response.ok) { + if (response.status === 401) { + return "Error: Invalid Nansen API key. Please check your NANSEN_API_KEY environment variable."; + } + if (response.status === 403) { + return "Error: Insufficient subscription tier for this endpoint."; + } + if (response.status === 429) { + return "Error: Rate limit exceeded. Please wait before making another request."; + } + return `Error fetching PnL leaderboard: ${response.status} ${response.statusText}`; + } + + const data: PnlLeaderboardResponse = await response.json(); + + if (!data.data || data.data.length === 0) { + return `No PnL leaderboard data found for token ${args.token_address}.`; + } + + let result = `🏆 PnL Leaderboard for ${args.token_address}:\n\n`; + + data.data.forEach((trader, index) => { + const timestamp = new Date(trader.timestamp).toLocaleString(); + const rankEmoji = index === 0 ? "🥇" : index === 1 ? "🥈" : index === 2 ? "🥉" : "🏅"; + const pnlEmoji = trader.pnl_usd && trader.pnl_usd >= 0 ? "📈" : "📉"; + const typeEmoji = trader.trader_type === "exchange" ? "🏦" : + trader.trader_type === "defi" ? "🔄" : + trader.trader_type === "smart_money" ? "🧠" : + trader.trader_type === "whale" ? "🐋" : "👤"; + + result += `${index + 1}. ${rankEmoji} Trader ${pnlEmoji}\n`; + result += ` • Trader: ${typeEmoji} ${trader.trader_label || trader.trader_address}\n`; + result += ` • Type: ${trader.trader_type}\n`; + result += ` • Chain: ${trader.chain}\n`; + if (trader.pnl_usd !== undefined) { + result += ` • PnL: $${trader.pnl_usd.toLocaleString()}\n`; + } + if (trader.pnl_percent !== undefined) { + result += ` • PnL %: ${trader.pnl_percent.toFixed(2)}%\n`; + } + result += ` • Win Rate: ${(trader.win_rate * 100).toFixed(1)}%\n`; + result += ` • Last Updated: ${timestamp}\n`; + result += "\n"; + }); + + if (!data.pagination.is_last_page) { + result += `Page ${data.pagination.page} of results. Use pagination to get more results.\n`; + } + + return result; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : "An unknown error occurred"; + return `Error fetching PnL leaderboard: ${errorMessage}`; + } +} + +/** + * Get PnL Leaderboard action. + */ +export class GetPnlLeaderboardAction implements AgentkitAction { + public name = "get_pnl_leaderboard"; + public description = GET_PNL_LEADERBOARD_PROMPT; + public argsSchema = GetPnlLeaderboardInput; + public func = getPnlLeaderboard; + public smartAccountRequired = false; +} diff --git a/agentkit-core/src/actions/NansenAction/TokenGodMode/getTokenScreenerAction.ts b/agentkit-core/src/actions/NansenAction/TokenGodMode/getTokenScreenerAction.ts new file mode 100644 index 0000000..0698e6f --- /dev/null +++ b/agentkit-core/src/actions/NansenAction/TokenGodMode/getTokenScreenerAction.ts @@ -0,0 +1,255 @@ +import { z } from "zod"; +import { AgentkitAction } from "../../../agentkit"; +import { ZeroXgaslessSmartAccount } from "@0xgasless/smart-account"; + +const GET_TOKEN_SCREENER_PROMPT = ` +Retrieve comprehensive token information and analytics for a specific token across multiple blockchains. This endpoint provides detailed token data including market metrics, holder information, and trading activity. + +Key Features: +- Comprehensive token information and analytics +- Multi-chain support +- Market metrics and holder information +- Trading activity and volume data +- Detailed token metadata + +This endpoint requires a Nansen API key to be configured. +`; + +/** + * Input schema for getting token screener data. + */ +export const GetTokenScreenerInput = z + .object({ + token_address: z.string().describe("The token address to get screener data for"), + + chains: z + .array( + z.enum([ + "all", + "arbitrum", + "avalanche", + "base", + "berachain", + "blast", + "bnb", + "ethereum", + "goat", + "hyperevm", + "iotaevm", + "linea", + "mantle", + "optimism", + "plasma", + "polygon", + "ronin", + "sei", + "scroll", + "sonic", + "unichain", + "zksync", + "solana", + ]) + ) + .describe("Chains to include in the analysis. Use 'all' to include all available chains."), + + filters: z + .object({ + token_symbol: z.string().optional().describe("Token symbol filter"), + token_sectors: z.array(z.string()).optional().describe("Token sectors filter"), + market_cap_usd: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Market cap range filter in USD"), + volume_24h_usd: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("24h volume range filter in USD"), + holders_count: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Holders count range filter"), + token_age_days: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Token age range filter in days"), + timestamp: z + .object({ + from: z.string().optional(), + to: z.string().optional(), + }) + .optional() + .describe("Timestamp range filter"), + }) + .optional() + .describe("Additional filters to apply"), + + pagination: z + .object({ + page: z.number().min(1).default(1).describe("Page number (1-based)"), + per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + }) + .optional() + .describe("Pagination parameters"), + + order_by: z + .array( + z.object({ + field: z + .enum([ + "chain", + "token_address", + "token_symbol", + "token_sectors", + "market_cap_usd", + "volume_24h_usd", + "holders_count", + "token_age_days", + "timestamp", + ]) + .describe("Field to sort by"), + direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), + }) + ) + .optional() + .describe("Custom sort order to override the endpoint's default ordering"), + }) + .strip() + .describe("Instructions for getting token screener data"); + +/** + * Response interface for token screener data. + */ +interface TokenScreener { + chain: string; + token_address: string; + token_symbol: string; + token_sectors: string[]; + market_cap_usd?: number; + volume_24h_usd?: number; + holders_count: number; + token_age_days: number; + timestamp: string; +} + +interface TokenScreenerResponse { + data: TokenScreener[]; + pagination: { + page: number; + per_page: number; + is_last_page: boolean; + }; +} + +/** + * Fetches token screener data from Nansen API. + * + * @param _wallet - The smart account (not used for this action). + * @param args - The input arguments containing token address, chains, filters, pagination, and sorting options. + * @returns A formatted string containing the token screener data. + */ +export async function getTokenScreener( + _wallet: ZeroXgaslessSmartAccount, + args: z.infer, +): Promise { + try { + const apiKey = process.env.NANSEN_API_KEY; + if (!apiKey) { + return "Error: NANSEN_API_KEY environment variable is required but not set."; + } + + const requestBody = { + token_address: args.token_address, + chains: args.chains, + ...(args.filters && { filters: args.filters }), + ...(args.pagination && { pagination: args.pagination }), + ...(args.order_by && { order_by: args.order_by }), + }; + + const response = await fetch("https://api.nansen.ai/api/v1/token-god-mode/token-screener", { + method: "POST", + headers: { + "Content-Type": "application/json", + apiKey: apiKey, + "User-Agent": "0xGasless-AgentKit/1.0", + }, + body: JSON.stringify(requestBody), + }); + + if (!response.ok) { + if (response.status === 401) { + return "Error: Invalid Nansen API key. Please check your NANSEN_API_KEY environment variable."; + } + if (response.status === 403) { + return "Error: Insufficient subscription tier for this endpoint."; + } + if (response.status === 429) { + return "Error: Rate limit exceeded. Please wait before making another request."; + } + return `Error fetching token screener: ${response.status} ${response.statusText}`; + } + + const data: TokenScreenerResponse = await response.json(); + + if (!data.data || data.data.length === 0) { + return `No token screener data found for token ${args.token_address}.`; + } + + let result = `🔍 Token Screener for ${args.token_address}:\n\n`; + + data.data.forEach((token, index) => { + const timestamp = new Date(token.timestamp).toLocaleString(); + const marketCapEmoji = token.market_cap_usd && token.market_cap_usd > 1000000000 ? "🚀" : + token.market_cap_usd && token.market_cap_usd > 100000000 ? "📈" : "📊"; + + result += `${index + 1}. Token Data ${marketCapEmoji}\n`; + result += ` • Symbol: ${token.token_symbol}\n`; + result += ` • Chain: ${token.chain}\n`; + result += ` • Address: ${token.token_address}\n`; + if (token.market_cap_usd) { + result += ` • Market Cap: $${token.market_cap_usd.toLocaleString()}\n`; + } + if (token.volume_24h_usd) { + result += ` • 24h Volume: $${token.volume_24h_usd.toLocaleString()}\n`; + } + result += ` • Holders: ${token.holders_count.toLocaleString()}\n`; + result += ` • Age: ${token.token_age_days} days\n`; + if (token.token_sectors && token.token_sectors.length > 0) { + result += ` • Sectors: ${token.token_sectors.join(", ")}\n`; + } + result += ` • Updated: ${timestamp}\n`; + result += "\n"; + }); + + if (!data.pagination.is_last_page) { + result += `Page ${data.pagination.page} of results. Use pagination to get more results.\n`; + } + + return result; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : "An unknown error occurred"; + return `Error fetching token screener: ${errorMessage}`; + } +} + +/** + * Get Token Screener action. + */ +export class GetTokenScreenerAction implements AgentkitAction { + public name = "get_token_screener"; + public description = GET_TOKEN_SCREENER_PROMPT; + public argsSchema = GetTokenScreenerInput; + public func = getTokenScreener; + public smartAccountRequired = false; +} diff --git a/agentkit-core/src/actions/NansenAction/TokenGodMode/getTransfersAction.ts b/agentkit-core/src/actions/NansenAction/TokenGodMode/getTransfersAction.ts new file mode 100644 index 0000000..2ade22f --- /dev/null +++ b/agentkit-core/src/actions/NansenAction/TokenGodMode/getTransfersAction.ts @@ -0,0 +1,252 @@ +import { z } from "zod"; +import { AgentkitAction } from "../../../agentkit"; +import { ZeroXgaslessSmartAccount } from "@0xgasless/smart-account"; + +const GET_TRANSFERS_PROMPT = ` +Retrieve transfer activity for a specific token across multiple blockchains. This endpoint provides detailed information about token transfers including sender/receiver information, amounts, and transaction details. + +Key Features: +- Transfer activity for a specific token +- Multi-chain support +- Sender and receiver information +- Transfer amounts and values +- Comprehensive transfer analysis + +This endpoint requires a Nansen API key to be configured. +`; + +/** + * Input schema for getting transfers data. + */ +export const GetTransfersInput = z + .object({ + token_address: z.string().describe("The token address to get transfers for"), + + chains: z + .array( + z.enum([ + "all", + "arbitrum", + "avalanche", + "base", + "berachain", + "blast", + "bnb", + "ethereum", + "goat", + "hyperevm", + "iotaevm", + "linea", + "mantle", + "optimism", + "plasma", + "polygon", + "ronin", + "sei", + "scroll", + "sonic", + "unichain", + "zksync", + "solana", + ]) + ) + .describe("Chains to include in the analysis. Use 'all' to include all available chains."), + + filters: z + .object({ + transaction_hash: z.string().optional().describe("Transaction hash filter"), + from_address: z.string().optional().describe("From address filter"), + to_address: z.string().optional().describe("To address filter"), + from_label: z.string().optional().describe("From label filter"), + to_label: z.string().optional().describe("To label filter"), + from_type: z.array(z.string()).optional().describe("From type filter"), + to_type: z.array(z.string()).optional().describe("To type filter"), + amount: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Amount range filter"), + value_usd: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Value range filter in USD"), + timestamp: z + .object({ + from: z.string().optional(), + to: z.string().optional(), + }) + .optional() + .describe("Timestamp range filter"), + }) + .optional() + .describe("Additional filters to apply"), + + pagination: z + .object({ + page: z.number().min(1).default(1).describe("Page number (1-based)"), + per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + }) + .optional() + .describe("Pagination parameters"), + + order_by: z + .array( + z.object({ + field: z + .enum([ + "chain", + "token_address", + "transaction_hash", + "from_address", + "to_address", + "from_label", + "to_label", + "from_type", + "to_type", + "amount", + "value_usd", + "timestamp", + ]) + .describe("Field to sort by"), + direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), + }) + ) + .optional() + .describe("Custom sort order to override the endpoint's default ordering"), + }) + .strip() + .describe("Instructions for getting transfers data"); + +/** + * Response interface for transfers data. + */ +interface Transfer { + chain: string; + token_address: string; + transaction_hash: string; + from_address: string; + to_address: string; + from_label: string; + to_label: string; + from_type: string; + to_type: string; + amount: number; + value_usd?: number; + timestamp: string; +} + +interface TransfersResponse { + data: Transfer[]; + pagination: { + page: number; + per_page: number; + is_last_page: boolean; + }; +} + +/** + * Fetches transfers data from Nansen API. + * + * @param _wallet - The smart account (not used for this action). + * @param args - The input arguments containing token address, chains, filters, pagination, and sorting options. + * @returns A formatted string containing the transfers data. + */ +export async function getTransfers( + _wallet: ZeroXgaslessSmartAccount, + args: z.infer, +): Promise { + try { + const apiKey = process.env.NANSEN_API_KEY; + if (!apiKey) { + return "Error: NANSEN_API_KEY environment variable is required but not set."; + } + + const requestBody = { + token_address: args.token_address, + chains: args.chains, + ...(args.filters && { filters: args.filters }), + ...(args.pagination && { pagination: args.pagination }), + ...(args.order_by && { order_by: args.order_by }), + }; + + const response = await fetch("https://api.nansen.ai/api/v1/token-god-mode/transfers", { + method: "POST", + headers: { + "Content-Type": "application/json", + apiKey: apiKey, + "User-Agent": "0xGasless-AgentKit/1.0", + }, + body: JSON.stringify(requestBody), + }); + + if (!response.ok) { + if (response.status === 401) { + return "Error: Invalid Nansen API key. Please check your NANSEN_API_KEY environment variable."; + } + if (response.status === 403) { + return "Error: Insufficient subscription tier for this endpoint."; + } + if (response.status === 429) { + return "Error: Rate limit exceeded. Please wait before making another request."; + } + return `Error fetching transfers: ${response.status} ${response.statusText}`; + } + + const data: TransfersResponse = await response.json(); + + if (!data.data || data.data.length === 0) { + return `No transfers found for token ${args.token_address}.`; + } + + let result = `📤 Transfers for ${args.token_address}:\n\n`; + + data.data.forEach((transfer, index) => { + const timestamp = new Date(transfer.timestamp).toLocaleString(); + const fromEmoji = transfer.from_type === "exchange" ? "🏦" : + transfer.from_type === "defi" ? "🔄" : + transfer.from_type === "smart_money" ? "🧠" : + transfer.from_type === "whale" ? "🐋" : "👤"; + const toEmoji = transfer.to_type === "exchange" ? "🏦" : + transfer.to_type === "defi" ? "🔄" : + transfer.to_type === "smart_money" ? "🧠" : + transfer.to_type === "whale" ? "🐋" : "👤"; + + result += `${index + 1}. Transfer ${fromEmoji}→${toEmoji}\n`; + result += ` • From: ${transfer.from_label || transfer.from_address}\n`; + result += ` • To: ${transfer.to_label || transfer.to_address}\n`; + result += ` • Chain: ${transfer.chain}\n`; + result += ` • Amount: ${transfer.amount.toFixed(6)}\n`; + if (transfer.value_usd) { + result += ` • Value: $${transfer.value_usd.toLocaleString()}\n`; + } + result += ` • Time: ${timestamp}\n`; + result += ` • Tx Hash: ${transfer.transaction_hash}\n`; + result += "\n"; + }); + + if (!data.pagination.is_last_page) { + result += `Page ${data.pagination.page} of results. Use pagination to get more results.\n`; + } + + return result; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : "An unknown error occurred"; + return `Error fetching transfers: ${errorMessage}`; + } +} + +/** + * Get Transfers action. + */ +export class GetTransfersAction implements AgentkitAction { + public name = "get_transfers"; + public description = GET_TRANSFERS_PROMPT; + public argsSchema = GetTransfersInput; + public func = getTransfers; + public smartAccountRequired = false; +} diff --git a/agentkit-core/src/actions/NansenAction/TokenGodMode/getWhoBoughtSoldAction.ts b/agentkit-core/src/actions/NansenAction/TokenGodMode/getWhoBoughtSoldAction.ts new file mode 100644 index 0000000..51690ce --- /dev/null +++ b/agentkit-core/src/actions/NansenAction/TokenGodMode/getWhoBoughtSoldAction.ts @@ -0,0 +1,244 @@ +import { z } from "zod"; +import { AgentkitAction } from "../../../agentkit"; +import { ZeroXgaslessSmartAccount } from "@0xgasless/smart-account"; + +const GET_WHO_BOUGHT_SOLD_PROMPT = ` +Retrieve information about who bought and sold a specific token across multiple blockchains. This endpoint provides detailed information about buyers and sellers including their labels, amounts, and transaction details. + +Key Features: +- Information about who bought and sold a specific token +- Multi-chain support +- Buyer and seller labels and amounts +- Transaction details and timing +- Comprehensive trading activity analysis + +This endpoint requires a Nansen API key to be configured. +`; + +/** + * Input schema for getting who bought/sold data. + */ +export const GetWhoBoughtSoldInput = z + .object({ + token_address: z.string().describe("The token address to get buy/sell data for"), + + chains: z + .array( + z.enum([ + "all", + "arbitrum", + "avalanche", + "base", + "berachain", + "blast", + "bnb", + "ethereum", + "goat", + "hyperevm", + "iotaevm", + "linea", + "mantle", + "optimism", + "plasma", + "polygon", + "ronin", + "sei", + "scroll", + "sonic", + "unichain", + "zksync", + "solana", + ]) + ) + .describe("Chains to include in the analysis. Use 'all' to include all available chains."), + + filters: z + .object({ + transaction_hash: z.string().optional().describe("Transaction hash filter"), + action_type: z.array(z.enum(["buy", "sell"])).optional().describe("Action type filter (buy, sell)"), + trader_address: z.string().optional().describe("Trader address filter"), + trader_label: z.string().optional().describe("Trader label filter"), + trader_type: z.array(z.string()).optional().describe("Trader type filter"), + amount: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Amount range filter"), + value_usd: z + .object({ + min: z.number().optional(), + max: z.number().optional(), + }) + .optional() + .describe("Value range filter in USD"), + timestamp: z + .object({ + from: z.string().optional(), + to: z.string().optional(), + }) + .optional() + .describe("Timestamp range filter"), + }) + .optional() + .describe("Additional filters to apply"), + + pagination: z + .object({ + page: z.number().min(1).default(1).describe("Page number (1-based)"), + per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + }) + .optional() + .describe("Pagination parameters"), + + order_by: z + .array( + z.object({ + field: z + .enum([ + "chain", + "token_address", + "transaction_hash", + "action_type", + "trader_address", + "trader_label", + "trader_type", + "amount", + "value_usd", + "timestamp", + ]) + .describe("Field to sort by"), + direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), + }) + ) + .optional() + .describe("Custom sort order to override the endpoint's default ordering"), + }) + .strip() + .describe("Instructions for getting who bought/sold data"); + +/** + * Response interface for who bought/sold data. + */ +interface WhoBoughtSold { + chain: string; + token_address: string; + transaction_hash: string; + action_type: string; + trader_address: string; + trader_label: string; + trader_type: string; + amount: number; + value_usd?: number; + timestamp: string; +} + +interface WhoBoughtSoldResponse { + data: WhoBoughtSold[]; + pagination: { + page: number; + per_page: number; + is_last_page: boolean; + }; +} + +/** + * Fetches who bought/sold data from Nansen API. + * + * @param _wallet - The smart account (not used for this action). + * @param args - The input arguments containing token address, chains, filters, pagination, and sorting options. + * @returns A formatted string containing the who bought/sold data. + */ +export async function getWhoBoughtSold( + _wallet: ZeroXgaslessSmartAccount, + args: z.infer, +): Promise { + try { + const apiKey = process.env.NANSEN_API_KEY; + if (!apiKey) { + return "Error: NANSEN_API_KEY environment variable is required but not set."; + } + + const requestBody = { + token_address: args.token_address, + chains: args.chains, + ...(args.filters && { filters: args.filters }), + ...(args.pagination && { pagination: args.pagination }), + ...(args.order_by && { order_by: args.order_by }), + }; + + const response = await fetch("https://api.nansen.ai/api/v1/token-god-mode/who-bought-sold", { + method: "POST", + headers: { + "Content-Type": "application/json", + apiKey: apiKey, + "User-Agent": "0xGasless-AgentKit/1.0", + }, + body: JSON.stringify(requestBody), + }); + + if (!response.ok) { + if (response.status === 401) { + return "Error: Invalid Nansen API key. Please check your NANSEN_API_KEY environment variable."; + } + if (response.status === 403) { + return "Error: Insufficient subscription tier for this endpoint."; + } + if (response.status === 429) { + return "Error: Rate limit exceeded. Please wait before making another request."; + } + return `Error fetching who bought/sold: ${response.status} ${response.statusText}`; + } + + const data: WhoBoughtSoldResponse = await response.json(); + + if (!data.data || data.data.length === 0) { + return `No buy/sell data found for token ${args.token_address}.`; + } + + let result = `💰 Who Bought/Sold ${args.token_address}:\n\n`; + + data.data.forEach((trade, index) => { + const timestamp = new Date(trade.timestamp).toLocaleString(); + const actionEmoji = trade.action_type === "buy" ? "🟢" : "🔴"; + const typeEmoji = trade.trader_type === "exchange" ? "🏦" : + trade.trader_type === "defi" ? "🔄" : + trade.trader_type === "smart_money" ? "🧠" : + trade.trader_type === "whale" ? "🐋" : "👤"; + + result += `${index + 1}. Trade ${actionEmoji}\n`; + result += ` • Action: ${trade.action_type.toUpperCase()}\n`; + result += ` • Trader: ${typeEmoji} ${trade.trader_label || trade.trader_address}\n`; + result += ` • Type: ${trade.trader_type}\n`; + result += ` • Chain: ${trade.chain}\n`; + result += ` • Amount: ${trade.amount.toFixed(6)}\n`; + if (trade.value_usd) { + result += ` • Value: $${trade.value_usd.toLocaleString()}\n`; + } + result += ` • Time: ${timestamp}\n`; + result += ` • Tx Hash: ${trade.transaction_hash}\n`; + result += "\n"; + }); + + if (!data.pagination.is_last_page) { + result += `Page ${data.pagination.page} of results. Use pagination to get more results.\n`; + } + + return result; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : "An unknown error occurred"; + return `Error fetching who bought/sold: ${errorMessage}`; + } +} + +/** + * Get Who Bought/Sold action. + */ +export class GetWhoBoughtSoldAction implements AgentkitAction { + public name = "get_who_bought_sold"; + public description = GET_WHO_BOUGHT_SOLD_PROMPT; + public argsSchema = GetWhoBoughtSoldInput; + public func = getWhoBoughtSold; + public smartAccountRequired = false; +} diff --git a/agentkit-core/src/actions/NansenAction/TokenGodMode/index.ts b/agentkit-core/src/actions/NansenAction/TokenGodMode/index.ts new file mode 100644 index 0000000..fdacd56 --- /dev/null +++ b/agentkit-core/src/actions/NansenAction/TokenGodMode/index.ts @@ -0,0 +1,9 @@ +export { GetTokenScreenerAction } from "./getTokenScreenerAction"; +export { GetFlowIntelligenceAction } from "./getFlowIntelligenceAction"; +export { GetHoldersAction } from "./getHoldersAction"; +export { GetFlowsAction } from "./getFlowsAction"; +export { GetWhoBoughtSoldAction } from "./getWhoBoughtSoldAction"; +export { GetDexTradesAction } from "./getDexTradesAction"; +export { GetTransfersAction } from "./getTransfersAction"; +export { GetJupiterDcasAction } from "./getJupiterDcasAction"; +export { GetPnlLeaderboardAction } from "./getPnlLeaderboardAction"; diff --git a/agentkit-core/src/actions/NansenAction/index.ts b/agentkit-core/src/actions/NansenAction/index.ts new file mode 100644 index 0000000..95c7f74 --- /dev/null +++ b/agentkit-core/src/actions/NansenAction/index.ts @@ -0,0 +1,26 @@ +export { GetSmartMoneyNetflowAction } from "./SmartMoney/getSmartMoneyNetflowAction"; +export { GetSmartMoneyHoldingsAction } from "./SmartMoney/getSmartMoneyHoldingsAction"; +export { GetSmartMoneyDexTradesAction } from "./SmartMoney/getSmartMoneyDexTradesAction"; +export { GetSmartMoneyDcasAction } from "./SmartMoney/getSmartMoneyDcasAction"; + +export { GetCurrentBalanceAction } from "./Profiler/getCurrentBalanceAction"; +export { GetHistoricalBalanceAction } from "./Profiler/getHistoricalBalanceAction"; +export { GetTransactionsAction } from "./Profiler/getTransactionsAction"; +export { GetCounterpartiesAction } from "./Profiler/getCounterpartiesAction"; +export { GetRelatedWalletsAction } from "./Profiler/getRelatedWalletsAction"; +export { GetPnlSummaryAction } from "./Profiler/getPnlSummaryAction"; +export { GetPnlAction } from "./Profiler/getPnlAction"; +export { GetLabelsAction } from "./Profiler/getLabelsAction"; +export { GetTransactionLookupAction } from "./Profiler/getTransactionLookupAction"; + +export { GetTokenScreenerAction } from "./TokenGodMode/getTokenScreenerAction"; +export { GetFlowIntelligenceAction } from "./TokenGodMode/getFlowIntelligenceAction"; +export { GetHoldersAction } from "./TokenGodMode/getHoldersAction"; +export { GetFlowsAction } from "./TokenGodMode/getFlowsAction"; +export { GetWhoBoughtSoldAction } from "./TokenGodMode/getWhoBoughtSoldAction"; +export { GetDexTradesAction } from "./TokenGodMode/getDexTradesAction"; +export { GetTransfersAction } from "./TokenGodMode/getTransfersAction"; +export { GetJupiterDcasAction } from "./TokenGodMode/getJupiterDcasAction"; +export { GetPnlLeaderboardAction } from "./TokenGodMode/getPnlLeaderboardAction"; + +export { GetDefiHoldingsAction } from "./Portfolio/getDefiHoldingsAction"; diff --git a/agentkit-core/src/actions/index.ts b/agentkit-core/src/actions/index.ts index 90d27fb..5bbff6f 100644 --- a/agentkit-core/src/actions/index.ts +++ b/agentkit-core/src/actions/index.ts @@ -19,6 +19,31 @@ import { import { DisperseAction } from "./disperseAction"; import { GetEoaAddressAction } from "./getEoaAddressAction"; import { GetEoaBalanceAction } from "./getEoaBalanceAction"; +import { + GetSmartMoneyNetflowAction, + GetSmartMoneyHoldingsAction, + GetSmartMoneyDexTradesAction, + GetSmartMoneyDcasAction, + GetCurrentBalanceAction, + GetHistoricalBalanceAction, + GetTransactionsAction, + GetCounterpartiesAction, + GetRelatedWalletsAction, + GetPnlSummaryAction, + GetPnlAction, + GetLabelsAction, + GetTransactionLookupAction, + GetTokenScreenerAction, + GetFlowIntelligenceAction, + GetHoldersAction, + GetFlowsAction, + GetWhoBoughtSoldAction, + GetDexTradesAction, + GetTransfersAction, + GetJupiterDcasAction, + GetPnlLeaderboardAction, + GetDefiHoldingsAction, +} from "./NansenAction"; export function getAllAgentkitActions(): AgentkitAction[] { return [ @@ -41,6 +66,33 @@ export function getAllAgentkitActions(): AgentkitAction[] { new SearchPairsAction(), new GetPairsByTokenAddressesAction(), new DisperseAction(), + // Nansen Smart Money Actions + new GetSmartMoneyNetflowAction(), + new GetSmartMoneyHoldingsAction(), + new GetSmartMoneyDexTradesAction(), + new GetSmartMoneyDcasAction(), + // Nansen Profiler Actions + new GetCurrentBalanceAction(), + new GetHistoricalBalanceAction(), + new GetTransactionsAction(), + new GetCounterpartiesAction(), + new GetRelatedWalletsAction(), + new GetPnlSummaryAction(), + new GetPnlAction(), + new GetLabelsAction(), + new GetTransactionLookupAction(), + // Nansen Token God Mode Actions + new GetTokenScreenerAction(), + new GetFlowIntelligenceAction(), + new GetHoldersAction(), + new GetFlowsAction(), + new GetWhoBoughtSoldAction(), + new GetDexTradesAction(), + new GetTransfersAction(), + new GetJupiterDcasAction(), + new GetPnlLeaderboardAction(), + // Nansen Portfolio Actions + new GetDefiHoldingsAction(), ]; } From bc86fd160d2144f3059b89da6ce0facb6dadb883 Mon Sep 17 00:00:00 2001 From: Sanyam Date: Tue, 14 Oct 2025 19:33:50 +0530 Subject: [PATCH 2/3] correcting getCurrentBalanceAction and getTransactionsAction --- agentkit-core/package.json | 2 +- .../Portfolio/getDefiHoldingsAction.ts | 38 +- .../Profiler/getCounterpartiesAction.ts | 24 +- .../Profiler/getCurrentBalanceAction.ts | 99 +- .../Profiler/getHistoricalBalanceAction.ts | 27 +- .../NansenAction/Profiler/getLabelsAction.ts | 17 +- .../NansenAction/Profiler/getPnlAction.ts | 13 +- .../Profiler/getPnlSummaryAction.ts | 13 +- .../Profiler/getRelatedWalletsAction.ts | 21 +- .../Profiler/getTransactionLookupAction.ts | 28 +- .../Profiler/getTransactionsAction.ts | 332 +++---- .../actions/NansenAction/Profiler/index.ts | 18 +- .../SmartMoney/getSmartMoneyDcasAction.ts | 31 +- .../getSmartMoneyDexTradesAction.ts | 44 +- .../SmartMoney/getSmartMoneyHoldingsAction.ts | 51 +- .../SmartMoney/getSmartMoneyNetflowAction.ts | 51 +- .../TokenGodMode/getDexTradesAction.ts | 27 +- .../TokenGodMode/getFlowIntelligenceAction.ts | 42 +- .../TokenGodMode/getFlowsAction.ts | 24 +- .../TokenGodMode/getHoldersAction.ts | 27 +- .../TokenGodMode/getJupiterDcasAction.ts | 25 +- .../TokenGodMode/getPnlLeaderboardAction.ts | 27 +- .../TokenGodMode/getTokenScreenerAction.ts | 21 +- .../TokenGodMode/getTransfersAction.ts | 41 +- .../TokenGodMode/getWhoBoughtSoldAction.ts | 32 +- .../src/actions/NansenAction/index.ts | 46 +- agentkit-core/src/index.ts | 1 + agentkit-demo/bun.lock | 4 +- agentkit-demo/package.json | 2 +- agentkit-demo/test-balance.ts | 26 + agentkit-demo/test-transactions.ts | 22 + data.md | 863 ++++++++++++++++++ 32 files changed, 1578 insertions(+), 461 deletions(-) create mode 100644 agentkit-demo/test-balance.ts create mode 100644 agentkit-demo/test-transactions.ts create mode 100644 data.md diff --git a/agentkit-core/package.json b/agentkit-core/package.json index ac5835f..fe7ccf2 100644 --- a/agentkit-core/package.json +++ b/agentkit-core/package.json @@ -23,7 +23,7 @@ "test:e2e": "bunx jest --no-cache --testMatch=**/e2e.ts --coverageThreshold '{}'", "test:types": "tsd --files src/tests/types.test-d.ts", "clean": "rm -rf dist && rm -rf docs", - "docs": "bunx --yes typedoc --entryPoints ./src --entryPointStrategy expand --exclude ./src/tests/**/*.ts", + "docs": "bunx --yes typedoc --entryPoints ./src --entryPointStrategy expand ", "docs:serve": "bunx serve ./docs", "dev": "bun link && concurrently \"tsc --watch\" \"tsc-alias -w\"", "build": "tsc --project ./tsconfig.json && tsc-alias -p ./tsconfig.json", diff --git a/agentkit-core/src/actions/NansenAction/Portfolio/getDefiHoldingsAction.ts b/agentkit-core/src/actions/NansenAction/Portfolio/getDefiHoldingsAction.ts index c6a6286..13c421a 100644 --- a/agentkit-core/src/actions/NansenAction/Portfolio/getDefiHoldingsAction.ts +++ b/agentkit-core/src/actions/NansenAction/Portfolio/getDefiHoldingsAction.ts @@ -48,7 +48,7 @@ export const GetDefiHoldingsInput = z "unichain", "zksync", "solana", - ]) + ]), ) .describe("Chains to include in the analysis. Use 'all' to include all available chains."), @@ -80,7 +80,12 @@ export const GetDefiHoldingsInput = z pagination: z .object({ page: z.number().min(1).default(1).describe("Page number (1-based)"), - per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + per_page: z + .number() + .min(1) + .max(1000) + .default(10) + .describe("Number of records per page (max 1000)"), }) .optional() .describe("Pagination parameters"), @@ -102,7 +107,7 @@ export const GetDefiHoldingsInput = z ]) .describe("Field to sort by"), direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), - }) + }), ) .optional() .describe("Custom sort order to override the endpoint's default ordering"), @@ -192,14 +197,25 @@ export async function getDefiHoldings( data.data.forEach((holding, index) => { const timestamp = new Date(holding.timestamp).toLocaleString(); - const protocolEmoji = holding.protocol_type === "lending" ? "💰" : - holding.protocol_type === "dex" ? "🔄" : - holding.protocol_type === "yield" ? "📈" : - holding.protocol_type === "staking" ? "🔒" : "🏛️"; - const positionEmoji = holding.position_type === "supply" ? "📤" : - holding.position_type === "borrow" ? "📥" : - holding.position_type === "liquidity" ? "💧" : "📊"; - + const protocolEmoji = + holding.protocol_type === "lending" + ? "💰" + : holding.protocol_type === "dex" + ? "🔄" + : holding.protocol_type === "yield" + ? "📈" + : holding.protocol_type === "staking" + ? "🔒" + : "🏛️"; + const positionEmoji = + holding.position_type === "supply" + ? "📤" + : holding.position_type === "borrow" + ? "📥" + : holding.position_type === "liquidity" + ? "💧" + : "📊"; + result += `${index + 1}. DeFi Position ${protocolEmoji}${positionEmoji}\n`; result += ` • Protocol: ${holding.protocol_name}\n`; result += ` • Type: ${holding.protocol_type}\n`; diff --git a/agentkit-core/src/actions/NansenAction/Profiler/getCounterpartiesAction.ts b/agentkit-core/src/actions/NansenAction/Profiler/getCounterpartiesAction.ts index 06355ea..08722b4 100644 --- a/agentkit-core/src/actions/NansenAction/Profiler/getCounterpartiesAction.ts +++ b/agentkit-core/src/actions/NansenAction/Profiler/getCounterpartiesAction.ts @@ -48,7 +48,7 @@ export const GetCounterpartiesInput = z "unichain", "zksync", "solana", - ]) + ]), ) .describe("Chains to include in the analysis. Use 'all' to include all available chains."), @@ -85,7 +85,12 @@ export const GetCounterpartiesInput = z pagination: z .object({ page: z.number().min(1).default(1).describe("Page number (1-based)"), - per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + per_page: z + .number() + .min(1) + .max(1000) + .default(10) + .describe("Number of records per page (max 1000)"), }) .optional() .describe("Pagination parameters"), @@ -105,7 +110,7 @@ export const GetCounterpartiesInput = z ]) .describe("Field to sort by"), direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), - }) + }), ) .optional() .describe("Custom sort order to override the endpoint's default ordering"), @@ -193,10 +198,15 @@ export async function getCounterparties( data.data.forEach((counterparty, index) => { const timestamp = new Date(counterparty.timestamp).toLocaleString(); - const typeEmoji = counterparty.counterparty_type === "exchange" ? "🏦" : - counterparty.counterparty_type === "defi" ? "🔄" : - counterparty.counterparty_type === "nft" ? "🎨" : "👤"; - + const typeEmoji = + counterparty.counterparty_type === "exchange" + ? "🏦" + : counterparty.counterparty_type === "defi" + ? "🔄" + : counterparty.counterparty_type === "nft" + ? "🎨" + : "👤"; + result += `${index + 1}. Counterparty ${typeEmoji}\n`; result += ` • Address: ${counterparty.counterparty_address}\n`; result += ` • Label: ${counterparty.counterparty_label}\n`; diff --git a/agentkit-core/src/actions/NansenAction/Profiler/getCurrentBalanceAction.ts b/agentkit-core/src/actions/NansenAction/Profiler/getCurrentBalanceAction.ts index 72a7db4..b125a92 100644 --- a/agentkit-core/src/actions/NansenAction/Profiler/getCurrentBalanceAction.ts +++ b/agentkit-core/src/actions/NansenAction/Profiler/getCurrentBalanceAction.ts @@ -20,42 +20,52 @@ This endpoint requires a Nansen API key to be configured. */ export const GetCurrentBalanceInput = z .object({ - wallet_address: z.string().describe("The wallet address to get balances for"), - - chains: z - .array( - z.enum([ - "all", - "arbitrum", - "avalanche", - "base", - "berachain", - "blast", - "bnb", - "ethereum", - "goat", - "hyperevm", - "iotaevm", - "linea", - "mantle", - "optimism", - "plasma", - "polygon", - "ronin", - "sei", - "scroll", - "sonic", - "unichain", - "zksync", - "solana", - ]) - ) - .describe("Chains to include in the analysis. Use 'all' to include all available chains."), + address: z.string().describe("The wallet address to get balances for"), + + chain: z + .enum([ + "all", + "arbitrum", + "avalanche", + "base", + "berachain", + "blast", + "bnb", + "ethereum", + "goat", + "hyperevm", + "iotaevm", + "linea", + "mantle", + "optimism", + "plasma", + "polygon", + "ronin", + "sei", + "scroll", + "sonic", + "unichain", + "zksync", + "solana", + "bitcoin", + "starknet", + "ton", + "tron", + ]) + .describe("Chain to include in the analysis. Use 'all' to include all available chains."), filters: z .object({ - include_stablecoins: z.boolean().optional().default(false).describe("Whether to include stablecoins in the results"), - include_native_tokens: z.boolean().optional().default(false).describe("Whether to include native tokens (e.g., ETH, SOL) in the results"), + include_stablecoins: z + .boolean() + .optional() + .default(false) + .describe("Whether to include stablecoins in the results"), + include_native_tokens: z + .boolean() + .optional() + .default(false) + .describe("Whether to include native tokens (e.g., ETH, SOL) in the results"), value_usd: z .object({ min: z.number().optional(), @@ -73,7 +83,12 @@ export const GetCurrentBalanceInput = z pagination: z .object({ page: z.number().min(1).default(1).describe("Page number (1-based)"), - per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + per_page: z + .number() + .min(1) + .max(1000) + .default(10) + .describe("Number of records per page (max 1000)"), }) .optional() .describe("Pagination parameters"), @@ -92,7 +107,7 @@ export const GetCurrentBalanceInput = z ]) .describe("Field to sort by"), direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), - }) + }), ) .optional() .describe("Custom sort order to override the endpoint's default ordering"), @@ -108,7 +123,7 @@ interface CurrentBalance { token_address: string; token_symbol: string; token_sectors: string[]; - balance: number; + token_amount: number; value_usd?: number; } @@ -139,14 +154,14 @@ export async function getCurrentBalance( } const requestBody = { - wallet_address: args.wallet_address, - chains: args.chains, + address: args.address, + chain: args.chain, ...(args.filters && { filters: args.filters }), ...(args.pagination && { pagination: args.pagination }), ...(args.order_by && { order_by: args.order_by }), }; - const response = await fetch("https://api.nansen.ai/api/v1/profiler/current-balance", { + const response = await fetch("https://api.nansen.ai/api/v1/profiler/address/current-balance", { method: "POST", headers: { "Content-Type": "application/json", @@ -172,15 +187,15 @@ export async function getCurrentBalance( const data: CurrentBalanceResponse = await response.json(); if (!data.data || data.data.length === 0) { - return `No balance data found for wallet ${args.wallet_address}.`; + return `No balance data found for wallet ${args.address}.`; } - let result = `💰 Current Balance for ${args.wallet_address}:\n\n`; + let result = `💰 Current Balance for ${args.address}:\n\n`; data.data.forEach((balance, index) => { result += `${index + 1}. ${balance.token_symbol} (${balance.chain})\n`; result += ` • Token Address: ${balance.token_address}\n`; - result += ` • Balance: ${balance.balance.toFixed(6)}\n`; + result += ` • Balance: ${balance.token_amount.toFixed(6)}\n`; if (balance.value_usd) { result += ` • Value: $${balance.value_usd.toLocaleString()}\n`; } diff --git a/agentkit-core/src/actions/NansenAction/Profiler/getHistoricalBalanceAction.ts b/agentkit-core/src/actions/NansenAction/Profiler/getHistoricalBalanceAction.ts index 4cd2062..b1ee216 100644 --- a/agentkit-core/src/actions/NansenAction/Profiler/getHistoricalBalanceAction.ts +++ b/agentkit-core/src/actions/NansenAction/Profiler/getHistoricalBalanceAction.ts @@ -48,14 +48,22 @@ export const GetHistoricalBalanceInput = z "unichain", "zksync", "solana", - ]) + ]), ) .describe("Chains to include in the analysis. Use 'all' to include all available chains."), filters: z .object({ - include_stablecoins: z.boolean().optional().default(false).describe("Whether to include stablecoins in the results"), - include_native_tokens: z.boolean().optional().default(false).describe("Whether to include native tokens (e.g., ETH, SOL) in the results"), + include_stablecoins: z + .boolean() + .optional() + .default(false) + .describe("Whether to include stablecoins in the results"), + include_native_tokens: z + .boolean() + .optional() + .default(false) + .describe("Whether to include native tokens (e.g., ETH, SOL) in the results"), value_usd: z .object({ min: z.number().optional(), @@ -80,7 +88,12 @@ export const GetHistoricalBalanceInput = z pagination: z .object({ page: z.number().min(1).default(1).describe("Page number (1-based)"), - per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + per_page: z + .number() + .min(1) + .max(1000) + .default(10) + .describe("Number of records per page (max 1000)"), }) .optional() .describe("Pagination parameters"), @@ -100,7 +113,7 @@ export const GetHistoricalBalanceInput = z ]) .describe("Field to sort by"), direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), - }) + }), ) .optional() .describe("Custom sort order to override the endpoint's default ordering"), @@ -215,7 +228,9 @@ export async function getHistoricalBalance( /** * Get Historical Balance action. */ -export class GetHistoricalBalanceAction implements AgentkitAction { +export class GetHistoricalBalanceAction + implements AgentkitAction +{ public name = "get_historical_balance"; public description = GET_HISTORICAL_BALANCE_PROMPT; public argsSchema = GetHistoricalBalanceInput; diff --git a/agentkit-core/src/actions/NansenAction/Profiler/getLabelsAction.ts b/agentkit-core/src/actions/NansenAction/Profiler/getLabelsAction.ts index 74b8d21..ad3b7f1 100644 --- a/agentkit-core/src/actions/NansenAction/Profiler/getLabelsAction.ts +++ b/agentkit-core/src/actions/NansenAction/Profiler/getLabelsAction.ts @@ -48,7 +48,7 @@ export const GetLabelsInput = z "unichain", "zksync", "solana", - ]) + ]), ) .describe("Chains to include in the analysis. Use 'all' to include all available chains."), @@ -78,7 +78,12 @@ export const GetLabelsInput = z pagination: z .object({ page: z.number().min(1).default(1).describe("Page number (1-based)"), - per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + per_page: z + .number() + .min(1) + .max(1000) + .default(10) + .describe("Number of records per page (max 1000)"), }) .optional() .describe("Pagination parameters"), @@ -97,7 +102,7 @@ export const GetLabelsInput = z ]) .describe("Field to sort by"), direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), - }) + }), ) .optional() .describe("Custom sort order to override the endpoint's default ordering"), @@ -184,9 +189,9 @@ export async function getLabels( data.data.forEach((label, index) => { const timestamp = new Date(label.timestamp).toLocaleString(); - const confidenceEmoji = label.confidence_score >= 0.8 ? "🎯" : - label.confidence_score >= 0.6 ? "⚖️" : "🎲"; - + const confidenceEmoji = + label.confidence_score >= 0.8 ? "🎯" : label.confidence_score >= 0.6 ? "⚖️" : "🎲"; + result += `${index + 1}. Label ${confidenceEmoji}\n`; result += ` • Name: ${label.label_name}\n`; result += ` • Type: ${label.label_type}\n`; diff --git a/agentkit-core/src/actions/NansenAction/Profiler/getPnlAction.ts b/agentkit-core/src/actions/NansenAction/Profiler/getPnlAction.ts index 82ac548..f625f92 100644 --- a/agentkit-core/src/actions/NansenAction/Profiler/getPnlAction.ts +++ b/agentkit-core/src/actions/NansenAction/Profiler/getPnlAction.ts @@ -48,7 +48,7 @@ export const GetPnlInput = z "unichain", "zksync", "solana", - ]) + ]), ) .describe("Chains to include in the analysis. Use 'all' to include all available chains."), @@ -86,7 +86,12 @@ export const GetPnlInput = z pagination: z .object({ page: z.number().min(1).default(1).describe("Page number (1-based)"), - per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + per_page: z + .number() + .min(1) + .max(1000) + .default(10) + .describe("Number of records per page (max 1000)"), }) .optional() .describe("Pagination parameters"), @@ -107,7 +112,7 @@ export const GetPnlInput = z ]) .describe("Field to sort by"), direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), - }) + }), ) .optional() .describe("Custom sort order to override the endpoint's default ordering"), @@ -197,7 +202,7 @@ export async function getPnl( data.data.forEach((pnl, index) => { const timestamp = new Date(pnl.timestamp).toLocaleString(); const pnlEmoji = pnl.pnl_usd && pnl.pnl_usd >= 0 ? "📈" : "📉"; - + result += `${index + 1}. PnL Transaction ${pnlEmoji}\n`; result += ` • Token: ${pnl.token_symbol} (${pnl.token_address})\n`; result += ` • Chain: ${pnl.chain}\n`; diff --git a/agentkit-core/src/actions/NansenAction/Profiler/getPnlSummaryAction.ts b/agentkit-core/src/actions/NansenAction/Profiler/getPnlSummaryAction.ts index 65e8353..32863cc 100644 --- a/agentkit-core/src/actions/NansenAction/Profiler/getPnlSummaryAction.ts +++ b/agentkit-core/src/actions/NansenAction/Profiler/getPnlSummaryAction.ts @@ -48,7 +48,7 @@ export const GetPnlSummaryInput = z "unichain", "zksync", "solana", - ]) + ]), ) .describe("Chains to include in the analysis. Use 'all' to include all available chains."), @@ -85,7 +85,12 @@ export const GetPnlSummaryInput = z pagination: z .object({ page: z.number().min(1).default(1).describe("Page number (1-based)"), - per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + per_page: z + .number() + .min(1) + .max(1000) + .default(10) + .describe("Number of records per page (max 1000)"), }) .optional() .describe("Pagination parameters"), @@ -105,7 +110,7 @@ export const GetPnlSummaryInput = z ]) .describe("Field to sort by"), direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), - }) + }), ) .optional() .describe("Custom sort order to override the endpoint's default ordering"), @@ -195,7 +200,7 @@ export async function getPnlSummary( const timestamp = new Date(summary.timestamp).toLocaleString(); const pnlEmoji = summary.pnl_usd && summary.pnl_usd >= 0 ? "📈" : "📉"; const winRateEmoji = summary.win_rate >= 0.6 ? "🎯" : summary.win_rate >= 0.4 ? "⚖️" : "🎲"; - + result += `${index + 1}. PnL Summary ${pnlEmoji}\n`; result += ` • Token: ${summary.token_symbol} (${summary.token_address})\n`; result += ` • Chain: ${summary.chain}\n`; diff --git a/agentkit-core/src/actions/NansenAction/Profiler/getRelatedWalletsAction.ts b/agentkit-core/src/actions/NansenAction/Profiler/getRelatedWalletsAction.ts index e57b523..c1099e5 100644 --- a/agentkit-core/src/actions/NansenAction/Profiler/getRelatedWalletsAction.ts +++ b/agentkit-core/src/actions/NansenAction/Profiler/getRelatedWalletsAction.ts @@ -48,7 +48,7 @@ export const GetRelatedWalletsInput = z "unichain", "zksync", "solana", - ]) + ]), ) .describe("Chains to include in the analysis. Use 'all' to include all available chains."), @@ -91,7 +91,12 @@ export const GetRelatedWalletsInput = z pagination: z .object({ page: z.number().min(1).default(1).describe("Page number (1-based)"), - per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + per_page: z + .number() + .min(1) + .max(1000) + .default(10) + .describe("Number of records per page (max 1000)"), }) .optional() .describe("Pagination parameters"), @@ -111,7 +116,7 @@ export const GetRelatedWalletsInput = z ]) .describe("Field to sort by"), direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), - }) + }), ) .optional() .describe("Custom sort order to override the endpoint's default ordering"), @@ -199,9 +204,13 @@ export async function getRelatedWallets( data.data.forEach((wallet, index) => { const timestamp = new Date(wallet.timestamp).toLocaleString(); - const strengthEmoji = wallet.relationship_strength >= 0.8 ? "🔗" : - wallet.relationship_strength >= 0.6 ? "🔗" : "🔗"; - + const strengthEmoji = + wallet.relationship_strength >= 0.8 + ? "🔗" + : wallet.relationship_strength >= 0.6 + ? "🔗" + : "🔗"; + result += `${index + 1}. Related Wallet ${strengthEmoji}\n`; result += ` • Address: ${wallet.related_wallet_address}\n`; result += ` • Relationship: ${wallet.relationship_type}\n`; diff --git a/agentkit-core/src/actions/NansenAction/Profiler/getTransactionLookupAction.ts b/agentkit-core/src/actions/NansenAction/Profiler/getTransactionLookupAction.ts index 5fe53f6..ce1bb5d 100644 --- a/agentkit-core/src/actions/NansenAction/Profiler/getTransactionLookupAction.ts +++ b/agentkit-core/src/actions/NansenAction/Profiler/getTransactionLookupAction.ts @@ -48,7 +48,7 @@ export const GetTransactionLookupInput = z "unichain", "zksync", "solana", - ]) + ]), ) .describe("Chains to include in the analysis. Use 'all' to include all available chains."), @@ -79,7 +79,12 @@ export const GetTransactionLookupInput = z pagination: z .object({ page: z.number().min(1).default(1).describe("Page number (1-based)"), - per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + per_page: z + .number() + .min(1) + .max(1000) + .default(10) + .describe("Number of records per page (max 1000)"), }) .optional() .describe("Pagination parameters"), @@ -99,7 +104,7 @@ export const GetTransactionLookupInput = z ]) .describe("Field to sort by"), direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), - }) + }), ) .optional() .describe("Custom sort order to override the endpoint's default ordering"), @@ -187,10 +192,15 @@ export async function getTransactionLookup( data.data.forEach((tx, index) => { const timestamp = new Date(tx.timestamp).toLocaleString(); - const typeEmoji = tx.transaction_type === "swap" ? "🔄" : - tx.transaction_type === "transfer" ? "📤" : - tx.transaction_type === "mint" ? "🪙" : "📄"; - + const typeEmoji = + tx.transaction_type === "swap" + ? "🔄" + : tx.transaction_type === "transfer" + ? "📤" + : tx.transaction_type === "mint" + ? "🪙" + : "📄"; + result += `${index + 1}. Transaction Detail ${typeEmoji}\n`; result += ` • Type: ${tx.transaction_type}\n`; result += ` • Chain: ${tx.chain}\n`; @@ -219,7 +229,9 @@ export async function getTransactionLookup( /** * Get Transaction Lookup action. */ -export class GetTransactionLookupAction implements AgentkitAction { +export class GetTransactionLookupAction + implements AgentkitAction +{ public name = "get_transaction_lookup"; public description = GET_TRANSACTION_LOOKUP_PROMPT; public argsSchema = GetTransactionLookupInput; diff --git a/agentkit-core/src/actions/NansenAction/Profiler/getTransactionsAction.ts b/agentkit-core/src/actions/NansenAction/Profiler/getTransactionsAction.ts index 7e168ab..ae0903f 100644 --- a/agentkit-core/src/actions/NansenAction/Profiler/getTransactionsAction.ts +++ b/agentkit-core/src/actions/NansenAction/Profiler/getTransactionsAction.ts @@ -2,230 +2,128 @@ import { z } from "zod"; import { AgentkitAction } from "../../../agentkit"; import { ZeroXgaslessSmartAccount } from "@0xgasless/smart-account"; -const GET_TRANSACTIONS_PROMPT = ` -Retrieve transaction history for a specific wallet address across multiple blockchains. This endpoint provides detailed transaction information including transfers, swaps, and other blockchain activities. - -Key Features: -- Transaction history for a specific wallet -- Multi-chain support -- Detailed transaction information -- Transfer and swap activities -- Comprehensive transaction metadata - -This endpoint requires a Nansen API key to be configured. -`; - -/** - * Input schema for getting transactions data. - */ -export const GetTransactionsInput = z - .object({ - wallet_address: z.string().describe("The wallet address to get transactions for"), - - chains: z - .array( - z.enum([ - "all", - "arbitrum", - "avalanche", - "base", - "berachain", - "blast", - "bnb", - "ethereum", - "goat", - "hyperevm", - "iotaevm", - "linea", - "mantle", - "optimism", - "plasma", - "polygon", - "ronin", - "sei", - "scroll", - "sonic", - "unichain", - "zksync", - "solana", - ]) - ) - .describe("Chains to include in the analysis. Use 'all' to include all available chains."), - - filters: z - .object({ - transaction_hash: z.string().optional().describe("Transaction hash filter"), - transaction_type: z.array(z.string()).optional().describe("Transaction type filter"), - token_address: z.string().optional().describe("Token address filter"), - token_symbol: z.string().optional().describe("Token symbol filter"), - counterparty_address: z.string().optional().describe("Counterparty address filter"), - counterparty_label: z.string().optional().describe("Counterparty label filter"), - value_usd: z - .object({ - min: z.number().optional(), - max: z.number().optional(), - }) - .optional() - .describe("Value range filter in USD"), - timestamp: z - .object({ - from: z.string().optional(), - to: z.string().optional(), - }) - .optional() - .describe("Timestamp range filter"), - }) - .optional() - .describe("Additional filters to apply"), - - pagination: z - .object({ - page: z.number().min(1).default(1).describe("Page number (1-based)"), - per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), - }) - .optional() - .describe("Pagination parameters"), - - order_by: z - .array( - z.object({ - field: z - .enum([ - "chain", - "transaction_hash", - "transaction_type", - "token_address", - "token_symbol", - "counterparty_address", - "counterparty_label", - "value_usd", - "timestamp", - ]) - .describe("Field to sort by"), - direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), +const GET_TRANSACTIONS_PROMPT = `Retrieve transaction history for a specific wallet address across multiple blockchains. This endpoint provides detailed transaction information including transfers, swaps, and other blockchain activities.`; + +// Input schema (match Nansen) +export const GetTransactionsInput = z.object({ + address: z.string().describe("The wallet address to get transactions for"), + chain: z + .enum([ + // short list here, but can expand as per Nansen docs + "arbitrum", + "avalanche", + "base", + "bnb", + "ethereum", + "optimism", + "polygon", + "solana", + "bitcoin", + "zksync", + // ... all others as needed + ]) + .describe("Blockchain chain for the transactions"), + date: z + .object({ + from: z.string().optional(), + to: z.string().optional(), + }) + .optional(), + hide_spam_token: z.boolean().default(true), + filters: z + .object({ + transaction_hash: z.string().optional(), + transaction_type: z.array(z.string()).optional(), + token_address: z.string().optional(), + token_symbol: z.string().optional(), + counterparty_address: z.string().optional(), + counterparty_label: z.string().optional(), + // Fix: use volume_usd not value_usd + volume_usd: z + .object({ + min: z.number().optional(), + max: z.number().optional(), }) - ) - .optional() - .describe("Custom sort order to override the endpoint's default ordering"), - }) - .strip() - .describe("Instructions for getting transactions data"); - -/** - * Response interface for transactions data. - */ -interface Transaction { - chain: string; - transaction_hash: string; - transaction_type: string; - token_address: string; - token_symbol: string; - counterparty_address: string; - counterparty_label: string; - value_usd?: number; - timestamp: string; -} - -interface TransactionsResponse { - data: Transaction[]; - pagination: { - page: number; - per_page: number; - is_last_page: boolean; - }; -} + .optional(), + // Fix: use blockTimestamp for timestamp range filter + blockTimestamp: z + .object({ + from: z.string().optional(), + to: z.string().optional(), + }) + .optional(), + }) + .optional(), + pagination: z + .object({ + page: z.number().min(1).default(1), + per_page: z.number().min(1).max(20).default(10), + }) + .optional(), + order_by: z + .array( + z.object({ + // Fix: use block_timestamp per nansen docs + field: z.enum([ + "chain", + "transaction_hash", + "block_number", + "block_timestamp", + "from_address", + "to_address", + "volume_usd", + "cost_usd", + "fee_usd", + ]), + direction: z.enum(["asc", "desc"]), + }), + ) + .optional(), +}); -/** - * Fetches transactions data from Nansen API. - * - * @param _wallet - The smart account (not used for this action). - * @param args - The input arguments containing wallet address, chains, filters, pagination, and sorting options. - * @returns A formatted string containing the transactions data. - */ export async function getTransactions( - _wallet: ZeroXgaslessSmartAccount, + _smartAccount: ZeroXgaslessSmartAccount, args: z.infer, -): Promise { - try { - const apiKey = process.env.NANSEN_API_KEY; - if (!apiKey) { - return "Error: NANSEN_API_KEY environment variable is required but not set."; - } - - const requestBody = { - wallet_address: args.wallet_address, - chains: args.chains, - ...(args.filters && { filters: args.filters }), - ...(args.pagination && { pagination: args.pagination }), - ...(args.order_by && { order_by: args.order_by }), - }; - - const response = await fetch("https://api.nansen.ai/api/v1/profiler/transactions", { - method: "POST", - headers: { - "Content-Type": "application/json", - apiKey: apiKey, - "User-Agent": "0xGasless-AgentKit/1.0", - }, - body: JSON.stringify(requestBody), - }); - - if (!response.ok) { - if (response.status === 401) { - return "Error: Invalid Nansen API key. Please check your NANSEN_API_KEY environment variable."; - } - if (response.status === 403) { - return "Error: Insufficient subscription tier for this endpoint."; - } - if (response.status === 429) { - return "Error: Rate limit exceeded. Please wait before making another request."; - } - return `Error fetching transactions: ${response.status} ${response.statusText}`; - } - - const data: TransactionsResponse = await response.json(); - - if (!data.data || data.data.length === 0) { - return `No transactions found for wallet ${args.wallet_address}.`; - } - - let result = `📋 Transactions for ${args.wallet_address}:\n\n`; - - data.data.forEach((tx, index) => { - const timestamp = new Date(tx.timestamp).toLocaleString(); - const typeEmoji = tx.transaction_type === "swap" ? "🔄" : tx.transaction_type === "transfer" ? "📤" : "📄"; - - result += `${index + 1}. Transaction ${typeEmoji}\n`; - result += ` • Type: ${tx.transaction_type}\n`; - result += ` • Chain: ${tx.chain}\n`; - result += ` • Token: ${tx.token_symbol} (${tx.token_address})\n`; - result += ` • Counterparty: ${tx.counterparty_label || tx.counterparty_address}\n`; - if (tx.value_usd) { - result += ` • Value: $${tx.value_usd.toLocaleString()}\n`; - } - result += ` • Time: ${timestamp}\n`; - result += ` • Tx Hash: ${tx.transaction_hash}\n`; - result += "\n"; - }); - - if (!data.pagination.is_last_page) { - result += `Page ${data.pagination.page} of results. Use pagination to get more results.\n`; - } +) { + const nansenApiKey = process.env.NANSEN_API_KEY; + if (!nansenApiKey) throw new Error("Nansen API key is not set"); + + const url = "https://api.nansen.ai/api/v1/profiler/address/transactions"; + console.log(`Fetching transactions for ${args.address} on ${args.chain}...`); + + const response = await fetch(url, { + method: "POST", + headers: { + "Content-Type": "application/json", + apiKey: nansenApiKey, // Key fix! + }, + body: JSON.stringify(args), + }); + + if (!response.ok) { + const errorData = await response.json(); + throw new Error( + `Failed to fetch transactions: ${response.statusText} - ${JSON.stringify(errorData)}`, + ); + } - return result; - } catch (error) { - const errorMessage = error instanceof Error ? error.message : "An unknown error occurred"; - return `Error fetching transactions: ${errorMessage}`; + const data = await response.json(); + if (!data.result || data.result.length === 0) { + return `No transactions found for wallet ${args.address}.`; } + + return data; } -/** - * Get Transactions action. - */ export class GetTransactionsAction implements AgentkitAction { - public name = "get_transactions"; - public description = GET_TRANSACTIONS_PROMPT; - public argsSchema = GetTransactionsInput; - public func = getTransactions; - public smartAccountRequired = false; + name = "getTransactions"; + description = GET_TRANSACTIONS_PROMPT; + inputSchema = GetTransactionsInput; + argsSchema = GetTransactionsInput; + func = getTransactions; + + async run(smartAccount: ZeroXgaslessSmartAccount, args: z.infer) { + const data = await getTransactions(smartAccount, args); + return data; + } } diff --git a/agentkit-core/src/actions/NansenAction/Profiler/index.ts b/agentkit-core/src/actions/NansenAction/Profiler/index.ts index 10a03e2..efaa48e 100644 --- a/agentkit-core/src/actions/NansenAction/Profiler/index.ts +++ b/agentkit-core/src/actions/NansenAction/Profiler/index.ts @@ -1,9 +1,9 @@ -export { GetCurrentBalanceAction } from "./getCurrentBalanceAction"; -export { GetHistoricalBalanceAction } from "./getHistoricalBalanceAction"; -export { GetTransactionsAction } from "./getTransactionsAction"; -export { GetCounterpartiesAction } from "./getCounterpartiesAction"; -export { GetRelatedWalletsAction } from "./getRelatedWalletsAction"; -export { GetPnlSummaryAction } from "./getPnlSummaryAction"; -export { GetPnlAction } from "./getPnlAction"; -export { GetLabelsAction } from "./getLabelsAction"; -export { GetTransactionLookupAction } from "./getTransactionLookupAction"; +export * from "./getCurrentBalanceAction"; +export * from "./getHistoricalBalanceAction"; +export * from "./getTransactionsAction"; +export * from "./getCounterpartiesAction"; +export * from "./getRelatedWalletsAction"; +export * from "./getPnlSummaryAction"; +export * from "./getPnlAction"; +export * from "./getLabelsAction"; +export * from "./getTransactionLookupAction"; diff --git a/agentkit-core/src/actions/NansenAction/SmartMoney/getSmartMoneyDcasAction.ts b/agentkit-core/src/actions/NansenAction/SmartMoney/getSmartMoneyDcasAction.ts index fd9abec..a8ca1df 100644 --- a/agentkit-core/src/actions/NansenAction/SmartMoney/getSmartMoneyDcasAction.ts +++ b/agentkit-core/src/actions/NansenAction/SmartMoney/getSmartMoneyDcasAction.ts @@ -23,11 +23,27 @@ export const GetSmartMoneyDcasInput = z filters: z .object({ include_smart_money_labels: z - .array(z.enum(["Fund", "Smart Trader", "30D Smart Trader", "90D Smart Trader", "180D Smart Trader"])) + .array( + z.enum([ + "Fund", + "Smart Trader", + "30D Smart Trader", + "90D Smart Trader", + "180D Smart Trader", + ]), + ) .optional() .describe("Smart money category filters to include"), exclude_smart_money_labels: z - .array(z.enum(["Fund", "Smart Trader", "30D Smart Trader", "90D Smart Trader", "180D Smart Trader"])) + .array( + z.enum([ + "Fund", + "Smart Trader", + "30D Smart Trader", + "90D Smart Trader", + "180D Smart Trader", + ]), + ) .optional() .describe("Smart money category filters to exclude"), dca_created_at: z @@ -70,7 +86,12 @@ export const GetSmartMoneyDcasInput = z pagination: z .object({ page: z.number().min(1).default(1).describe("Page number (1-based)"), - per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + per_page: z + .number() + .min(1) + .max(1000) + .default(10) + .describe("Number of records per page (max 1000)"), }) .optional() .describe("Pagination parameters"), @@ -91,7 +112,7 @@ export const GetSmartMoneyDcasInput = z ]) .describe("Field to sort by"), direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), - }) + }), ) .optional() .describe("Custom sort order to override the endpoint's default ordering"), @@ -187,7 +208,7 @@ export async function getSmartMoneyDcas( const createdDate = new Date(dca.dca_created_at).toLocaleString(); const updatedDate = new Date(dca.dca_updated_at).toLocaleString(); const statusEmoji = dca.dca_status === "active" ? "🟢" : "🔴"; - + result += `${index + 1}. DCA Order ${statusEmoji}\n`; result += ` • Trader: ${dca.trader_address_label || dca.trader_address}\n`; result += ` • Strategy: ${dca.input_token_symbol} → ${dca.output_token_symbol}\n`; diff --git a/agentkit-core/src/actions/NansenAction/SmartMoney/getSmartMoneyDexTradesAction.ts b/agentkit-core/src/actions/NansenAction/SmartMoney/getSmartMoneyDexTradesAction.ts index 2900e84..d5950e6 100644 --- a/agentkit-core/src/actions/NansenAction/SmartMoney/getSmartMoneyDexTradesAction.ts +++ b/agentkit-core/src/actions/NansenAction/SmartMoney/getSmartMoneyDexTradesAction.ts @@ -46,25 +46,46 @@ export const GetSmartMoneyDexTradesInput = z "unichain", "zksync", "solana", - ]) + ]), ) - .describe("Chains to include in the analysis (only smart money supported chains). Use 'all' to include all available chains."), + .describe( + "Chains to include in the analysis (only smart money supported chains). Use 'all' to include all available chains.", + ), filters: z .object({ include_smart_money_labels: z - .array(z.enum(["Fund", "Smart Trader", "30D Smart Trader", "90D Smart Trader", "180D Smart Trader"])) + .array( + z.enum([ + "Fund", + "Smart Trader", + "30D Smart Trader", + "90D Smart Trader", + "180D Smart Trader", + ]), + ) .optional() .describe("Smart money category filters to include"), exclude_smart_money_labels: z - .array(z.enum(["Fund", "Smart Trader", "30D Smart Trader", "90D Smart Trader", "180D Smart Trader"])) + .array( + z.enum([ + "Fund", + "Smart Trader", + "30D Smart Trader", + "90D Smart Trader", + "180D Smart Trader", + ]), + ) .optional() .describe("Smart money category filters to exclude"), chain: z.string().optional().describe("Blockchain network filter"), transaction_hash: z.string().optional().describe("Transaction hash filter"), trader_address: z.string().optional().describe("Trader address filter"), trader_address_label: z.string().optional().describe("Trader name or label filter"), - token_bought_address: z.string().optional().describe("Token address filter for bought tokens"), + token_bought_address: z + .string() + .optional() + .describe("Token address filter for bought tokens"), token_sold_address: z.string().optional().describe("Token address filter for sold tokens"), token_bought_amount: z .object({ @@ -124,7 +145,12 @@ export const GetSmartMoneyDexTradesInput = z pagination: z .object({ page: z.number().min(1).default(1).describe("Page number (1-based)"), - per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + per_page: z + .number() + .min(1) + .max(1000) + .default(10) + .describe("Number of records per page (max 1000)"), }) .optional() .describe("Pagination parameters"), @@ -153,7 +179,7 @@ export const GetSmartMoneyDexTradesInput = z ]) .describe("Field to sort by"), direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), - }) + }), ) .optional() .describe("Custom sort order to override the endpoint's default ordering"), @@ -279,7 +305,9 @@ export async function getSmartMoneyDexTrades( /** * Get Smart Money DEX Trades action. */ -export class GetSmartMoneyDexTradesAction implements AgentkitAction { +export class GetSmartMoneyDexTradesAction + implements AgentkitAction +{ public name = "get_smart_money_dex_trades"; public description = GET_SMART_MONEY_DEX_TRADES_PROMPT; public argsSchema = GetSmartMoneyDexTradesInput; diff --git a/agentkit-core/src/actions/NansenAction/SmartMoney/getSmartMoneyHoldingsAction.ts b/agentkit-core/src/actions/NansenAction/SmartMoney/getSmartMoneyHoldingsAction.ts index 6fa4f69..11504ef 100644 --- a/agentkit-core/src/actions/NansenAction/SmartMoney/getSmartMoneyHoldingsAction.ts +++ b/agentkit-core/src/actions/NansenAction/SmartMoney/getSmartMoneyHoldingsAction.ts @@ -45,22 +45,48 @@ export const GetSmartMoneyHoldingsInput = z "unichain", "zksync", "solana", - ]) + ]), ) - .describe("Chains to include in the analysis (only smart money supported chains). Use 'all' to include all available chains."), + .describe( + "Chains to include in the analysis (only smart money supported chains). Use 'all' to include all available chains.", + ), filters: z .object({ include_smart_money_labels: z - .array(z.enum(["Fund", "Smart Trader", "30D Smart Trader", "90D Smart Trader", "180D Smart Trader"])) + .array( + z.enum([ + "Fund", + "Smart Trader", + "30D Smart Trader", + "90D Smart Trader", + "180D Smart Trader", + ]), + ) .optional() .describe("Smart money category filters to include"), exclude_smart_money_labels: z - .array(z.enum(["Fund", "Smart Trader", "30D Smart Trader", "90D Smart Trader", "180D Smart Trader"])) + .array( + z.enum([ + "Fund", + "Smart Trader", + "30D Smart Trader", + "90D Smart Trader", + "180D Smart Trader", + ]), + ) .optional() .describe("Smart money category filters to exclude"), - include_stablecoins: z.boolean().optional().default(false).describe("Whether to include stablecoins in the results"), - include_native_tokens: z.boolean().optional().default(false).describe("Whether to include native tokens (e.g., ETH, SOL) in the results"), + include_stablecoins: z + .boolean() + .optional() + .default(false) + .describe("Whether to include stablecoins in the results"), + include_native_tokens: z + .boolean() + .optional() + .default(false) + .describe("Whether to include native tokens (e.g., ETH, SOL) in the results"), value_usd: z .object({ min: z.number().optional(), @@ -113,7 +139,12 @@ export const GetSmartMoneyHoldingsInput = z pagination: z .object({ page: z.number().min(1).default(1).describe("Page number (1-based)"), - per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + per_page: z + .number() + .min(1) + .max(1000) + .default(10) + .describe("Number of records per page (max 1000)"), }) .optional() .describe("Pagination parameters"), @@ -135,7 +166,7 @@ export const GetSmartMoneyHoldingsInput = z ]) .describe("Field to sort by"), direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), - }) + }), ) .optional() .describe("Custom sort order to override the endpoint's default ordering"), @@ -261,7 +292,9 @@ export async function getSmartMoneyHoldings( /** * Get Smart Money Holdings action. */ -export class GetSmartMoneyHoldingsAction implements AgentkitAction { +export class GetSmartMoneyHoldingsAction + implements AgentkitAction +{ public name = "get_smart_money_holdings"; public description = GET_SMART_MONEY_HOLDINGS_PROMPT; public argsSchema = GetSmartMoneyHoldingsInput; diff --git a/agentkit-core/src/actions/NansenAction/SmartMoney/getSmartMoneyNetflowAction.ts b/agentkit-core/src/actions/NansenAction/SmartMoney/getSmartMoneyNetflowAction.ts index dbbcee7..fb26e95 100644 --- a/agentkit-core/src/actions/NansenAction/SmartMoney/getSmartMoneyNetflowAction.ts +++ b/agentkit-core/src/actions/NansenAction/SmartMoney/getSmartMoneyNetflowAction.ts @@ -52,23 +52,49 @@ export const GetSmartMoneyNetflowInput = z "unichain", "zksync", "solana", - ]) + ]), ) - .describe("Chains to include in the analysis (only smart money supported chains). Use 'all' to include all available chains."), + .describe( + "Chains to include in the analysis (only smart money supported chains). Use 'all' to include all available chains.", + ), filters: z .object({ include_smart_money_labels: z - .array(z.enum(["Fund", "Smart Trader", "30D Smart Trader", "90D Smart Trader", "180D Smart Trader"])) + .array( + z.enum([ + "Fund", + "Smart Trader", + "30D Smart Trader", + "90D Smart Trader", + "180D Smart Trader", + ]), + ) .optional() .describe("Smart money category filters to include"), exclude_smart_money_labels: z - .array(z.enum(["Fund", "Smart Trader", "30D Smart Trader", "90D Smart Trader", "180D Smart Trader"])) + .array( + z.enum([ + "Fund", + "Smart Trader", + "30D Smart Trader", + "90D Smart Trader", + "180D Smart Trader", + ]), + ) .optional() .describe("Smart money category filters to exclude"), token_address: z.string().optional().describe("Token address or symbol filter"), - include_stablecoins: z.boolean().optional().default(false).describe("Whether to include stablecoins in the results"), - include_native_tokens: z.boolean().optional().default(false).describe("Whether to include native tokens (e.g., ETH, SOL) in the results"), + include_stablecoins: z + .boolean() + .optional() + .default(false) + .describe("Whether to include stablecoins in the results"), + include_native_tokens: z + .boolean() + .optional() + .default(false) + .describe("Whether to include native tokens (e.g., ETH, SOL) in the results"), token_sector: z.array(z.string()).optional().describe("Token sector filter"), trader_count: z .object({ @@ -98,7 +124,12 @@ export const GetSmartMoneyNetflowInput = z pagination: z .object({ page: z.number().min(1).default(1).describe("Page number (1-based)"), - per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + per_page: z + .number() + .min(1) + .max(1000) + .default(10) + .describe("Number of records per page (max 1000)"), }) .optional() .describe("Pagination parameters"), @@ -121,7 +152,7 @@ export const GetSmartMoneyNetflowInput = z ]) .describe("Field to sort by"), direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), - }) + }), ) .optional() .describe("Custom sort order to override the endpoint's default ordering"), @@ -240,7 +271,9 @@ export async function getSmartMoneyNetflow( /** * Get Smart Money Netflow action. */ -export class GetSmartMoneyNetflowAction implements AgentkitAction { +export class GetSmartMoneyNetflowAction + implements AgentkitAction +{ public name = "get_smart_money_netflow"; public description = GET_SMART_MONEY_NETFLOW_PROMPT; public argsSchema = GetSmartMoneyNetflowInput; diff --git a/agentkit-core/src/actions/NansenAction/TokenGodMode/getDexTradesAction.ts b/agentkit-core/src/actions/NansenAction/TokenGodMode/getDexTradesAction.ts index bc66c06..32d9203 100644 --- a/agentkit-core/src/actions/NansenAction/TokenGodMode/getDexTradesAction.ts +++ b/agentkit-core/src/actions/NansenAction/TokenGodMode/getDexTradesAction.ts @@ -48,7 +48,7 @@ export const GetDexTradesInput = z "unichain", "zksync", "solana", - ]) + ]), ) .describe("Chains to include in the analysis. Use 'all' to include all available chains."), @@ -94,7 +94,12 @@ export const GetDexTradesInput = z pagination: z .object({ page: z.number().min(1).default(1).describe("Page number (1-based)"), - per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + per_page: z + .number() + .min(1) + .max(1000) + .default(10) + .describe("Number of records per page (max 1000)"), }) .optional() .describe("Pagination parameters"), @@ -118,7 +123,7 @@ export const GetDexTradesInput = z ]) .describe("Field to sort by"), direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), - }) + }), ) .optional() .describe("Custom sort order to override the endpoint's default ordering"), @@ -210,11 +215,17 @@ export async function getDexTrades( data.data.forEach((trade, index) => { const timestamp = new Date(trade.timestamp).toLocaleString(); - const typeEmoji = trade.trader_type === "exchange" ? "🏦" : - trade.trader_type === "defi" ? "🔄" : - trade.trader_type === "smart_money" ? "🧠" : - trade.trader_type === "whale" ? "🐋" : "👤"; - + const typeEmoji = + trade.trader_type === "exchange" + ? "🏦" + : trade.trader_type === "defi" + ? "🔄" + : trade.trader_type === "smart_money" + ? "🧠" + : trade.trader_type === "whale" + ? "🐋" + : "👤"; + result += `${index + 1}. DEX Trade ${typeEmoji}\n`; result += ` • Trader: ${trade.trader_label || trade.trader_address}\n`; result += ` • Type: ${trade.trader_type}\n`; diff --git a/agentkit-core/src/actions/NansenAction/TokenGodMode/getFlowIntelligenceAction.ts b/agentkit-core/src/actions/NansenAction/TokenGodMode/getFlowIntelligenceAction.ts index 06cd0ee..c296650 100644 --- a/agentkit-core/src/actions/NansenAction/TokenGodMode/getFlowIntelligenceAction.ts +++ b/agentkit-core/src/actions/NansenAction/TokenGodMode/getFlowIntelligenceAction.ts @@ -48,14 +48,17 @@ export const GetFlowIntelligenceInput = z "unichain", "zksync", "solana", - ]) + ]), ) .describe("Chains to include in the analysis. Use 'all' to include all available chains."), filters: z .object({ entity_type: z.array(z.string()).optional().describe("Entity type filter"), - flow_type: z.array(z.string()).optional().describe("Flow type filter (inflow, outflow, net)"), + flow_type: z + .array(z.string()) + .optional() + .describe("Flow type filter (inflow, outflow, net)"), value_usd: z .object({ min: z.number().optional(), @@ -77,7 +80,12 @@ export const GetFlowIntelligenceInput = z pagination: z .object({ page: z.number().min(1).default(1).describe("Page number (1-based)"), - per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + per_page: z + .number() + .min(1) + .max(1000) + .default(10) + .describe("Number of records per page (max 1000)"), }) .optional() .describe("Pagination parameters"), @@ -86,17 +94,10 @@ export const GetFlowIntelligenceInput = z .array( z.object({ field: z - .enum([ - "chain", - "token_address", - "entity_type", - "flow_type", - "value_usd", - "timestamp", - ]) + .enum(["chain", "token_address", "entity_type", "flow_type", "value_usd", "timestamp"]) .describe("Field to sort by"), direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), - }) + }), ) .optional() .describe("Custom sort order to override the endpoint's default ordering"), @@ -183,12 +184,17 @@ export async function getFlowIntelligence( data.data.forEach((flow, index) => { const timestamp = new Date(flow.timestamp).toLocaleString(); - const flowEmoji = flow.flow_type === "inflow" ? "📈" : - flow.flow_type === "outflow" ? "📉" : "⚖️"; - const entityEmoji = flow.entity_type === "exchange" ? "🏦" : - flow.entity_type === "defi" ? "🔄" : - flow.entity_type === "smart_money" ? "🧠" : "👤"; - + const flowEmoji = + flow.flow_type === "inflow" ? "📈" : flow.flow_type === "outflow" ? "📉" : "⚖️"; + const entityEmoji = + flow.entity_type === "exchange" + ? "🏦" + : flow.entity_type === "defi" + ? "🔄" + : flow.entity_type === "smart_money" + ? "🧠" + : "👤"; + result += `${index + 1}. Flow Data ${flowEmoji}\n`; result += ` • Entity: ${entityEmoji} ${flow.entity_type}\n`; result += ` • Flow Type: ${flow.flow_type}\n`; diff --git a/agentkit-core/src/actions/NansenAction/TokenGodMode/getFlowsAction.ts b/agentkit-core/src/actions/NansenAction/TokenGodMode/getFlowsAction.ts index 5e30cbe..92d7dcd 100644 --- a/agentkit-core/src/actions/NansenAction/TokenGodMode/getFlowsAction.ts +++ b/agentkit-core/src/actions/NansenAction/TokenGodMode/getFlowsAction.ts @@ -48,7 +48,7 @@ export const GetFlowsInput = z "unichain", "zksync", "solana", - ]) + ]), ) .describe("Chains to include in the analysis. Use 'all' to include all available chains."), @@ -88,7 +88,12 @@ export const GetFlowsInput = z pagination: z .object({ page: z.number().min(1).default(1).describe("Page number (1-based)"), - per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + per_page: z + .number() + .min(1) + .max(1000) + .default(10) + .describe("Number of records per page (max 1000)"), }) .optional() .describe("Pagination parameters"), @@ -112,7 +117,7 @@ export const GetFlowsInput = z ]) .describe("Field to sort by"), direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), - }) + }), ) .optional() .describe("Custom sort order to override the endpoint's default ordering"), @@ -204,10 +209,15 @@ export async function getFlows( data.data.forEach((flow, index) => { const timestamp = new Date(flow.timestamp).toLocaleString(); - const flowEmoji = flow.flow_type === "transfer" ? "📤" : - flow.flow_type === "swap" ? "🔄" : - flow.flow_type === "mint" ? "🪙" : "📄"; - + const flowEmoji = + flow.flow_type === "transfer" + ? "📤" + : flow.flow_type === "swap" + ? "🔄" + : flow.flow_type === "mint" + ? "🪙" + : "📄"; + result += `${index + 1}. Flow ${flowEmoji}\n`; result += ` • Type: ${flow.flow_type}\n`; result += ` • Chain: ${flow.chain}\n`; diff --git a/agentkit-core/src/actions/NansenAction/TokenGodMode/getHoldersAction.ts b/agentkit-core/src/actions/NansenAction/TokenGodMode/getHoldersAction.ts index 1a9753a..2f92573 100644 --- a/agentkit-core/src/actions/NansenAction/TokenGodMode/getHoldersAction.ts +++ b/agentkit-core/src/actions/NansenAction/TokenGodMode/getHoldersAction.ts @@ -48,7 +48,7 @@ export const GetHoldersInput = z "unichain", "zksync", "solana", - ]) + ]), ) .describe("Chains to include in the analysis. Use 'all' to include all available chains."), @@ -85,7 +85,12 @@ export const GetHoldersInput = z pagination: z .object({ page: z.number().min(1).default(1).describe("Page number (1-based)"), - per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + per_page: z + .number() + .min(1) + .max(1000) + .default(10) + .describe("Number of records per page (max 1000)"), }) .optional() .describe("Pagination parameters"), @@ -106,7 +111,7 @@ export const GetHoldersInput = z ]) .describe("Field to sort by"), direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), - }) + }), ) .optional() .describe("Custom sort order to override the endpoint's default ordering"), @@ -195,11 +200,17 @@ export async function getHolders( data.data.forEach((holder, index) => { const timestamp = new Date(holder.timestamp).toLocaleString(); - const typeEmoji = holder.holder_type === "exchange" ? "🏦" : - holder.holder_type === "defi" ? "🔄" : - holder.holder_type === "smart_money" ? "🧠" : - holder.holder_type === "whale" ? "🐋" : "👤"; - + const typeEmoji = + holder.holder_type === "exchange" + ? "🏦" + : holder.holder_type === "defi" + ? "🔄" + : holder.holder_type === "smart_money" + ? "🧠" + : holder.holder_type === "whale" + ? "🐋" + : "👤"; + result += `${index + 1}. Holder ${typeEmoji}\n`; result += ` • Address: ${holder.holder_address}\n`; result += ` • Label: ${holder.holder_label}\n`; diff --git a/agentkit-core/src/actions/NansenAction/TokenGodMode/getJupiterDcasAction.ts b/agentkit-core/src/actions/NansenAction/TokenGodMode/getJupiterDcasAction.ts index 657f754..fca0c73 100644 --- a/agentkit-core/src/actions/NansenAction/TokenGodMode/getJupiterDcasAction.ts +++ b/agentkit-core/src/actions/NansenAction/TokenGodMode/getJupiterDcasAction.ts @@ -73,7 +73,12 @@ export const GetJupiterDcasInput = z pagination: z .object({ page: z.number().min(1).default(1).describe("Page number (1-based)"), - per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + per_page: z + .number() + .min(1) + .max(1000) + .default(10) + .describe("Number of records per page (max 1000)"), }) .optional() .describe("Pagination parameters"), @@ -99,7 +104,7 @@ export const GetJupiterDcasInput = z ]) .describe("Field to sort by"), direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), - }) + }), ) .optional() .describe("Custom sort order to override the endpoint's default ordering"), @@ -193,11 +198,17 @@ export async function getJupiterDcas( data.data.forEach((dca, index) => { const createdDate = new Date(dca.dca_created_at).toLocaleString(); const statusEmoji = dca.dca_status === "active" ? "🟢" : "🔴"; - const typeEmoji = dca.trader_type === "exchange" ? "🏦" : - dca.trader_type === "defi" ? "🔄" : - dca.trader_type === "smart_money" ? "🧠" : - dca.trader_type === "whale" ? "🐋" : "👤"; - + const typeEmoji = + dca.trader_type === "exchange" + ? "🏦" + : dca.trader_type === "defi" + ? "🔄" + : dca.trader_type === "smart_money" + ? "🧠" + : dca.trader_type === "whale" + ? "🐋" + : "👤"; + result += `${index + 1}. DCA Order ${statusEmoji}\n`; result += ` • Trader: ${typeEmoji} ${dca.trader_label || dca.trader_address}\n`; result += ` • Type: ${dca.trader_type}\n`; diff --git a/agentkit-core/src/actions/NansenAction/TokenGodMode/getPnlLeaderboardAction.ts b/agentkit-core/src/actions/NansenAction/TokenGodMode/getPnlLeaderboardAction.ts index f1b0927..271a75c 100644 --- a/agentkit-core/src/actions/NansenAction/TokenGodMode/getPnlLeaderboardAction.ts +++ b/agentkit-core/src/actions/NansenAction/TokenGodMode/getPnlLeaderboardAction.ts @@ -48,7 +48,7 @@ export const GetPnlLeaderboardInput = z "unichain", "zksync", "solana", - ]) + ]), ) .describe("Chains to include in the analysis. Use 'all' to include all available chains."), @@ -92,7 +92,12 @@ export const GetPnlLeaderboardInput = z pagination: z .object({ page: z.number().min(1).default(1).describe("Page number (1-based)"), - per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + per_page: z + .number() + .min(1) + .max(1000) + .default(10) + .describe("Number of records per page (max 1000)"), }) .optional() .describe("Pagination parameters"), @@ -114,7 +119,7 @@ export const GetPnlLeaderboardInput = z ]) .describe("Field to sort by"), direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), - }) + }), ) .optional() .describe("Custom sort order to override the endpoint's default ordering"), @@ -206,11 +211,17 @@ export async function getPnlLeaderboard( const timestamp = new Date(trader.timestamp).toLocaleString(); const rankEmoji = index === 0 ? "🥇" : index === 1 ? "🥈" : index === 2 ? "🥉" : "🏅"; const pnlEmoji = trader.pnl_usd && trader.pnl_usd >= 0 ? "📈" : "📉"; - const typeEmoji = trader.trader_type === "exchange" ? "🏦" : - trader.trader_type === "defi" ? "🔄" : - trader.trader_type === "smart_money" ? "🧠" : - trader.trader_type === "whale" ? "🐋" : "👤"; - + const typeEmoji = + trader.trader_type === "exchange" + ? "🏦" + : trader.trader_type === "defi" + ? "🔄" + : trader.trader_type === "smart_money" + ? "🧠" + : trader.trader_type === "whale" + ? "🐋" + : "👤"; + result += `${index + 1}. ${rankEmoji} Trader ${pnlEmoji}\n`; result += ` • Trader: ${typeEmoji} ${trader.trader_label || trader.trader_address}\n`; result += ` • Type: ${trader.trader_type}\n`; diff --git a/agentkit-core/src/actions/NansenAction/TokenGodMode/getTokenScreenerAction.ts b/agentkit-core/src/actions/NansenAction/TokenGodMode/getTokenScreenerAction.ts index 0698e6f..3b2adcf 100644 --- a/agentkit-core/src/actions/NansenAction/TokenGodMode/getTokenScreenerAction.ts +++ b/agentkit-core/src/actions/NansenAction/TokenGodMode/getTokenScreenerAction.ts @@ -48,7 +48,7 @@ export const GetTokenScreenerInput = z "unichain", "zksync", "solana", - ]) + ]), ) .describe("Chains to include in the analysis. Use 'all' to include all available chains."), @@ -98,7 +98,12 @@ export const GetTokenScreenerInput = z pagination: z .object({ page: z.number().min(1).default(1).describe("Page number (1-based)"), - per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + per_page: z + .number() + .min(1) + .max(1000) + .default(10) + .describe("Number of records per page (max 1000)"), }) .optional() .describe("Pagination parameters"), @@ -120,7 +125,7 @@ export const GetTokenScreenerInput = z ]) .describe("Field to sort by"), direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), - }) + }), ) .optional() .describe("Custom sort order to override the endpoint's default ordering"), @@ -210,9 +215,13 @@ export async function getTokenScreener( data.data.forEach((token, index) => { const timestamp = new Date(token.timestamp).toLocaleString(); - const marketCapEmoji = token.market_cap_usd && token.market_cap_usd > 1000000000 ? "🚀" : - token.market_cap_usd && token.market_cap_usd > 100000000 ? "📈" : "📊"; - + const marketCapEmoji = + token.market_cap_usd && token.market_cap_usd > 1000000000 + ? "🚀" + : token.market_cap_usd && token.market_cap_usd > 100000000 + ? "📈" + : "📊"; + result += `${index + 1}. Token Data ${marketCapEmoji}\n`; result += ` • Symbol: ${token.token_symbol}\n`; result += ` • Chain: ${token.chain}\n`; diff --git a/agentkit-core/src/actions/NansenAction/TokenGodMode/getTransfersAction.ts b/agentkit-core/src/actions/NansenAction/TokenGodMode/getTransfersAction.ts index 2ade22f..b96a7b7 100644 --- a/agentkit-core/src/actions/NansenAction/TokenGodMode/getTransfersAction.ts +++ b/agentkit-core/src/actions/NansenAction/TokenGodMode/getTransfersAction.ts @@ -48,7 +48,7 @@ export const GetTransfersInput = z "unichain", "zksync", "solana", - ]) + ]), ) .describe("Chains to include in the analysis. Use 'all' to include all available chains."), @@ -89,7 +89,12 @@ export const GetTransfersInput = z pagination: z .object({ page: z.number().min(1).default(1).describe("Page number (1-based)"), - per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + per_page: z + .number() + .min(1) + .max(1000) + .default(10) + .describe("Number of records per page (max 1000)"), }) .optional() .describe("Pagination parameters"), @@ -114,7 +119,7 @@ export const GetTransfersInput = z ]) .describe("Field to sort by"), direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), - }) + }), ) .optional() .describe("Custom sort order to override the endpoint's default ordering"), @@ -207,15 +212,27 @@ export async function getTransfers( data.data.forEach((transfer, index) => { const timestamp = new Date(transfer.timestamp).toLocaleString(); - const fromEmoji = transfer.from_type === "exchange" ? "🏦" : - transfer.from_type === "defi" ? "🔄" : - transfer.from_type === "smart_money" ? "🧠" : - transfer.from_type === "whale" ? "🐋" : "👤"; - const toEmoji = transfer.to_type === "exchange" ? "🏦" : - transfer.to_type === "defi" ? "🔄" : - transfer.to_type === "smart_money" ? "🧠" : - transfer.to_type === "whale" ? "🐋" : "👤"; - + const fromEmoji = + transfer.from_type === "exchange" + ? "🏦" + : transfer.from_type === "defi" + ? "🔄" + : transfer.from_type === "smart_money" + ? "🧠" + : transfer.from_type === "whale" + ? "🐋" + : "👤"; + const toEmoji = + transfer.to_type === "exchange" + ? "🏦" + : transfer.to_type === "defi" + ? "🔄" + : transfer.to_type === "smart_money" + ? "🧠" + : transfer.to_type === "whale" + ? "🐋" + : "👤"; + result += `${index + 1}. Transfer ${fromEmoji}→${toEmoji}\n`; result += ` • From: ${transfer.from_label || transfer.from_address}\n`; result += ` • To: ${transfer.to_label || transfer.to_address}\n`; diff --git a/agentkit-core/src/actions/NansenAction/TokenGodMode/getWhoBoughtSoldAction.ts b/agentkit-core/src/actions/NansenAction/TokenGodMode/getWhoBoughtSoldAction.ts index 51690ce..a8013be 100644 --- a/agentkit-core/src/actions/NansenAction/TokenGodMode/getWhoBoughtSoldAction.ts +++ b/agentkit-core/src/actions/NansenAction/TokenGodMode/getWhoBoughtSoldAction.ts @@ -48,14 +48,17 @@ export const GetWhoBoughtSoldInput = z "unichain", "zksync", "solana", - ]) + ]), ) .describe("Chains to include in the analysis. Use 'all' to include all available chains."), filters: z .object({ transaction_hash: z.string().optional().describe("Transaction hash filter"), - action_type: z.array(z.enum(["buy", "sell"])).optional().describe("Action type filter (buy, sell)"), + action_type: z + .array(z.enum(["buy", "sell"])) + .optional() + .describe("Action type filter (buy, sell)"), trader_address: z.string().optional().describe("Trader address filter"), trader_label: z.string().optional().describe("Trader label filter"), trader_type: z.array(z.string()).optional().describe("Trader type filter"), @@ -87,7 +90,12 @@ export const GetWhoBoughtSoldInput = z pagination: z .object({ page: z.number().min(1).default(1).describe("Page number (1-based)"), - per_page: z.number().min(1).max(1000).default(10).describe("Number of records per page (max 1000)"), + per_page: z + .number() + .min(1) + .max(1000) + .default(10) + .describe("Number of records per page (max 1000)"), }) .optional() .describe("Pagination parameters"), @@ -110,7 +118,7 @@ export const GetWhoBoughtSoldInput = z ]) .describe("Field to sort by"), direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), - }) + }), ) .optional() .describe("Custom sort order to override the endpoint's default ordering"), @@ -202,11 +210,17 @@ export async function getWhoBoughtSold( data.data.forEach((trade, index) => { const timestamp = new Date(trade.timestamp).toLocaleString(); const actionEmoji = trade.action_type === "buy" ? "🟢" : "🔴"; - const typeEmoji = trade.trader_type === "exchange" ? "🏦" : - trade.trader_type === "defi" ? "🔄" : - trade.trader_type === "smart_money" ? "🧠" : - trade.trader_type === "whale" ? "🐋" : "👤"; - + const typeEmoji = + trade.trader_type === "exchange" + ? "🏦" + : trade.trader_type === "defi" + ? "🔄" + : trade.trader_type === "smart_money" + ? "🧠" + : trade.trader_type === "whale" + ? "🐋" + : "👤"; + result += `${index + 1}. Trade ${actionEmoji}\n`; result += ` • Action: ${trade.action_type.toUpperCase()}\n`; result += ` • Trader: ${typeEmoji} ${trade.trader_label || trade.trader_address}\n`; diff --git a/agentkit-core/src/actions/NansenAction/index.ts b/agentkit-core/src/actions/NansenAction/index.ts index 95c7f74..71e9c14 100644 --- a/agentkit-core/src/actions/NansenAction/index.ts +++ b/agentkit-core/src/actions/NansenAction/index.ts @@ -1,26 +1,26 @@ -export { GetSmartMoneyNetflowAction } from "./SmartMoney/getSmartMoneyNetflowAction"; -export { GetSmartMoneyHoldingsAction } from "./SmartMoney/getSmartMoneyHoldingsAction"; -export { GetSmartMoneyDexTradesAction } from "./SmartMoney/getSmartMoneyDexTradesAction"; -export { GetSmartMoneyDcasAction } from "./SmartMoney/getSmartMoneyDcasAction"; +export * from "./SmartMoney/getSmartMoneyNetflowAction"; +export * from "./SmartMoney/getSmartMoneyHoldingsAction"; +export * from "./SmartMoney/getSmartMoneyDexTradesAction"; +export * from "./SmartMoney/getSmartMoneyDcasAction"; -export { GetCurrentBalanceAction } from "./Profiler/getCurrentBalanceAction"; -export { GetHistoricalBalanceAction } from "./Profiler/getHistoricalBalanceAction"; -export { GetTransactionsAction } from "./Profiler/getTransactionsAction"; -export { GetCounterpartiesAction } from "./Profiler/getCounterpartiesAction"; -export { GetRelatedWalletsAction } from "./Profiler/getRelatedWalletsAction"; -export { GetPnlSummaryAction } from "./Profiler/getPnlSummaryAction"; -export { GetPnlAction } from "./Profiler/getPnlAction"; -export { GetLabelsAction } from "./Profiler/getLabelsAction"; -export { GetTransactionLookupAction } from "./Profiler/getTransactionLookupAction"; +export * from "./Profiler/getCurrentBalanceAction"; +export * from "./Profiler/getHistoricalBalanceAction"; +export * from "./Profiler/getTransactionsAction"; +export * from "./Profiler/getCounterpartiesAction"; +export * from "./Profiler/getRelatedWalletsAction"; +export * from "./Profiler/getPnlSummaryAction"; +export * from "./Profiler/getPnlAction"; +export * from "./Profiler/getLabelsAction"; +export * from "./Profiler/getTransactionLookupAction"; -export { GetTokenScreenerAction } from "./TokenGodMode/getTokenScreenerAction"; -export { GetFlowIntelligenceAction } from "./TokenGodMode/getFlowIntelligenceAction"; -export { GetHoldersAction } from "./TokenGodMode/getHoldersAction"; -export { GetFlowsAction } from "./TokenGodMode/getFlowsAction"; -export { GetWhoBoughtSoldAction } from "./TokenGodMode/getWhoBoughtSoldAction"; -export { GetDexTradesAction } from "./TokenGodMode/getDexTradesAction"; -export { GetTransfersAction } from "./TokenGodMode/getTransfersAction"; -export { GetJupiterDcasAction } from "./TokenGodMode/getJupiterDcasAction"; -export { GetPnlLeaderboardAction } from "./TokenGodMode/getPnlLeaderboardAction"; +export * from "./TokenGodMode/getTokenScreenerAction"; +export * from "./TokenGodMode/getFlowIntelligenceAction"; +export * from "./TokenGodMode/getHoldersAction"; +export * from "./TokenGodMode/getFlowsAction"; +export * from "./TokenGodMode/getWhoBoughtSoldAction"; +export * from "./TokenGodMode/getDexTradesAction"; +export * from "./TokenGodMode/getTransfersAction"; +export * from "./TokenGodMode/getJupiterDcasAction"; +export * from "./TokenGodMode/getPnlLeaderboardAction"; -export { GetDefiHoldingsAction } from "./Portfolio/getDefiHoldingsAction"; +export * from "./Portfolio/getDefiHoldingsAction"; diff --git a/agentkit-core/src/index.ts b/agentkit-core/src/index.ts index 4080873..0c2085c 100644 --- a/agentkit-core/src/index.ts +++ b/agentkit-core/src/index.ts @@ -11,3 +11,4 @@ export * from "./actions"; export * from "./agentkit"; export * from "./langchain"; export * from "./services"; +export * from "./actions/NansenAction"; diff --git a/agentkit-demo/bun.lock b/agentkit-demo/bun.lock index 0bdaf65..d2a74f4 100644 --- a/agentkit-demo/bun.lock +++ b/agentkit-demo/bun.lock @@ -10,7 +10,7 @@ "@langchain/langgraph": "^0.2.21", "@langchain/openai": "^0.3.14", "axios": "^1.7.9", - "dotenv": "^16.4.5", + "dotenv": "^17.2.3", "merkletreejs": "^0.4.1", "tslib": "^2.8.1", "viem": "^2.22.17", @@ -116,7 +116,7 @@ "delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="], - "dotenv": ["dotenv@16.5.0", "", {}, "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg=="], + "dotenv": ["dotenv@17.2.3", "", {}, "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w=="], "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], diff --git a/agentkit-demo/package.json b/agentkit-demo/package.json index 1a4ae3a..4410b75 100644 --- a/agentkit-demo/package.json +++ b/agentkit-demo/package.json @@ -20,7 +20,7 @@ "@langchain/langgraph": "^0.2.21", "@langchain/openai": "^0.3.14", "axios": "^1.7.9", - "dotenv": "^16.4.5", + "dotenv": "^17.2.3", "merkletreejs": "^0.4.1", "tslib": "^2.8.1", "viem": "^2.22.17", diff --git a/agentkit-demo/test-balance.ts b/agentkit-demo/test-balance.ts new file mode 100644 index 0000000..0edd4f3 --- /dev/null +++ b/agentkit-demo/test-balance.ts @@ -0,0 +1,26 @@ +import "dotenv/config"; +import { getCurrentBalance } from "@0xgasless/agentkit"; + +async function main() { + const address = "0x50Fa6437631194662Be1D9Babe6FA300774e07A5"; + // The Nansen API uses "avalanche" for the mainnet. + // "fuji" is the testnet and may not be supported by this endpoint. + const chain = "base"; // Changed to "base" as requested + + console.log(`Fetching balance for ${address} on ${chain}...`); + + try { + // The first argument to getCurrentBalance is a smart wallet, which is not needed for this action. + // We can pass 'null' and cast it to 'any' to satisfy the type checker. + const result = await getCurrentBalance(null as any, { + address: address, + chain: chain, + }); + + console.log(result); + } catch (error) { + console.error("An error occurred during the test:", error); + } +} + +main(); diff --git a/agentkit-demo/test-transactions.ts b/agentkit-demo/test-transactions.ts new file mode 100644 index 0000000..1f106a0 --- /dev/null +++ b/agentkit-demo/test-transactions.ts @@ -0,0 +1,22 @@ +import "dotenv/config"; +import { getTransactions } from "@0xgasless/agentkit"; + +async function main() { + const result = await getTransactions( + null as any, + { + address: "0x50Fa6437631194662Be1D9Babe6FA300774e07A5", + chain: "base", + date: { + from: "2024-01-01T00:00:00Z", + to: "2025-10-14T23:59:59Z", + }, + // optional fields below ensure default, clean API request + hide_spam_token: true, + // add more fields as needed (filters, pagination, order_by) + } + ); + console.log(JSON.stringify(result, null, 2)); // pretty-print result +} + +main().catch(console.error); diff --git a/data.md b/data.md new file mode 100644 index 0000000..55adc07 --- /dev/null +++ b/data.md @@ -0,0 +1,863 @@ + +# Introduction + +Nansen API offers programmatic access to high-quality onchain data and advanced blockchain analytics across numerous networks. The API aims to equip users with the necessary data to gain a competitive edge, identify opportunities, perform due diligence, and make informed decisions within the dynamic crypto market. It effectively translates the complexity of raw blockchain data into actionable intelligence, accessible through a structured API interface. + +### Key Capabilities + +* **Proprietary Data Labeling:** Nansen applies unique, human-readable labels to hundreds of millions of blockchain addresses. These labels identify specific entities such as exchanges, funds, market makers, notable individual investors that allows users to understand who is behind onchain activities, providing crucial context that raw, pseudonymous data lacks. Accessing this labelled data via the API is a core component of Nansen's offering. +* **Unique Datasets and Insights:** The API provides access to data points and analytics not readily available elsewhere, such as Smart Money analytics. +* **Comprehensive Multi-Chain Coverage:** The API consolidates data from multiple blockchain networks, allowing users to track assets and activities across different ecosystems through a single integration point. + +These features collectively enable the API to deliver not just data, but contextualized intelligence, transforming raw onchain events into a clearer picture of market dynamics and participant behavior. + +### Jump right in + +
Authenticationauthentication
Endpoints Overviewendpoints-overview
Smart Money APIsmart-money
Profiler APIprofiler
Token God Modetoken-god-mode
+ +link to the docs : @https://docs.nansen.ai/ + +endpoints overview : +# Endpoints Overview + +{% hint style="warning" %} +Deprecation Notice: The ‎`/beta` API endpoints will be deprecated on 01 October 2025. Please migrate your integrations to the ‎`/v1` endpoints before this date to ensure uninterrupted service. +{% endhint %} + +Below is the list of APIs currently available as part of the Nansen API. V1 delivers a stable, scalable foundation for developers, with advanced filtering, standardized endpoints, and comprehensive documentation. This ensures efficient integration, reliable performance, and easier maintenance as you build onchain analytics solutions. + +### Smart Money + +A curated list of the top 5 000 highest-performing wallets ranked by realised profit, winrate, and strong performance across market cycles. + +| Endpoint | Description | +| ----------------------------------------------------------------------------------------- | ---------------------------------------------------------------- | +| [smart-money/netflows](https://docs.nansen.ai/v1-nansen-api/api/smart-money/netflows) | Provides net flow of tokens bought/sold by Smart Money addresses | +| [smart-money/holdings](https://docs.nansen.ai/v1-nansen-api/api/smart-money/holdings) | Holdings of tokens by Smart Money addresses. | +| [smart-money/dex-trades](https://docs.nansen.ai/v1-nansen-api/api/smart-money/dex-trades) | All dex trades of smart money traders in the last 24h | +| [smart-money/dcas ](https://docs.nansen.ai/v1-nansen-api/api/smart-money/jupiter-dcas) | All Jupiter DCAs started by Smart Money Wallets on Solana | + +### Profiler + +A toolkit for diving deep into address relationships and behaviour, letting you analyse any wallet or entity cluster to uncover flows, counterparties, and behavioural patterns. + +| Endpoint | Description | +| -------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | +| [address/current-balance](https://docs.nansen.ai/v1-nansen-api/api/profiler/address-current-balances) | Current Token balances of an address | +| [profiler/address/historical-balances](https://docs.nansen.ai/v1-nansen-api/api/profiler/address-historical-balances) | Historical holdings of a wallet address | +| [profiler/address/transactions](https://docs.nansen.ai/v1-nansen-api/api/profiler/address-transactions) | List of transactions made by an address | +| [profiler/address/counterparties](https://docs.nansen.ai/v1-nansen-api/api/profiler/address-counterparties) | Top Counterparties a wallet has interacted with | +| [profiler/address/related-wallets](https://docs.nansen.ai/v1-nansen-api/api/profiler/address-related-wallets) | List of related wallets and its first degree relation | +| [profiler/address/pnl-summary](https://docs.nansen.ai/v1-nansen-api/api/profiler/address-pnl-and-trade-performance) | Trade summary including top 5 trades | +| [profiler/address/pnl](https://docs.nansen.ai/v1-nansen-api/api/profiler/address-pnl-and-trade-performance#post-api-v1-profiler-address-pnl) | List of Past Trades and their performance made by the address | +| [/profiler/address/labels](https://docs.nansen.ai/v1-nansen-api/api/profiler/address-labels) | Address and list of all its labels | + +### Token God Mode + +A comprehensive lens on a token’s on-chain activity, combining Smart Money movements, holder-base analysis, and exchange-flow tracking in one view. + +| Endpoint | Description | +| -------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | +| [tgm/token-screener](https://docs.nansen.ai/v1-nansen-api/api/token-god-mode/token-screener) | A token screening endpoint that provides real-time analytics and insights across multiple blockchain networks. | +| [tgm/flow-intelligence](https://docs.nansen.ai/v1-nansen-api/api/token-god-mode/flow-intelligence) | Summary of token flows across Smart Money, exchanges, Top PnL Traders, Public Figures, Whales, Fresh Wallets | +| [tgm/holders](https://docs.nansen.ai/v1-nansen-api/api/token-god-mode/holders) | Balance of top addresses, smart money, exchanges, public figures and whales that can be queried by address or by entity | +| [tgm/flows](https://docs.nansen.ai/v1-nansen-api/api/token-god-mode/flows) | Total Inflow and outflow of a token from smart money, exchanges, public figures or whales. | +| [tgm/who-bought-sold ](https://docs.nansen.ai/v1-nansen-api/api/token-god-mode/who-bought-sold) | Recent buyers and sellers of a token summarised | +| [tgm/dex-trades](https://docs.nansen.ai/v1-nansen-api/api/token-god-mode/dex-trades) | All DEX Trades of a Token | +| [tgm/transfers ](https://docs.nansen.ai/v1-nansen-api/api/token-god-mode/token-transfers) | Top Token Transfers of a token | +| [tgm/jup-dca ](https://docs.nansen.ai/v1-nansen-api/api/token-god-mode/jupiter-dcas) | List of all Jupiter DCA orders of a token on Solana | +| [tgm/pnl-leaderboard ](https://docs.nansen.ai/v1-nansen-api/api/token-god-mode/pnl-leaderboard) | List of addresses and their total realised and unrealised PnL | + +### Portfolio API + +| Endpoint | Description | +| ----------------------------------------------------------------------------- | ------------------------------------- | +| [portfolio/defi-holdings](https://docs.nansen.ai/v1-nansen-api/api/portfolio) | Track DeFi positions of all addresses | + + +api call : +# Make Your First API Call + +### **Step 1: Get your API key** + +Create or copy your key from the Nansen API tab in the navigation bar [(Click here)](https://app.nansen.ai/api) + +
+ +### **Step 2: Run this cURL Command** + +```bash +curl -L \ + --request POST \ + --url 'https://api.nansen.ai/api/v1/smart-money/netflow' \ + --header 'apiKey: YOUR_API_KEY' \ + --header 'Content-Type: application/json' \ + --data '{ + "chains": [ + "ethereum", + "solana" + ], + "pagination": { + "page": 1, + "per_page": 10 + }, + "order_by": [ + { + "field": "net_flow_24h_usd", + "direction": "DESC" + } + ] + }' + +``` + +### Step 3: Now try this in API Explorer + +* Click on Test It button on the API codeblock below +* Paste your API Key under the value section (As shown in the screenshot)\ + ![](https://3666025612-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FHE8GKwbmDRKKCMC7hnip%2Fuploads%2FpgdtmDetI8UOqgaCFEIE%2FScreenshot%202025-09-01%20at%208.36.07%E2%80%AFPM.png?alt=media\&token=4f7af6d7-e1f3-44e6-96cb-6883828edc24) +* Click on "Send" or press CMD + Enter. + +## Get Smart Money Netflow Data + +> Analyze net capital flows (inflows vs outflows) from smart traders and funds across different time periods. This endpoint helps identify which tokens are experiencing net accumulation or distribution by smart money.\ +> \ +> What are Net Flows?\ +> Net flows represent the difference between smart money inflows and outflows for a token. This includes:\ +> \ +> \- DEX Trading Activity: Tokens bought vs sold on decentralized exchanges\ +> \- CEX Transfers: Tokens sent to or received from centralized exchanges\ +> \- Positive Net Flow: Smart money is accumulating (buying more than selling, or withdrawing from CEXs)\ +> \- Negative Net Flow: Smart money is distributing (selling more than buying, or depositing to CEXs)\ +> \ +> Key Features:\ +> \ +> \- Aggregated net flow calculations across all smart money activity\ +> \- Multiple time period analysis (24h, 7d, 30d)\ +> \- Sortable results by volume metrics\ +> \- Includes both DEX trades and CEX transfers + +```json +{"openapi":"3.1.0","info":{"title":"Nansen API","version":"1.0.0"},"tags":[{"name":"Smart Money","description":"Smart money analytics and insights"}],"servers":[{"url":"https://api.nansen.ai","description":"Production server"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"apiKey","description":"API key for authentication"}},"schemas":{"SmartMoneyNetflowRequest":{"properties":{"chains":{"items":{"$ref":"#/components/schemas/SmartMoneyChain"},"type":"array","title":"Chains","description":"Chains to include in the analysis (only smart money supported chains). Use 'all' to include all available chains."},"filters":{"anyOf":[{"$ref":"#/components/schemas/SmartMoneyNetflowFilters"}],"description":"Additional filters to apply. Only filters for columns that are being selected will be applied."},"pagination":{"$ref":"#/components/schemas/PaginationRequest","description":"Pagination parameters"},"order_by":{"anyOf":[{"items":{"$ref":"#/components/schemas/SortOrder_SmartMoneyNetflowSortField_"},"type":"array"}],"title":"Order By","description":"Custom sort order to override the endpoint's default ordering.\n\nExamples:\n- [{\"field\": \"market_cap_usd\", \"direction\": \"DESC\"}] - Sort by market cap descending\n- [{\"field\": \"net_flow_24h_usd\", \"direction\": \"ASC\"}] - Sort by 24h flow ascending\n- [{\"field\": \"market_cap_usd\", \"direction\": \"DESC\"}, {\"field\": \"net_flow_24h_usd\", \"direction\": \"ASC\"}] - Sort by market cap descending, then 24h flow ascending"}},"additionalProperties":false,"type":"object","required":["chains"],"title":"SmartMoneyNetflowRequest","description":""},"SmartMoneyChain":{"type":"string","enum":["all","arbitrum","avalanche","base","berachain","blast","bnb","ethereum","goat","hyperevm","iotaevm","linea","mantle","optimism","plasma","polygon","ronin","sei","scroll","sonic","unichain","zksync","solana"],"title":"SmartMoneyChain","description":"Enum for chains supported in smart money analysis."},"SmartMoneyNetflowFilters":{"properties":{"include_smart_money_labels":{"anyOf":[{"items":{"$ref":"#/components/schemas/SmartMoneyFilterType"},"type":"array"}],"title":"Include Smart Money Labels","description":"Smart money category filters"},"exclude_smart_money_labels":{"anyOf":[{"items":{"$ref":"#/components/schemas/SmartMoneyFilterType"},"type":"array"}],"title":"Exclude Smart Money Labels","description":"Smart money category filters"},"token_address":{"anyOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Token Address","description":"Token address or symbol filter"},"include_stablecoins":{"anyOf":[{"type":"boolean"}],"title":"Include Stablecoins","description":"Whether to include stablecoins in the results","default":false},"include_native_tokens":{"anyOf":[{"type":"boolean"}],"title":"Include Native Tokens","description":"Whether to include native tokens (e.g., ETH, SOL) in the results","default":false},"token_sector":{"anyOf":[{"items":{"type":"string"},"type":"array"}],"title":"Token Sector","description":"Token sector filter"},"trader_count":{"anyOf":[{"$ref":"#/components/schemas/NumericRangeFilter"}],"description":"Trader count range filter"},"token_age_days":{"anyOf":[{"$ref":"#/components/schemas/NumericRangeFilter"}],"description":"Token age range filter in days"},"market_cap_usd":{"anyOf":[{"$ref":"#/components/schemas/NumericRangeFilter"}],"description":"Market cap range filter in USD"}},"additionalProperties":false,"type":"object","title":"SmartMoneyNetflowFilters","description":"Filters for smart money netflow endpoint.\n\nThese filters control which smart money categories, tokens, and data\nare included in the netflow analysis."},"SmartMoneyFilterType":{"type":"string","enum":["Fund","Smart Trader","30D Smart Trader","90D Smart Trader","180D Smart Trader"],"title":"SmartMoneyFilterType","description":"Enum for smart money filter options."},"NumericRangeFilter":{"properties":{"min":{"anyOf":[{"type":"number"}],"title":"Min","description":"Minimum value (inclusive)"},"max":{"anyOf":[{"type":"number"}],"title":"Max","description":"Maximum value (inclusive)"}},"type":"object","title":"NumericRangeFilter","description":"Filter for numeric values (floats) with optional min/max bounds.\nUse for prices, volumes, ratios, and other decimal values. - Values between -10.5 and 100.75"},"PaginationRequest":{"properties":{"page":{"type":"integer","minimum":1,"title":"Page","description":"Page number (1-based)","default":1},"per_page":{"type":"integer","maximum":1000,"minimum":1,"title":"Per Page","description":"Number of records per page (max 1000)","default":10}},"type":"object","title":"PaginationRequest","description":"Pagination parameters for API requests."},"SortOrder_SmartMoneyNetflowSortField_":{"properties":{"field":{"$ref":"#/components/schemas/SmartMoneyNetflowSortField","description":"Field to sort by"},"direction":{"$ref":"#/components/schemas/SortDirection","description":"Sort direction (ASC or DESC)"}},"type":"object","required":["field","direction"],"title":"SortOrder[SmartMoneyNetflowSortField]"},"SmartMoneyNetflowSortField":{"type":"string","enum":["chain","token_address","token_symbol","net_flow_24h_usd","net_flow_7d_usd","net_flow_30d_usd","token_sectors","trader_count","token_age_days","market_cap_usd"],"title":"SmartMoneyNetflowSortField","description":"Enum for sortable fields in smart money netflow."},"SortDirection":{"type":"string","enum":["ASC","DESC"],"title":"SortDirection","description":"Enum for sort directions."},"SmartMoneyNetflowResponse":{"properties":{"data":{"items":{"$ref":"#/components/schemas/SmartMoneyNetflow"},"type":"array","title":"Data","description":"List of smart money netflow records"},"pagination":{"$ref":"#/components/schemas/PaginationInfo","description":"Pagination information"}},"type":"object","required":["data","pagination"],"title":"SmartMoneyNetflowResponse","description":"Response model for smart money netflow endpoint.\n\nContains the filtered smart money netflow data with metadata."},"SmartMoneyNetflow":{"properties":{"token_address":{"type":"string","title":"Token Address","description":"Token contract address"},"token_symbol":{"type":"string","title":"Token Symbol","description":"Token symbol"},"net_flow_24h_usd":{"type":"number","title":"Net Flow 24H Usd","description":"Net flow bought/sold of token by Smart Money in the past 24 hours."},"net_flow_7d_usd":{"type":"number","title":"Net Flow 7D Usd","description":"Net flow bought/sold of token by Smart Money in the past 7 days."},"net_flow_30d_usd":{"type":"number","title":"Net Flow 30D Usd","description":"Net flow bought/sold of token by Smart Money in the past 30 days."},"chain":{"type":"string","title":"Chain","description":"Blockchain chain"},"token_sectors":{"items":{"type":"string"},"type":"array","title":"Token Sectors","description":"Token sectors"},"trader_count":{"type":"integer","title":"Trader Count","description":"Number of Smart Money traders of token in the past 30 days."},"token_age_days":{"type":"integer","title":"Token Age Days","description":"Number of days since token was deployed."},"market_cap_usd":{"anyOf":[{"type":"number"}],"title":"Market Cap Usd","description":"Market cap of token."}},"type":"object","required":["token_address","token_symbol","net_flow_24h_usd","net_flow_7d_usd","net_flow_30d_usd","chain","token_sectors","trader_count","token_age_days"],"title":"SmartMoneyNetflow","description":"Individual smart money netflow record.\n\nRepresents a single token's smart money netflow data."},"PaginationInfo":{"properties":{"page":{"type":"integer","minimum":1,"title":"Page","description":"Current page number","default":1},"per_page":{"type":"integer","maximum":1000,"minimum":1,"title":"Per Page","description":"Number of records per page","default":10},"is_last_page":{"type":"boolean","title":"Is Last Page","description":"Whether this is the last page","default":true}},"type":"object","title":"PaginationInfo","description":"Pagination information for API responses."}},"responses":{"BadRequestError":{"description":"Bad Request - Invalid request parameters or malformed request","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"UnauthorizedError":{"description":"Authentication error - No API key found in request","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"ForbiddenError":{"description":"Forbidden - User does not have required subscription tier","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"NotFoundError":{"description":"Not Found - The requested resource was not found","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"ValidationError":{"description":"Validation error - Invalid request parameters","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"loc":{"type":"array","items":{"type":"string"}},"msg":{"type":"string"},"type":{"type":"string"}}}}}}}}},"TooManyRequestsError":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"},"retry_after":{"type":"integer","description":"Seconds to wait before retrying"}}}}}},"InternalServerError":{"description":"Internal Server Error - An unexpected error occurred","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}}}},"paths":{"/api/v1/smart-money/netflow":{"post":{"tags":["Smart Money"],"summary":"Get Smart Money Netflow Data","description":"Analyze net capital flows (inflows vs outflows) from smart traders and funds across different time periods. This endpoint helps identify which tokens are experiencing net accumulation or distribution by smart money.\n\nWhat are Net Flows?\nNet flows represent the difference between smart money inflows and outflows for a token. This includes:\n\n- DEX Trading Activity: Tokens bought vs sold on decentralized exchanges\n- CEX Transfers: Tokens sent to or received from centralized exchanges\n- Positive Net Flow: Smart money is accumulating (buying more than selling, or withdrawing from CEXs)\n- Negative Net Flow: Smart money is distributing (selling more than buying, or depositing to CEXs)\n\nKey Features:\n\n- Aggregated net flow calculations across all smart money activity\n- Multiple time period analysis (24h, 7d, 30d)\n- Sortable results by volume metrics\n- Includes both DEX trades and CEX transfers","operationId":"get_smart_money_netflow_api_v1_smart_money_netflow_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SmartMoneyNetflowRequest"}}},"required":true},"responses":{"200":{"description":"Smart money netflow data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SmartMoneyNetflowResponse"}}}},"400":{"description":"Bad Request","$ref":"#/components/responses/BadRequestError"},"401":{"description":"Unauthorized","$ref":"#/components/responses/UnauthorizedError"},"403":{"description":"Forbidden","$ref":"#/components/responses/ForbiddenError"},"404":{"description":"Not Found","$ref":"#/components/responses/NotFoundError"},"422":{"description":"Unprocessable Content","$ref":"#/components/responses/ValidationError"},"429":{"description":"Too Many Requests","$ref":"#/components/responses/TooManyRequestsError"},"500":{"description":"Internal Server Error","$ref":"#/components/responses/InternalServerError"}}}}}} +``` + +### Next Steps + +1. **Checkout these Usecase Templates** + +{% content-ref url="use-case-templates" %} +[use-case-templates](https://docs.nansen.ai/getting-started/use-case-templates) +{% endcontent-ref %} + +2. **Checkout all the available endpoints** + +{% content-ref url="../api/smart-money" %} +[smart-money](https://docs.nansen.ai/api/smart-money) +{% endcontent-ref %} + +{% content-ref url="../api/token-god-mode" %} +[token-god-mode](https://docs.nansen.ai/api/token-god-mode) +{% endcontent-ref %} + +{% content-ref url="../api/profiler" %} +[profiler](https://docs.nansen.ai/api/profiler) +{% endcontent-ref %} + +{% content-ref url="../api/portfolio" %} +[portfolio](https://docs.nansen.ai/api/portfolio) +{% endcontent-ref %} + +api structure nd base url : +# API Structure & Base URL + +All interactions with the Nansen API V1 occur via HTTPS requests to specific endpoints. The general structure of an API call is: + +``` +HTTP Method + Base URL + Endpoint Path +``` + +* HTTP Method: Primarily ‎\`POST\` for retrieving data. +* Base URL: The root URL for all V1 API requests is: + +``` +https://api.nansen.ai/api/v1 +``` + +* Endpoint Path: The specific path identifying the resource and desired data, appended directly to the Base URL (e.g., ‎\`/smart-money/netflows\`). Endpoint paths for V1 resources are detailed within their respective sections of this documentation. +* Request Body: Parameters are typically passed in JSON format within the request body for POST requests. + + +authentication : +# Authentication + +The Nansen API uses API key-based authentication. All requests must include an API key provided in the request header for successful authentication. + +### Obtaining API Keys + +You can access the API Keys from [this link](https://app.nansen.ai/api) in account settings + +
+ +### Including Your API Key in Requests + +Add the following header to all API requests: + +| Header Name | Header Value | +| ----------- | -------------- | +| `apiKey` | `YOUR_API_KEY` | + +Replace `YOUR_API_KEY` with your actual API key. + + +responses and handling error : +# Understanding Responses and Handling Errors + +API responses are delivered in JSON format. The client applications must parse this JSON to extract the required data. Equally important is handling the HTTP status code returned with each response to determine success or failure. + +**Common HTTP Status Codes:** + +
Status CodeMeaningWhat to Do
400Bad Request: Malformed request, invalid parameters or formatCheck your request syntax and parameters
401Unauthorized: Authentication failed (missing, invalid, or expired token)Obtain or refresh your API Key
403Forbidden: Auth succeeded, but no permission for resourceEnsure your account has access rights
404Not Found: Resource or endpoint does not existVerify the endpoint path and resource identifiers
429Too Many Requests: Rate limit exceededSlow down requests; respect rate limits
500Internal Server Error: Unexpected server issueTry again later; contact support if persistent
504Gateway Timeout: Backend server did not respond in timeRetry after a short wait; check for heavy queries
+ +\\ + +api restructuing : +# 2025-08-29 - Major API Restructuring + +This changelog highlights the key architectural and structural differences between the beta endpoints and v1 endpoints, focusing on breaking changes that developers need to be aware of when migrating. + +#### 🔄 Version Update + +* **From**: Beta endpoints (`/api/beta/*`) +* **To**: v1 endpoints (`/api/v1/*`) + +#### 🏗️ **Major Structural Changes** + +#### 1. **Parameter Structure Overhaul** + +**Before (Beta): Nested Parameters Object** + +```json +{ + "parameters": { + "tokenAddress": "2zMMhcVQEXDtdE6vsFS7S7D5oUodfJHE8vd1gnBouauv", + "smFilter": ["180D Smart Trader"], + "chain": "solana" + }, + "pagination": { + "page": 1, + "recordsPerPage": 100 + } +} +``` + +**After (v1): Structured Request with Nested Filters** + +```json +{ + "chain": "solana", + "token_address": "2zMMhcVQEXDtdE6vsFS7S7D5oUodfJHE8vd1gnBouauv", + "filters": { + "smart_money": { + "include": ["180D Smart Trader"] + }, + "include_stablecoins": true, + "include_native_tokens": true + }, + "pagination": { + "page": 1, + "per_page": 100 + } +} +``` + +**Impact**: All existing client code must be restructured to remove the nested `parameters` wrapper. + +#### 2. **Naming Convention Changes** + +**Before (Beta): camelCase** + +* `tokenAddress` +* `includeStablecoin` + +**After (v1): snake\_case** + +* `tokenAddress →` token\_address\` +* `smFilter` → `filters.smart_money.include` (nested structure) +* `includeStablecoin` → `filters.include_stablecoins` + +**Impact**: Significant impact - all fields are changed to snake\_case + +#### 3. **Response Structure Standardization** + +**Before (Beta): camelCase Response Fields** + +```json +{ + "tokenAddress": "...", + "symbol": "...", + "marketCap": 1000000 +} +``` + +**After (v1): snake\_case Response Fields** + +```json +{ + "token_address": "...", + "symbol": "...", + "market_cap": 1000000 +} +``` + +**Note**: Not all v1 endpoints return pagination fields - some return data only while others include pagination metadata. When pagination is present, it now includes an `is_last_page` boolean for easier pagination handling. + +**Impact**: All client code must be updated to handle snake\_case field names in responses. + +#### 📋 **Renamed Endpoint** + +#### **Smart Money Endpoints** + +**`/beta/smart-money/inflows` → `/api/v1/smart-money/netflow`** + +#### **Profiler Endpoints** + +**`/beta/profiler/address/balances` → `/api/v1/profiler/address/current-balance`** + +#### 🚨 **Breaking Changes Summary** + +#### **Must Update**: + +1. **Remove nested `parameters` wrapper** from all requests +2. **Handle new response structure** with `data` and `pagination` fields +3. **Check parameter naming** for snake\_case vs camelCase changes + +### Endpoint Migration Map + +#### Smart Money Endpoints + +**`/api/beta/smart-money/inflows` → `/api/v1/smart-money/netflow`** + +**Changes:** + +* Renamed from "inflows" to "netflow" for clarity +* Request structure simplified (no `parameters` wrapper) +* Enhanced filtering capabilities +* Added comprehensive sorting options +* Response includes pagination metadata + +**New Features in V1:** + +* `remove_scam_tokens` filter +* `hide_spam_tokens` filter +* `token_sector` filter +* Custom sort ordering support + +**`/api/beta/smart-money/holdings` → `/api/v1/smart-money/holdings`** + +**Changes:** + +* Direct request body structure +* Enhanced response with pagination +* Improved filtering system +* Added sort customization + +**`/api/beta/smart-money/dex-trades` → `/api/v1/smart-money/dex-trades`** + +**Changes:** + +* Simplified request structure +* Added comprehensive trade filters +* Enhanced label filtering +* Improved response metadata + +**`/api/beta/smart-money/dcas` → `/api/v1/smart-money/dcas`** + +**Changes:** + +* Standardized request/response format +* Enhanced filtering for DCA parameters +* Added sort capabilities + +#### Wallet Profiler Endpoints + +**`/api/beta/profiler/address/transactions` → `/api/v1/profiler/address/transactions`** + +**Changes:** + +* Reduced max pagination from 100 to 20 records per page (performance optimization) +* Enhanced filtering for transaction types +* Added method and source type filters +* Improved token info structure + +**`/api/beta/profiler/address/balances` → `/api/v1/profiler/address/current-balance`** + +**Changes:** + +* Renamed for clarity (balances → current-balance) +* Enhanced filtering capabilities +* Added value range filters +* Improved chain support + +**`/api/beta/profiler/address/pnl` → `/api/v1/profiler/address/pnl`** + +**Changes:** + +* Simplified request structure +* Enhanced PnL calculation fields +* Added comprehensive filtering +* Improved sort options + +**`/api/beta/profiler/address/pnl-summary` → `/api/v1/profiler/address/pnl-summary`** + +**Changes:** + +* Standardized response format +* Enhanced top token structure +* Improved metadata + +**`/api/beta/profiler/address/counterparties` → `/api/v1/profiler/address/counterparties`** + +**Changes:** + +* Enhanced label filtering +* Added interaction count filters +* Improved volume filtering +* Better token info structure + +**`/api/beta/profiler/address/historical-balances` → `/api/v1/profiler/address/historical-balances`** + +**Changes:** + +* Standardized date range handling +* Enhanced spam token filtering +* Improved response structure + +**`/api/beta/profiler/address/related-wallets` → `/api/v1/profiler/address/related-wallets`** + +**Changes:** + +* Enhanced relationship metadata +* Added sort capabilities +* Improved response structure + +#### Token God Mode (TGM) Endpoints + +**`/api/beta/tgm/dex-trades` → `/api/v1/tgm/dex-trades`** + +**Changes:** + +* Enhanced filtering system +* Added action filters (buy/sell) +* Improved trader label filtering +* Better value range filters + +**`/api/beta/tgm/transfers` → `/api/v1/tgm/transfers`** + +**Changes:** + +* Enhanced transfer type filtering +* Added CEX/DEX inclusion controls +* Improved smart money filtering +* Better address label filtering + +**`/api/beta/tgm/holders` → `/api/v1/tgm/holders`** + +**Changes:** + +* Simplified label type handling +* Enhanced balance change tracking +* Added ownership percentage filters +* Improved sort capabilities + +**`/api/beta/tgm/flows` → `/api/v1/tgm/flows`** + +**Changes:** + +* Enhanced flow tracking +* Added holder statistics +* Improved time-based analysis +* Better sort options + +**`/api/beta/tgm/pnl-leaderboard` → `/api/v1/tgm/pnl-leaderboard`** + +**Changes:** + +* Enhanced PnL metrics +* Added ROI calculations +* Improved trader filtering +* Better sort capabilities + +**`/api/beta/tgm/who-bought-sold` → `/api/v1/tgm/who-bought-sold`** + +**Changes:** + +* Enhanced volume tracking +* Added trade direction analysis +* Improved label filtering + +**`/api/beta/tgm/jup-dca` → `/api/v1/tgm/jup-dca`** + +**Changes:** + +* Standardized DCA vault tracking +* Enhanced status filtering +* Improved deposit tracking + +**`/api/beta/tgm/flow-intelligence` → `/api/v1/tgm/flow-intelligence`** + +**Changes:** + +* Enhanced category tracking +* Added wallet count metrics +* Improved flow analysis + +#### New V1-Only Endpoints + +**`/api/v1/portfolio/defi-holdings`** + +* Production-ready DeFi portfolio tracking +* Comprehensive protocol breakdown +* Asset/debt/reward categorization + +**`/api/v1/transaction-with-token-transfer-lookup`** + +* Enhanced transaction lookup +* NFT transfer support +* Comprehensive token transfer tracking + +**`/api/v1/token-screener`** + +* Advanced token discovery +* Multi-chain screening +* Comprehensive filtering system +* Smart money integration + +netflow : +# Netflows + +## Get Smart Money Netflow Data + +> Analyze net capital flows (inflows vs outflows) from smart traders and funds across different time periods. This endpoint helps identify which tokens are experiencing net accumulation or distribution by smart money.\ +> \ +> What are Net Flows?\ +> Net flows represent the difference between smart money inflows and outflows for a token. This includes:\ +> \ +> \- DEX Trading Activity: Tokens bought vs sold on decentralized exchanges\ +> \- CEX Transfers: Tokens sent to or received from centralized exchanges\ +> \- Positive Net Flow: Smart money is accumulating (buying more than selling, or withdrawing from CEXs)\ +> \- Negative Net Flow: Smart money is distributing (selling more than buying, or depositing to CEXs)\ +> \ +> Key Features:\ +> \ +> \- Aggregated net flow calculations across all smart money activity\ +> \- Multiple time period analysis (24h, 7d, 30d)\ +> \- Sortable results by volume metrics\ +> \- Includes both DEX trades and CEX transfers + +```json +{"openapi":"3.1.0","info":{"title":"Nansen API","version":"1.0.0"},"tags":[{"name":"Smart Money","description":"Smart money analytics and insights"}],"servers":[{"url":"https://api.nansen.ai","description":"Production server"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"apiKey","description":"API key for authentication"}},"schemas":{"SmartMoneyNetflowRequest":{"properties":{"chains":{"items":{"$ref":"#/components/schemas/SmartMoneyChain"},"type":"array","title":"Chains","description":"Chains to include in the analysis (only smart money supported chains). Use 'all' to include all available chains."},"filters":{"anyOf":[{"$ref":"#/components/schemas/SmartMoneyNetflowFilters"}],"description":"Additional filters to apply. Only filters for columns that are being selected will be applied."},"pagination":{"$ref":"#/components/schemas/PaginationRequest","description":"Pagination parameters"},"order_by":{"anyOf":[{"items":{"$ref":"#/components/schemas/SortOrder_SmartMoneyNetflowSortField_"},"type":"array"}],"title":"Order By","description":"Custom sort order to override the endpoint's default ordering.\n\nExamples:\n- [{\"field\": \"market_cap_usd\", \"direction\": \"DESC\"}] - Sort by market cap descending\n- [{\"field\": \"net_flow_24h_usd\", \"direction\": \"ASC\"}] - Sort by 24h flow ascending\n- [{\"field\": \"market_cap_usd\", \"direction\": \"DESC\"}, {\"field\": \"net_flow_24h_usd\", \"direction\": \"ASC\"}] - Sort by market cap descending, then 24h flow ascending"}},"additionalProperties":false,"type":"object","required":["chains"],"title":"SmartMoneyNetflowRequest","description":""},"SmartMoneyChain":{"type":"string","enum":["all","arbitrum","avalanche","base","berachain","blast","bnb","ethereum","goat","hyperevm","iotaevm","linea","mantle","optimism","plasma","polygon","ronin","sei","scroll","sonic","unichain","zksync","solana"],"title":"SmartMoneyChain","description":"Enum for chains supported in smart money analysis."},"SmartMoneyNetflowFilters":{"properties":{"include_smart_money_labels":{"anyOf":[{"items":{"$ref":"#/components/schemas/SmartMoneyFilterType"},"type":"array"}],"title":"Include Smart Money Labels","description":"Smart money category filters"},"exclude_smart_money_labels":{"anyOf":[{"items":{"$ref":"#/components/schemas/SmartMoneyFilterType"},"type":"array"}],"title":"Exclude Smart Money Labels","description":"Smart money category filters"},"token_address":{"anyOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Token Address","description":"Token address or symbol filter"},"include_stablecoins":{"anyOf":[{"type":"boolean"}],"title":"Include Stablecoins","description":"Whether to include stablecoins in the results","default":false},"include_native_tokens":{"anyOf":[{"type":"boolean"}],"title":"Include Native Tokens","description":"Whether to include native tokens (e.g., ETH, SOL) in the results","default":false},"token_sector":{"anyOf":[{"items":{"type":"string"},"type":"array"}],"title":"Token Sector","description":"Token sector filter"},"trader_count":{"anyOf":[{"$ref":"#/components/schemas/NumericRangeFilter"}],"description":"Trader count range filter"},"token_age_days":{"anyOf":[{"$ref":"#/components/schemas/NumericRangeFilter"}],"description":"Token age range filter in days"},"market_cap_usd":{"anyOf":[{"$ref":"#/components/schemas/NumericRangeFilter"}],"description":"Market cap range filter in USD"}},"additionalProperties":false,"type":"object","title":"SmartMoneyNetflowFilters","description":"Filters for smart money netflow endpoint.\n\nThese filters control which smart money categories, tokens, and data\nare included in the netflow analysis."},"SmartMoneyFilterType":{"type":"string","enum":["Fund","Smart Trader","30D Smart Trader","90D Smart Trader","180D Smart Trader"],"title":"SmartMoneyFilterType","description":"Enum for smart money filter options."},"NumericRangeFilter":{"properties":{"min":{"anyOf":[{"type":"number"}],"title":"Min","description":"Minimum value (inclusive)"},"max":{"anyOf":[{"type":"number"}],"title":"Max","description":"Maximum value (inclusive)"}},"type":"object","title":"NumericRangeFilter","description":"Filter for numeric values (floats) with optional min/max bounds.\nUse for prices, volumes, ratios, and other decimal values. - Values between -10.5 and 100.75"},"PaginationRequest":{"properties":{"page":{"type":"integer","minimum":1,"title":"Page","description":"Page number (1-based)","default":1},"per_page":{"type":"integer","maximum":1000,"minimum":1,"title":"Per Page","description":"Number of records per page (max 1000)","default":10}},"type":"object","title":"PaginationRequest","description":"Pagination parameters for API requests."},"SortOrder_SmartMoneyNetflowSortField_":{"properties":{"field":{"$ref":"#/components/schemas/SmartMoneyNetflowSortField","description":"Field to sort by"},"direction":{"$ref":"#/components/schemas/SortDirection","description":"Sort direction (ASC or DESC)"}},"type":"object","required":["field","direction"],"title":"SortOrder[SmartMoneyNetflowSortField]"},"SmartMoneyNetflowSortField":{"type":"string","enum":["chain","token_address","token_symbol","net_flow_24h_usd","net_flow_7d_usd","net_flow_30d_usd","token_sectors","trader_count","token_age_days","market_cap_usd"],"title":"SmartMoneyNetflowSortField","description":"Enum for sortable fields in smart money netflow."},"SortDirection":{"type":"string","enum":["ASC","DESC"],"title":"SortDirection","description":"Enum for sort directions."},"SmartMoneyNetflowResponse":{"properties":{"data":{"items":{"$ref":"#/components/schemas/SmartMoneyNetflow"},"type":"array","title":"Data","description":"List of smart money netflow records"},"pagination":{"$ref":"#/components/schemas/PaginationInfo","description":"Pagination information"}},"type":"object","required":["data","pagination"],"title":"SmartMoneyNetflowResponse","description":"Response model for smart money netflow endpoint.\n\nContains the filtered smart money netflow data with metadata."},"SmartMoneyNetflow":{"properties":{"token_address":{"type":"string","title":"Token Address","description":"Token contract address"},"token_symbol":{"type":"string","title":"Token Symbol","description":"Token symbol"},"net_flow_24h_usd":{"type":"number","title":"Net Flow 24H Usd","description":"Net flow bought/sold of token by Smart Money in the past 24 hours."},"net_flow_7d_usd":{"type":"number","title":"Net Flow 7D Usd","description":"Net flow bought/sold of token by Smart Money in the past 7 days."},"net_flow_30d_usd":{"type":"number","title":"Net Flow 30D Usd","description":"Net flow bought/sold of token by Smart Money in the past 30 days."},"chain":{"type":"string","title":"Chain","description":"Blockchain chain"},"token_sectors":{"items":{"type":"string"},"type":"array","title":"Token Sectors","description":"Token sectors"},"trader_count":{"type":"integer","title":"Trader Count","description":"Number of Smart Money traders of token in the past 30 days."},"token_age_days":{"type":"integer","title":"Token Age Days","description":"Number of days since token was deployed."},"market_cap_usd":{"anyOf":[{"type":"number"}],"title":"Market Cap Usd","description":"Market cap of token."}},"type":"object","required":["token_address","token_symbol","net_flow_24h_usd","net_flow_7d_usd","net_flow_30d_usd","chain","token_sectors","trader_count","token_age_days"],"title":"SmartMoneyNetflow","description":"Individual smart money netflow record.\n\nRepresents a single token's smart money netflow data."},"PaginationInfo":{"properties":{"page":{"type":"integer","minimum":1,"title":"Page","description":"Current page number","default":1},"per_page":{"type":"integer","maximum":1000,"minimum":1,"title":"Per Page","description":"Number of records per page","default":10},"is_last_page":{"type":"boolean","title":"Is Last Page","description":"Whether this is the last page","default":true}},"type":"object","title":"PaginationInfo","description":"Pagination information for API responses."}},"responses":{"BadRequestError":{"description":"Bad Request - Invalid request parameters or malformed request","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"UnauthorizedError":{"description":"Authentication error - No API key found in request","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"ForbiddenError":{"description":"Forbidden - User does not have required subscription tier","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"NotFoundError":{"description":"Not Found - The requested resource was not found","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"ValidationError":{"description":"Validation error - Invalid request parameters","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"loc":{"type":"array","items":{"type":"string"}},"msg":{"type":"string"},"type":{"type":"string"}}}}}}}}},"TooManyRequestsError":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"},"retry_after":{"type":"integer","description":"Seconds to wait before retrying"}}}}}},"InternalServerError":{"description":"Internal Server Error - An unexpected error occurred","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}}}},"paths":{"/api/v1/smart-money/netflow":{"post":{"tags":["Smart Money"],"summary":"Get Smart Money Netflow Data","description":"Analyze net capital flows (inflows vs outflows) from smart traders and funds across different time periods. This endpoint helps identify which tokens are experiencing net accumulation or distribution by smart money.\n\nWhat are Net Flows?\nNet flows represent the difference between smart money inflows and outflows for a token. This includes:\n\n- DEX Trading Activity: Tokens bought vs sold on decentralized exchanges\n- CEX Transfers: Tokens sent to or received from centralized exchanges\n- Positive Net Flow: Smart money is accumulating (buying more than selling, or withdrawing from CEXs)\n- Negative Net Flow: Smart money is distributing (selling more than buying, or depositing to CEXs)\n\nKey Features:\n\n- Aggregated net flow calculations across all smart money activity\n- Multiple time period analysis (24h, 7d, 30d)\n- Sortable results by volume metrics\n- Includes both DEX trades and CEX transfers","operationId":"get_smart_money_netflow_api_v1_smart_money_netflow_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SmartMoneyNetflowRequest"}}},"required":true},"responses":{"200":{"description":"Smart money netflow data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SmartMoneyNetflowResponse"}}}},"400":{"description":"Bad Request","$ref":"#/components/responses/BadRequestError"},"401":{"description":"Unauthorized","$ref":"#/components/responses/UnauthorizedError"},"403":{"description":"Forbidden","$ref":"#/components/responses/ForbiddenError"},"404":{"description":"Not Found","$ref":"#/components/responses/NotFoundError"},"422":{"description":"Unprocessable Content","$ref":"#/components/responses/ValidationError"},"429":{"description":"Too Many Requests","$ref":"#/components/responses/TooManyRequestsError"},"500":{"description":"Internal Server Error","$ref":"#/components/responses/InternalServerError"}}}}}} +``` +holdings : +# Holdings + +## Get Smart Money Holdings Data + +> Retrieve aggregated token balances held by smart traders and funds across multiple blockchains. This endpoint provides insights into what tokens are being accumulated by sophisticated market participants, excluding whales, large holders, and influencers to focus specifically on trading expertise.\ +> \ +> Key Features:\ +> \ +> \- Aggregated balances (not per-wallet breakdowns)\ +> \- 24-hour balance change tracking updated in realtime\ +> \- Sector categorization for tokens + +```json +{"openapi":"3.1.0","info":{"title":"Nansen API","version":"1.0.0"},"tags":[{"name":"Smart Money","description":"Smart money analytics and insights"}],"servers":[{"url":"https://api.nansen.ai","description":"Production server"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"apiKey","description":"API key for authentication"}},"schemas":{"SmartMoneyHoldingsRequest":{"properties":{"chains":{"items":{"$ref":"#/components/schemas/SmartMoneyChain"},"type":"array","title":"Chains","description":"Chains to include in the analysis (only smart money supported chains). Use 'all' to include all available chains."},"filters":{"anyOf":[{"$ref":"#/components/schemas/SmartMoneyHoldingsFilters"}],"description":"Additional filters to apply. Only filters for columns that are being selected will be applied."},"pagination":{"$ref":"#/components/schemas/PaginationRequest","description":"Pagination parameters"},"order_by":{"anyOf":[{"items":{"$ref":"#/components/schemas/SortOrder_SmartMoneyHoldingsSortField_"},"type":"array"}],"title":"Order By","description":"Custom sort order to override the endpoint's default ordering.\n\nExamples:\n- [{\"field\": \"value_usd\", \"direction\": \"DESC\"}] - Sort by value USD descending\n- [{\"field\": \"holders_count\", \"direction\": \"ASC\"}] - Sort by number of holders ascending\n- [{\"field\": \"value_usd\", \"direction\": \"DESC\"}, {\"field\": \"holders_count\", \"direction\": \"ASC\"}] - Sort by value USD descending, then number of holders ascending"}},"additionalProperties":false,"type":"object","required":["chains"],"title":"SmartMoneyHoldingsRequest","description":""},"SmartMoneyChain":{"type":"string","enum":["all","arbitrum","avalanche","base","berachain","blast","bnb","ethereum","goat","hyperevm","iotaevm","linea","mantle","optimism","plasma","polygon","ronin","sei","scroll","sonic","unichain","zksync","solana"],"title":"SmartMoneyChain","description":"Enum for chains supported in smart money analysis."},"SmartMoneyHoldingsFilters":{"properties":{"include_smart_money_labels":{"anyOf":[{"items":{"$ref":"#/components/schemas/SmartMoneyFilterType"},"type":"array"}],"title":"Include Smart Money Labels","description":"Smart money category filters"},"exclude_smart_money_labels":{"anyOf":[{"items":{"$ref":"#/components/schemas/SmartMoneyFilterType"},"type":"array"}],"title":"Exclude Smart Money Labels","description":"Smart money category filters"},"include_stablecoins":{"anyOf":[{"type":"boolean"}],"title":"Include Stablecoins","description":"Whether to include stablecoins in the results","default":false},"include_native_tokens":{"anyOf":[{"type":"boolean"}],"title":"Include Native Tokens","description":"Whether to include native tokens (e.g., ETH, SOL) in the results","default":false},"value_usd":{"anyOf":[{"$ref":"#/components/schemas/NumericRangeFilter"}],"description":"Value range filter in USD"},"balance_24h_percent_change":{"anyOf":[{"$ref":"#/components/schemas/NumericRangeFilter"}],"description":"24-hour balance change percentage range filter"},"holders_count":{"anyOf":[{"$ref":"#/components/schemas/IntegerRangeFilter"}],"description":"Number of holders range filter"},"share_of_holdings_percent":{"anyOf":[{"$ref":"#/components/schemas/NumericRangeFilter"}],"description":"Share of holdings percentage range filter"},"token_age_days":{"anyOf":[{"$ref":"#/components/schemas/NumericRangeFilter"}],"description":"Token age range filter in days"},"market_cap_usd":{"anyOf":[{"$ref":"#/components/schemas/NumericRangeFilter"}],"description":"Market cap range filter in USD"},"token_address":{"anyOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Token Address","description":"Token address filter"},"token_symbol":{"anyOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Token Symbol","description":"Token symbol filter"},"token_sectors":{"anyOf":[{"items":{"type":"string"},"type":"array"}],"title":"Token Sectors","description":"Token sectors filter"}},"additionalProperties":false,"type":"object","title":"SmartMoneyHoldingsFilters","description":"Filters for smart money holdings endpoint.\n\nThese filters control which token holdings, smart money categories,\nand data are included in the holdings analysis."},"SmartMoneyFilterType":{"type":"string","enum":["Fund","Smart Trader","30D Smart Trader","90D Smart Trader","180D Smart Trader"],"title":"SmartMoneyFilterType","description":"Enum for smart money filter options."},"NumericRangeFilter":{"properties":{"min":{"anyOf":[{"type":"number"}],"title":"Min","description":"Minimum value (inclusive)"},"max":{"anyOf":[{"type":"number"}],"title":"Max","description":"Maximum value (inclusive)"}},"type":"object","title":"NumericRangeFilter","description":"Filter for numeric values (floats) with optional min/max bounds.\nUse for prices, volumes, ratios, and other decimal values. - Values between -10.5 and 100.75"},"IntegerRangeFilter":{"properties":{"min":{"anyOf":[{"type":"integer"}],"title":"Min","description":"Minimum value (inclusive)"},"max":{"anyOf":[{"type":"integer"}],"title":"Max","description":"Maximum value (inclusive)"}},"type":"object","title":"IntegerRangeFilter","description":"Filter for integer values with optional min/max bounds.\nUse for counts, numbers of items, and other whole number values. - Values between 5 and 100"},"PaginationRequest":{"properties":{"page":{"type":"integer","minimum":1,"title":"Page","description":"Page number (1-based)","default":1},"per_page":{"type":"integer","maximum":1000,"minimum":1,"title":"Per Page","description":"Number of records per page (max 1000)","default":10}},"type":"object","title":"PaginationRequest","description":"Pagination parameters for API requests."},"SortOrder_SmartMoneyHoldingsSortField_":{"properties":{"field":{"$ref":"#/components/schemas/SmartMoneyHoldingsSortField","description":"Field to sort by"},"direction":{"$ref":"#/components/schemas/SortDirection","description":"Sort direction (ASC or DESC)"}},"type":"object","required":["field","direction"],"title":"SortOrder[SmartMoneyHoldingsSortField]"},"SmartMoneyHoldingsSortField":{"type":"string","enum":["chain","token_address","token_symbol","value_usd","balance_24h_percent_change","holders_count","share_of_holdings_percent","token_age_days","market_cap_usd"],"title":"SmartMoneyHoldingsSortField","description":"Enum for sortable fields in smart money holdings."},"SortDirection":{"type":"string","enum":["ASC","DESC"],"title":"SortDirection","description":"Enum for sort directions."},"SmartMoneyHoldingsResponse":{"properties":{"data":{"items":{"$ref":"#/components/schemas/SmartMoneyHolding"},"type":"array","title":"Data","description":"List of smart money holding records"},"pagination":{"$ref":"#/components/schemas/PaginationInfo","description":"Pagination information"}},"type":"object","required":["data","pagination"],"title":"SmartMoneyHoldingsResponse","description":"Response model for smart money holdings endpoint.\n\nContains the filtered smart money holdings data with metadata."},"SmartMoneyHolding":{"properties":{"chain":{"$ref":"#/components/schemas/SmartMoneyChain","description":"Chain name"},"token_address":{"type":"string","title":"Token Address","description":"Address of token"},"token_symbol":{"type":"string","title":"Token Symbol","description":"Token symbol"},"token_sectors":{"items":{"type":"string"},"type":"array","title":"Token Sectors","description":"Token sectors"},"value_usd":{"anyOf":[{"type":"number"}],"title":"Value Usd","description":"Value of token held by Smart Money."},"balance_24h_percent_change":{"anyOf":[{"type":"number"}],"title":"Balance 24H Percent Change","description":"Balance change of Smart Money for token during the last 24 hours"},"holders_count":{"type":"integer","title":"Holders Count","description":"Number of Smart Money holders of token."},"share_of_holdings_percent":{"anyOf":[{"type":"number"}],"title":"Share Of Holdings Percent","description":"Share of Smart Money total USD balance."},"token_age_days":{"type":"integer","title":"Token Age Days","description":"Number of days since token was deployed."},"market_cap_usd":{"anyOf":[{"type":"number"}],"title":"Market Cap Usd","description":"Market cap of token."}},"type":"object","required":["chain","token_address","token_symbol","token_sectors","holders_count","token_age_days"],"title":"SmartMoneyHolding","description":"Individual smart money holding record.\n\nRepresents a single token's smart money holding data."},"PaginationInfo":{"properties":{"page":{"type":"integer","minimum":1,"title":"Page","description":"Current page number","default":1},"per_page":{"type":"integer","maximum":1000,"minimum":1,"title":"Per Page","description":"Number of records per page","default":10},"is_last_page":{"type":"boolean","title":"Is Last Page","description":"Whether this is the last page","default":true}},"type":"object","title":"PaginationInfo","description":"Pagination information for API responses."}},"responses":{"BadRequestError":{"description":"Bad Request - Invalid request parameters or malformed request","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"UnauthorizedError":{"description":"Authentication error - No API key found in request","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"ForbiddenError":{"description":"Forbidden - User does not have required subscription tier","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"NotFoundError":{"description":"Not Found - The requested resource was not found","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"ValidationError":{"description":"Validation error - Invalid request parameters","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"loc":{"type":"array","items":{"type":"string"}},"msg":{"type":"string"},"type":{"type":"string"}}}}}}}}},"TooManyRequestsError":{"description":"Too Many Requests - Rate limit +exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"},"retry_after":{"type":"integer","description":"Seconds to wait before retrying"}}}}}},"InternalServerError":{"description":"Internal Server Error - An unexpected error occurred","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}}}},"paths":{"/api/v1/smart-money/holdings":{"post":{"tags":["Smart Money"],"summary":"Get Smart Money Holdings Data","description":"Retrieve aggregated token balances held by smart traders and funds across multiple blockchains. This endpoint provides insights into what tokens are being accumulated by sophisticated market participants, excluding whales, large holders, and influencers to focus specifically on trading expertise.\n\nKey Features:\n\n- Aggregated balances (not per-wallet breakdowns)\n- 24-hour balance change tracking updated in realtime\n- Sector categorization for tokens","operationId":"get_smart_money_holdings_api_v1_smart_money_holdings_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SmartMoneyHoldingsRequest"}}},"required":true},"responses":{"200":{"description":"Smart money holdings data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SmartMoneyHoldingsResponse"}}}},"400":{"description":"Bad Request","$ref":"#/components/responses/BadRequestError"},"401":{"description":"Unauthorized","$ref":"#/components/responses/UnauthorizedError"},"403":{"description":"Forbidden","$ref":"#/components/responses/ForbiddenError"},"404":{"description":"Not Found","$ref":"#/components/responses/NotFoundError"},"422":{"description":"Unprocessable Content","$ref":"#/components/responses/ValidationError"},"429":{"description":"Too Many Requests","$ref":"#/components/responses/TooManyRequestsError"},"500":{"description":"Internal Server Error","$ref":"#/components/responses/InternalServerError"}}}}}} +``` + +dex trades : +# DEX Trades + +## Get Smart Money DEX Trades Data + +> Access real-time DEX trading activity from smart traders and funds over the last 24 hours. This endpoint provides granular transaction-level data showing exactly what sophisticated traders are buying and selling on decentralized exchanges. + +```json +{"openapi":"3.1.0","info":{"title":"Nansen API","version":"1.0.0"},"tags":[{"name":"Smart Money","description":"Smart money analytics and insights"}],"servers":[{"url":"https://api.nansen.ai","description":"Production server"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"apiKey","description":"API key for authentication"}},"schemas":{"SmartMoneyDexTradesRequest":{"properties":{"chains":{"items":{"$ref":"#/components/schemas/SmartMoneyChain"},"type":"array","title":"Chains","description":"Chains to include in the analysis (only smart money supported chains). Use 'all' to include all available chains."},"filters":{"anyOf":[{"$ref":"#/components/schemas/SmartMoneyDexTradesFilters"}],"description":"Additional filters to apply. Only filters for columns that are being selected will be applied."},"pagination":{"$ref":"#/components/schemas/PaginationRequest","description":"Pagination parameters"},"order_by":{"anyOf":[{"items":{"$ref":"#/components/schemas/SortOrder_SmartMoneyDexTradesSortField_"},"type":"array"}],"title":"Order By","description":"Custom sort order to override the endpoint's default ordering.\n\nExamples:\n- [{\"field\": \"trade_value_in_usd\", \"direction\": \"DESC\"}] - Sort by trade value descending\n- [{\"field\": \"block_timestamp\", \"direction\": \"ASC\"}] - Sort by timestamp ascending\n- [{\"field\": \"token_bought_amount\", \"direction\": \"DESC\"}, {\"field\": \"block_timestamp\", \"direction\": \"ASC\"}] - Sort by bought amount descending, then timestamp ascending"}},"additionalProperties":false,"type":"object","required":["chains"],"title":"SmartMoneyDexTradesRequest","description":""},"SmartMoneyChain":{"type":"string","enum":["all","arbitrum","avalanche","base","berachain","blast","bnb","ethereum","goat","hyperevm","iotaevm","linea","mantle","optimism","plasma","polygon","ronin","sei","scroll","sonic","unichain","zksync","solana"],"title":"SmartMoneyChain","description":"Enum for chains supported in smart money analysis."},"SmartMoneyDexTradesFilters":{"properties":{"include_smart_money_labels":{"anyOf":[{"items":{"$ref":"#/components/schemas/SmartMoneyFilterType"},"type":"array"}],"title":"Include Smart Money Labels","description":"Smart money category filters"},"exclude_smart_money_labels":{"anyOf":[{"items":{"$ref":"#/components/schemas/SmartMoneyFilterType"},"type":"array"}],"title":"Exclude Smart Money Labels","description":"Smart money category filters"},"chain":{"anyOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Chain","description":"Blockchain network filter"},"transaction_hash":{"anyOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Transaction Hash","description":"Transaction hash filter"},"trader_address":{"anyOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Trader Address","description":"Trader address filter"},"trader_address_label":{"anyOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Trader Address Label","description":"Trader name or label filter"},"token_bought_address":{"anyOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Token Bought Address","description":"Token address filter for bought tokens"},"token_sold_address":{"anyOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Token Sold Address","description":"Token address filter for sold tokens"},"token_bought_amount":{"anyOf":[{"$ref":"#/components/schemas/NumericRangeFilter"}],"description":"Amount range filter for bought tokens"},"token_sold_amount":{"anyOf":[{"$ref":"#/components/schemas/NumericRangeFilter"}],"description":"Amount range filter for sold tokens"},"token_bought_symbol":{"anyOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Token Bought Symbol","description":"Symbol filter for bought tokens"},"token_sold_symbol":{"anyOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Token Sold Symbol","description":"Symbol filter for sold tokens"},"token_bought_age_days":{"anyOf":[{"$ref":"#/components/schemas/NumericRangeFilter"}],"description":"Age range filter for bought tokens in days"},"token_sold_age_days":{"anyOf":[{"$ref":"#/components/schemas/NumericRangeFilter"}],"description":"Age range filter for sold tokens in days"},"token_bought_market_cap":{"anyOf":[{"$ref":"#/components/schemas/NumericRangeFilter"}],"description":"Market cap range filter for bought tokens"},"token_sold_market_cap":{"anyOf":[{"$ref":"#/components/schemas/NumericRangeFilter"}],"description":"Market cap range filter for sold tokens"},"trade_value_usd":{"anyOf":[{"$ref":"#/components/schemas/NumericRangeFilter"}],"description":"Trade value range filter in USD"}},"additionalProperties":false,"type":"object","title":"SmartMoneyDexTradesFilters","description":"Filters for smart money DEX trades endpoint.\n\nThese filters control which DEX trades, tokens, and traders\nare included in the trades analysis."},"SmartMoneyFilterType":{"type":"string","enum":["Fund","Smart Trader","30D Smart Trader","90D Smart Trader","180D Smart Trader"],"title":"SmartMoneyFilterType","description":"Enum for smart money filter options."},"NumericRangeFilter":{"properties":{"min":{"anyOf":[{"type":"number"}],"title":"Min","description":"Minimum value (inclusive)"},"max":{"anyOf":[{"type":"number"}],"title":"Max","description":"Maximum value (inclusive)"}},"type":"object","title":"NumericRangeFilter","description":"Filter for numeric values (floats) with optional min/max bounds.\nUse for prices, volumes, ratios, and other decimal values. - Values between -10.5 and 100.75"},"PaginationRequest":{"properties":{"page":{"type":"integer","minimum":1,"title":"Page","description":"Page number (1-based)","default":1},"per_page":{"type":"integer","maximum":1000,"minimum":1,"title":"Per Page","description":"Number of records per page (max 1000)","default":10}},"type":"object","title":"PaginationRequest","description":"Pagination parameters for API requests."},"SortOrder_SmartMoneyDexTradesSortField_":{"properties":{"field":{"$ref":"#/components/schemas/SmartMoneyDexTradesSortField","description":"Field to sort by"},"direction":{"$ref":"#/components/schemas/SortDirection","description":"Sort direction (ASC or DESC)"}},"type":"object","required":["field","direction"],"title":"SortOrder[SmartMoneyDexTradesSortField]"},"SmartMoneyDexTradesSortField":{"type":"string","enum":["chain","block_timestamp","transaction_hash","trader_address","trader_address_label","token_bought_address","token_sold_address","token_bought_amount","token_sold_amount","token_bought_symbol","token_sold_symbol","token_bought_age_days","token_sold_age_days","token_bought_market_cap","token_sold_market_cap","trade_value_usd"],"title":"SmartMoneyDexTradesSortField","description":"Enum for sortable fields in smart money dex trades."},"SortDirection":{"type":"string","enum":["ASC","DESC"],"title":"SortDirection","description":"Enum for sort directions."},"SmartMoneyDexTradesResponse":{"properties":{"data":{"items":{"$ref":"#/components/schemas/SmartMoneyDexTrade"},"type":"array","title":"Data","description":"List of smart money dex trade records"},"pagination":{"$ref":"#/components/schemas/PaginationInfo","description":"Pagination information"}},"type":"object","required":["data","pagination"],"title":"SmartMoneyDexTradesResponse","description":"Response model for smart money dex trades endpoint.\n\nContains the filtered smart money dex trades data with metadata."},"SmartMoneyDexTrade":{"properties":{"chain":{"type":"string","title":"Chain","description":"Blockchain chain"},"block_timestamp":{"type":"string","title":"Block Timestamp","description":"Block timestamp of the trade"},"transaction_hash":{"type":"string","title":"Transaction Hash","description":"Transaction hash"},"trader_address":{"type":"string","title":"Trader Address","description":"Hexadecimal representation of the trader's address, i.e. the signer of the transaction"},"trader_address_label":{"type":"string","title":"Trader Address Label","description":"Name of the trader, based on nansen_label"},"token_bought_address":{"type":"string","title":"Token Bought Address","description":"Hexadecimal representation of the bought token's address"},"token_sold_address":{"type":"string","title":"Token Sold Address","description":"Hexadecimal representation of the sold token's address"},"token_bought_amount":{"anyOf":[{"type":"number"}],"title":"Token Bought Amount","description":"Amount of token bought in decimal amount"},"token_sold_amount":{"anyOf":[{"type":"number"}],"title":"Token Sold Amount","description":"Amount of token sold in decimal amount"},"token_bought_symbol":{"type":"string","title":"Token Bought Symbol","description":"Symbol of the bought token"},"token_sold_symbol":{"type":"string","title":"Token Sold Symbol","description":"Symbol of the sold token"},"token_bought_age_days":{"type":"integer","title":"Token Bought Age Days","description":"Age of bought token's address in days"},"token_sold_age_days":{"type":"integer","title":"Token Sold Age Days","description":"Age of sold token's address in days"},"token_bought_market_cap":{"anyOf":[{"type":"number"}],"title":"Token Bought Market Cap","description":"Market cap of bought token's address in usd"},"token_sold_market_cap":{"anyOf":[{"type":"number"}],"title":"Token Sold Market Cap","description":"Market cap of sold token's address in usd"},"trade_value_usd":{"anyOf":[{"type":"number"}],"title":"Trade Value Usd","description":"Either token_bought_in_usd or token_sold_in_usd, if token_bought_in_usd is 0"}},"type":"object","required":["chain","block_timestamp","transaction_hash","trader_address","trader_address_label","token_bought_address","token_sold_address","token_bought_symbol","token_sold_symbol","token_bought_age_days","token_sold_age_days"],"title":"SmartMoneyDexTrade","description":"Individual smart money dex trade record.\n\nRepresents a single DEX trade made by smart money wallets."},"PaginationInfo":{"properties":{"page":{"type":"integer","minimum":1,"title":"Page","description":"Current page number","default":1},"per_page":{"type":"integer","maximum":1000,"minimum":1,"title":"Per Page","description":"Number of records per page","default":10},"is_last_page":{"type":"boolean","title":"Is Last Page","description":"Whether this is the last page","default":true}},"type":"object","title":"PaginationInfo","description":"Pagination information for API responses."}},"responses":{"BadRequestError":{"description":"Bad Request - Invalid request parameters or malformed request","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"UnauthorizedError":{"description":"Authentication error - No API key found in request","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"ForbiddenError":{"description":"Forbidden - User does not have required subscription tier","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"NotFoundError":{"description":"Not Found - The requested resource was not found","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"ValidationError":{"description":"Validation error - Invalid request parameters","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"loc":{"type":"array","items":{"type":"string"}},"msg":{"type":"string"},"type":{"type":"string"}}}}}}}}},"TooManyRequestsError":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"},"retry_after":{"type":"integer","description":"Seconds to wait before retrying"}}}}}},"InternalServerError":{"description":"Internal Server Error - An unexpected error occurred","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}}}},"paths":{"/api/v1/smart-money/dex-trades":{"post":{"tags":["Smart Money"],"summary":"Get Smart Money DEX Trades Data","description":"Access real-time DEX trading activity from smart traders and funds over the last 24 hours. This endpoint provides granular transaction-level data showing exactly what sophisticated traders are buying and selling on decentralized exchanges.","operationId":"get_smart_money_dex_trades_api_v1_smart_money_dex_trades_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SmartMoneyDexTradesRequest"}}},"required":true},"responses":{"200":{"description":"Smart money DEX trades data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SmartMoneyDexTradesResponse"}}}},"400":{"description":"Bad Request","$ref":"#/components/responses/BadRequestError"},"401":{"description":"Unauthorized","$ref":"#/components/responses/UnauthorizedError"},"403":{"description":"Forbidden","$ref":"#/components/responses/ForbiddenError"},"404":{"description":"Not Found","$ref":"#/components/responses/NotFoundError"},"422":{"description":"Unprocessable Content","$ref":"#/components/responses/ValidationError"},"429":{"description":"Too Many Requests","$ref":"#/components/responses/TooManyRequestsError"},"500":{"description":"Internal Server Error","$ref":"#/components/responses/InternalServerError"}}}}}} +``` + +jupiter dcas : +# Jupiter DCAs + +## Get Smart Money DCAs Data + +> Monitor DCA strategies employed by smart money on Solana through Jupiter DCA. This endpoint reveals systematic accumulation strategies used by smart money. + +```json +{"openapi":"3.1.0","info":{"title":"Nansen API","version":"1.0.0"},"tags":[{"name":"Smart Money","description":"Smart money analytics and insights"}],"servers":[{"url":"https://api.nansen.ai","description":"Production server"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"apiKey","description":"API key for authentication"}},"schemas":{"SmartMoneyDcasRequest":{"properties":{"filters":{"anyOf":[{"$ref":"#/components/schemas/SmartMoneyDcasFilters"}],"description":"Additional filters to apply. Only filters for columns that are being selected will be applied."},"pagination":{"$ref":"#/components/schemas/PaginationRequest","description":"Pagination parameters"},"order_by":{"anyOf":[{"items":{"$ref":"#/components/schemas/SortOrder_SmartMoneyDcasSortField_"},"type":"array"}],"title":"Order By","description":"Custom sort order to override the endpoint's default ordering.\n\nExamples:\n- [{\"field\": \"dca_created_at\", \"direction\": \"DESC\"}] - Sort by DCA created timestamp descending\n- [{\"field\": \"dca_updated_at\", \"direction\": \"ASC\"}] - Sort by DCA updated timestamp ascending\n- [{\"field\": \"deposit_token_amount\", \"direction\": \"DESC\"}, {\"field\": \"token_spent_amount\", \"direction\": \"ASC\"}] - Sort by deposit token amount descending, then token spent amount ascending"}},"additionalProperties":false,"type":"object","title":"SmartMoneyDcasRequest","description":""},"SmartMoneyDcasFilters":{"properties":{"include_smart_money_labels":{"anyOf":[{"items":{"$ref":"#/components/schemas/SmartMoneyFilterType"},"type":"array"}],"title":"Include Smart Money Labels","description":"Smart money category filters"},"exclude_smart_money_labels":{"anyOf":[{"items":{"$ref":"#/components/schemas/SmartMoneyFilterType"},"type":"array"}],"title":"Exclude Smart Money Labels","description":"Smart money category filters"},"dca_created_at":{"anyOf":[{"$ref":"#/components/schemas/DateRangeFilter"}],"description":"Date range filter for DCA creation timestamps"},"transaction_hash":{"anyOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Transaction Hash","description":"Transaction hash filter"},"trader_address":{"anyOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Trader Address","description":"Trader address filter"},"trader_address_label":{"anyOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Trader Address Label","description":"Trader name or label filter"},"input_token_symbol":{"anyOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Input Token Symbol","description":"Symbol filter for input tokens"},"output_token_symbol":{"anyOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Output Token Symbol","description":"Symbol filter for output tokens"},"deposit_token_amount":{"anyOf":[{"$ref":"#/components/schemas/NumericRangeFilter"}],"description":"Deposit amount range filter"},"token_spent_amount":{"anyOf":[{"$ref":"#/components/schemas/NumericRangeFilter"}],"description":"Token spent amount range filter"},"output_token_redeemed_amount":{"anyOf":[{"$ref":"#/components/schemas/NumericRangeFilter"}],"description":"Output token redeemed amount range filter"}},"additionalProperties":false,"type":"object","title":"SmartMoneyDcasFilters","description":"Filters for smart money DCAs endpoint.\n\nThese filters control which DCA orders, tokens, and traders\nare included in the DCA analysis."},"SmartMoneyFilterType":{"type":"string","enum":["Fund","Smart Trader","30D Smart Trader","90D Smart Trader","180D Smart Trader"],"title":"SmartMoneyFilterType","description":"Enum for smart money filter options."},"DateRangeFilter":{"properties":{"from":{"anyOf":[{"type":"string","format":"date-time"},{"type":"string"},{"type":"null"}],"title":"From","description":"Start date (inclusive)"},"to":{"anyOf":[{"type":"string","format":"date-time"},{"type":"string"},{"type":"null"}],"title":"To","description":"End date (inclusive)"}},"type":"object","title":"DateRangeFilter","description":"Filter for date ranges with optional from/to bounds. - Date range"},"NumericRangeFilter":{"properties":{"min":{"anyOf":[{"type":"number"}],"title":"Min","description":"Minimum value (inclusive)"},"max":{"anyOf":[{"type":"number"}],"title":"Max","description":"Maximum value (inclusive)"}},"type":"object","title":"NumericRangeFilter","description":"Filter for numeric values (floats) with optional min/max bounds.\nUse for prices, volumes, ratios, and other decimal values. - Values between -10.5 and 100.75"},"PaginationRequest":{"properties":{"page":{"type":"integer","minimum":1,"title":"Page","description":"Page number (1-based)","default":1},"per_page":{"type":"integer","maximum":1000,"minimum":1,"title":"Per Page","description":"Number of records per page (max 1000)","default":10}},"type":"object","title":"PaginationRequest","description":"Pagination parameters for API requests."},"SortOrder_SmartMoneyDcasSortField_":{"properties":{"field":{"$ref":"#/components/schemas/SmartMoneyDcasSortField","description":"Field to sort by"},"direction":{"$ref":"#/components/schemas/SortDirection","description":"Sort direction (ASC or DESC)"}},"type":"object","required":["field","direction"],"title":"SortOrder[SmartMoneyDcasSortField]"},"SmartMoneyDcasSortField":{"type":"string","enum":["dca_created_at","dca_updated_at","input_token_symbol","output_token_symbol","deposit_token_amount","token_spent_amount","deposit_value_usd","output_token_redeemed_amount"],"title":"SmartMoneyDcasSortField","description":"Enum for sortable fields in smart money DCAs."},"SortDirection":{"type":"string","enum":["ASC","DESC"],"title":"SortDirection","description":"Enum for sort directions."},"SmartMoneyDcasResponse":{"properties":{"data":{"items":{"$ref":"#/components/schemas/SmartMoneyDca"},"type":"array","title":"Data","description":"List of smart money DCA records"},"pagination":{"$ref":"#/components/schemas/PaginationInfo","description":"Pagination information"}},"type":"object","required":["data","pagination"],"title":"SmartMoneyDcasResponse","description":"Response model for smart money DCAs endpoint.\n\nContains the filtered smart money DCAs data with metadata."},"SmartMoneyDca":{"properties":{"dca_created_at":{"type":"string","title":"Dca Created At","description":"The timestamp of the earliest transaction"},"dca_updated_at":{"type":"string","title":"Dca Updated At","description":"The timestamp of the latest transaction"},"trader_address":{"type":"string","title":"Trader Address","description":"The address of the trader"},"transaction_hash":{"type":"string","title":"Transaction Hash","description":"The transaction hash at the time of creation"},"trader_address_label":{"type":"string","title":"Trader Address Label","description":"Label associated with the address"},"dca_vault_address":{"type":"string","title":"Dca Vault Address","description":"The address of the DCA vault"},"input_token_address":{"type":"string","title":"Input Token Address","description":"Address of token"},"output_token_address":{"type":"string","title":"Output Token Address","description":"Address of token"},"deposit_token_amount":{"anyOf":[{"type":"number"}],"title":"Deposit Token Amount","description":"The amount deposited into the DCA vault"},"token_spent_amount":{"anyOf":[{"type":"number"}],"title":"Token Spent Amount","description":"The amount spent from the deposit"},"output_token_redeemed_amount":{"anyOf":[{"type":"number"}],"title":"Output Token Redeemed Amount","description":"The amount of other tokens redeemed"},"dca_status":{"type":"string","title":"Dca Status","description":"Indicates if the account was closed or active"},"input_token_symbol":{"type":"string","title":"Input Token Symbol","description":"The symbol of the input token"},"output_token_symbol":{"type":"string","title":"Output Token Symbol","description":"The symbol of the output token"},"deposit_value_usd":{"anyOf":[{"type":"number"}],"title":"Deposit Value Usd","description":"The USD value of the deposit"}},"type":"object","required":["dca_created_at","dca_updated_at","trader_address","transaction_hash","trader_address_label","dca_vault_address","input_token_address","output_token_address","dca_status","input_token_symbol","output_token_symbol"],"title":"SmartMoneyDca","description":"Individual smart money DCA record.\n\nRepresents a single DCA (Dollar Cost Averaging) order made by smart money wallets."},"PaginationInfo":{"properties":{"page":{"type":"integer","minimum":1,"title":"Page","description":"Current page number","default":1},"per_page":{"type":"integer","maximum":1000,"minimum":1,"title":"Per Page","description":"Number of records per page","default":10},"is_last_page":{"type":"boolean","title":"Is Last Page","description":"Whether this is the last page","default":true}},"type":"object","title":"PaginationInfo","description":"Pagination information for API responses."}},"responses":{"BadRequestError":{"description":"Bad Request - Invalid request parameters or malformed request","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"UnauthorizedError":{"description":"Authentication error - No API key found in request","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"ForbiddenError":{"description":"Forbidden - User does not have required subscription tier","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"NotFoundError":{"description":"Not Found - The requested resource was not found","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"ValidationError":{"description":"Validation error - Invalid request parameters","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"loc":{"type":"array","items":{"type":"string"}},"msg":{"type":"string"},"type":{"type":"string"}}}}}}}}},"TooManyRequestsError":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"},"retry_after":{"type":"integer","description":"Seconds to wait before retrying"}}}}}},"InternalServerError":{"description":"Internal Server Error - An unexpected error occurred","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}}}},"paths":{"/api/v1/smart-money/dcas":{"post":{"tags":["Smart Money"],"summary":"Get Smart Money DCAs Data","description":"Monitor DCA strategies employed by smart money on Solana through Jupiter DCA. This endpoint reveals systematic accumulation strategies used by smart money.","operationId":"get_smart_money_dcas_api_v1_smart_money_dcas_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SmartMoneyDcasRequest"}}},"required":true},"responses":{"200":{"description":"Smart money DCAs data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SmartMoneyDcasResponse"}}}},"400":{"description":"Bad Request","$ref":"#/components/responses/BadRequestError"},"401":{"description":"Unauthorized","$ref":"#/components/responses/UnauthorizedError"},"403":{"description":"Forbidden","$ref":"#/components/responses/ForbiddenError"},"404":{"description":"Not Found","$ref":"#/components/responses/NotFoundError"},"422":{"description":"Unprocessable Content","$ref":"#/components/responses/ValidationError"},"429":{"description":"Too Many Requests","$ref":"#/components/responses/TooManyRequestsError"},"500":{"description":"Internal Server Error","$ref":"#/components/responses/InternalServerError"}}}}}} +``` + + +# Address Current Balances + +## Get Address Current Balance Data + +> Retrieve current token holdings for addresses or entities. Returns detailed balance information across specified chains.\ +> \ +> What it helps to answer:\ +> \ +> \- Current token holdings with quantities and USD valuations\ +> \- Asset distribution across different blockchain networks\ +> \- Native token versus token balances\ +> \- Stablecoin holdings and percentages\ +> \- Cross-chain portfolio composition\ +> \ +> Note: The address field in the response will be empty if entity\_name is provided. + +```json +{"openapi":"3.1.0","info":{"title":"Nansen API","version":"1.0.0"},"tags":[{"name":"Profiler","description":"Wallet profiling and analysis"}],"servers":[{"url":"https://api.nansen.ai","description":"Production server"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"apiKey","description":"API key for authentication"}},"schemas":{"ProfilerAddressBalancesRequest":{"properties":{"address":{"anyOf":[{"type":"string"}],"title":"Address","description":"Address to get balances for"},"entity_name":{"anyOf":[{"type":"string"}],"title":"Entity Name","description":"Entity name to get balances for"},"chain":{"$ref":"#/components/schemas/ProfilerChain","description":"Blockchain chain for the balances"},"hide_spam_token":{"type":"boolean","title":"Hide Spam Token","description":"Removes suspicious tokens from the balance list","default":true},"filters":{"anyOf":[{"$ref":"#/components/schemas/ProfilerAddressBalancesFilters"}],"description":"Additional filters to apply. Only filters for columns that are being selected will be applied."},"pagination":{"$ref":"#/components/schemas/PaginationRequest","description":"Pagination parameters"},"order_by":{"anyOf":[{"items":{"$ref":"#/components/schemas/SortOrder_ProfilerAddressBalancesSortField_"},"type":"array"}],"title":"Order By","description":"Custom sort order to override the endpoint's default ordering"}},"additionalProperties":false,"type":"object","required":["chain"],"title":"ProfilerAddressBalancesRequest","description":""},"ProfilerChain":{"type":"string","enum":["all","arbitrum","avalanche","base","berachain","blast","bnb","ethereum","goat","hyperevm","iotaevm","linea","mantle","optimism","plasma","polygon","ronin","sei","scroll","sonic","unichain","zksync","solana","bitcoin","starknet","ton","tron"],"title":"ProfilerChain","description":"Enum for chains supported in profiler analysis."},"ProfilerAddressBalancesFilters":{"properties":{"value_usd":{"anyOf":[{"$ref":"#/components/schemas/NumericRangeFilter"}],"description":"Balance range filter in USD"},"price_usd":{"anyOf":[{"$ref":"#/components/schemas/NumericRangeFilter"}],"description":"Token price range filter in USD"},"token_amount":{"anyOf":[{"$ref":"#/components/schemas/IntegerRangeFilter"}],"description":"Token amount range filter"},"token_symbol":{"anyOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Token Symbol","description":"Token symbol filter"},"token_address":{"anyOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Token Address","description":"Token address filter"},"token_name":{"anyOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Token Name","description":"Token name filter"}},"additionalProperties":false,"type":"object","title":"ProfilerAddressBalancesFilters","description":"Filters for profiler address current balance endpoint.\n\nThese filters control which token balances are included."},"NumericRangeFilter":{"properties":{"min":{"anyOf":[{"type":"number"}],"title":"Min","description":"Minimum value (inclusive)"},"max":{"anyOf":[{"type":"number"}],"title":"Max","description":"Maximum value (inclusive)"}},"type":"object","title":"NumericRangeFilter","description":"Filter for numeric values (floats) with optional min/max bounds.\nUse for prices, volumes, ratios, and other decimal values. - Values between -10.5 and 100.75"},"IntegerRangeFilter":{"properties":{"min":{"anyOf":[{"type":"integer"}],"title":"Min","description":"Minimum value (inclusive)"},"max":{"anyOf":[{"type":"integer"}],"title":"Max","description":"Maximum value (inclusive)"}},"type":"object","title":"IntegerRangeFilter","description":"Filter for integer values with optional min/max bounds.\nUse for counts, numbers of items, and other whole number values. - Values between 5 and 100"},"PaginationRequest":{"properties":{"page":{"type":"integer","minimum":1,"title":"Page","description":"Page number (1-based)","default":1},"per_page":{"type":"integer","maximum":1000,"minimum":1,"title":"Per Page","description":"Number of records per page (max 1000)","default":10}},"type":"object","title":"PaginationRequest","description":"Pagination parameters for API requests."},"SortOrder_ProfilerAddressBalancesSortField_":{"properties":{"field":{"$ref":"#/components/schemas/ProfilerAddressBalancesSortField","description":"Field to sort by"},"direction":{"$ref":"#/components/schemas/SortDirection","description":"Sort direction (ASC or DESC)"}},"type":"object","required":["field","direction"],"title":"SortOrder[ProfilerAddressBalancesSortField]"},"ProfilerAddressBalancesSortField":{"type":"string","enum":["value_usd","token_symbol"],"title":"ProfilerAddressBalancesSortField","description":"Enum for sortable fields in profiler address balances."},"SortDirection":{"type":"string","enum":["ASC","DESC"],"title":"SortDirection","description":"Enum for sort directions."},"ProfilerAddressBalancesResponse":{"properties":{"pagination":{"$ref":"#/components/schemas/PaginationInfo","description":"Pagination information"},"data":{"items":{"$ref":"#/components/schemas/ProfilerBalance"},"type":"array","title":"Data","description":"List of balance records"}},"type":"object","required":["pagination","data"],"title":"ProfilerAddressBalancesResponse","description":"Response model for profiler address current-balance endpoint.\n\nContains the filtered balance data with metadata."},"PaginationInfo":{"properties":{"page":{"type":"integer","minimum":1,"title":"Page","description":"Current page number","default":1},"per_page":{"type":"integer","maximum":1000,"minimum":1,"title":"Per Page","description":"Number of records per page","default":10},"is_last_page":{"type":"boolean","title":"Is Last Page","description":"Whether this is the last page","default":true}},"type":"object","title":"PaginationInfo","description":"Pagination information for API responses."},"ProfilerBalance":{"properties":{"chain":{"type":"string","title":"Chain","description":"Chain"},"address":{"type":"string","title":"Address","description":"Address of the wallet. Empty if entity_name is provided."},"token_address":{"type":"string","title":"Token Address","description":"Address of token"},"token_symbol":{"type":"string","title":"Token Symbol","description":"Token symbol"},"token_name":{"anyOf":[{"type":"string"}],"title":"Token Name","description":"Token name"},"token_amount":{"anyOf":[{"type":"number"}],"title":"Token Amount","description":"Token balance"},"price_usd":{"anyOf":[{"type":"number"}],"title":"Price Usd","description":"Price of the token"},"value_usd":{"anyOf":[{"type":"number"}],"title":"Value Usd","description":"Token balance value in USD"}},"type":"object","required":["chain","address","token_address","token_symbol"],"title":"ProfilerBalance","description":"Individual profiler balance record.\n\nRepresents a single token balance from the wallet profiler."}},"responses":{"BadRequestError":{"description":"Bad Request - Invalid request parameters or malformed request","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"UnauthorizedError":{"description":"Authentication error - No API key found in request","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"ForbiddenError":{"description":"Forbidden - User does not have required subscription tier","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"NotFoundError":{"description":"Not Found - The requested resource was not found","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"ValidationError":{"description":"Validation error - Invalid request parameters","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"loc":{"type":"array","items":{"type":"string"}},"msg":{"type":"string"},"type":{"type":"string"}}}}}}}}},"TooManyRequestsError":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"},"retry_after":{"type":"integer","description":"Seconds to wait before retrying"}}}}}},"InternalServerError":{"description":"Internal Server Error - An unexpected error occurred","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}}}},"paths":{"/api/v1/profiler/address/current-balance":{"post":{"tags":["Profiler"],"summary":"Get Address Current Balance Data","description":"Retrieve current token holdings for addresses or entities. Returns detailed balance information across specified chains.\n\nWhat it helps to answer:\n\n- Current token holdings with quantities and USD valuations\n- Asset distribution across different blockchain networks\n- Native token versus token balances\n- Stablecoin holdings and percentages\n- Cross-chain portfolio composition\n\nNote: The address field in the response will be empty if entity_name is provided.","operationId":"get_profiler_address_current_balance_api_v1_profiler_address_current_balance_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfilerAddressBalancesRequest"}}},"required":true},"responses":{"200":{"description":"Address current balance data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfilerAddressBalancesResponse"}}}},"400":{"description":"Bad Request","$ref":"#/components/responses/BadRequestError"},"401":{"description":"Unauthorized","$ref":"#/components/responses/UnauthorizedError"},"403":{"description":"Forbidden","$ref":"#/components/responses/ForbiddenError"},"404":{"description":"Not Found","$ref":"#/components/responses/NotFoundError"},"422":{"description":"Unprocessable Content","$ref":"#/components/responses/ValidationError"},"429":{"description":"Too Many Requests","$ref":"#/components/responses/TooManyRequestsError"},"500":{"description":"Internal Server Error","$ref":"#/components/responses/InternalServerError"}}}}}} +``` +# Address Historical Balances + +## Get Address Historical Balances Data + +> Track token and native coin balance changes over time for addresses or entities. Provides snapshots at configurable intervals to analyze holding patterns, transaction activity, and portfolio evolution across multiple blockchains.\ +> \ +> What it helps to answer:\ +> \ +> \- Portfolio value changes across different time periods\ +> \- Token accumulation and distribution patterns over selected timeframes\ +> \- New positions entered and exited during specific periods + +```json +{"openapi":"3.1.0","info":{"title":"Nansen API","version":"1.0.0"},"tags":[{"name":"Profiler","description":"Wallet profiling and analysis"}],"servers":[{"url":"https://api.nansen.ai","description":"Production server"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"apiKey","description":"API key for authentication"}},"schemas":{"ProfilerAddressHistoricalBalancesRequest":{"properties":{"address":{"anyOf":[{"type":"string"}],"title":"Address","description":"Address to get historical balances for"},"entity_name":{"anyOf":[{"type":"string"}],"title":"Entity Name","description":"Entity name to get historical balances for"},"chain":{"$ref":"#/components/schemas/ProfilerChain","description":"Blockchain chain for the historical balances"},"date":{"$ref":"#/components/schemas/DateRange","description":"Date range for historical data"},"filters":{"anyOf":[{"$ref":"#/components/schemas/ProfilerAddressHistoricalBalancesFilters"}],"description":"Additional filters to apply. Only filters for columns that are being selected will be applied."},"pagination":{"$ref":"#/components/schemas/PaginationRequest","description":"Pagination parameters"},"order_by":{"anyOf":[{"items":{"$ref":"#/components/schemas/SortOrder_ProfilerAddressHistoricalBalancesSortField_"},"type":"array"}],"title":"Order By","description":"Custom sort order to override the endpoint's default ordering"}},"additionalProperties":false,"type":"object","required":["chain","date"],"title":"ProfilerAddressHistoricalBalancesRequest","description":""},"ProfilerChain":{"type":"string","enum":["all","arbitrum","avalanche","base","berachain","blast","bnb","ethereum","goat","hyperevm","iotaevm","linea","mantle","optimism","plasma","polygon","ronin","sei","scroll","sonic","unichain","zksync","solana","bitcoin","starknet","ton","tron"],"title":"ProfilerChain","description":"Enum for chains supported in profiler analysis."},"DateRange":{"properties":{"from":{"anyOf":[{"type":"string"}],"title":"From","description":"Start date in ISO 8601 format"},"to":{"anyOf":[{"type":"string"}],"title":"To","description":"End date in ISO 8601 format"}},"type":"object","title":"DateRange","description":"Date range model matching the API schema."},"ProfilerAddressHistoricalBalancesFilters":{"properties":{"value_usd":{"anyOf":[{"$ref":"#/components/schemas/NumericRangeFilter"}],"description":"Balance range filter in USD"},"token_amount":{"anyOf":[{"$ref":"#/components/schemas/IntegerRangeFilter"}],"description":"Token balance count range filter"},"token_symbol":{"anyOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Token Symbol","description":"Token symbol filter"},"token_address":{"anyOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Token Address","description":"Token address filter"},"hide_spam_tokens":{"anyOf":[{"type":"boolean"}],"title":"Hide Spam Tokens","description":"Whether to hide spam tokens from results","default":true}},"additionalProperties":false,"type":"object","title":"ProfilerAddressHistoricalBalancesFilters","description":"Filters for profiler address historical balances endpoint.\n\nThese filters control which historical balance data is included."},"NumericRangeFilter":{"properties":{"min":{"anyOf":[{"type":"number"}],"title":"Min","description":"Minimum value (inclusive)"},"max":{"anyOf":[{"type":"number"}],"title":"Max","description":"Maximum value (inclusive)"}},"type":"object","title":"NumericRangeFilter","description":"Filter for numeric values (floats) with optional min/max bounds.\nUse for prices, volumes, ratios, and other decimal values. - Values between -10.5 and 100.75"},"IntegerRangeFilter":{"properties":{"min":{"anyOf":[{"type":"integer"}],"title":"Min","description":"Minimum value (inclusive)"},"max":{"anyOf":[{"type":"integer"}],"title":"Max","description":"Maximum value (inclusive)"}},"type":"object","title":"IntegerRangeFilter","description":"Filter for integer values with optional min/max bounds.\nUse for counts, numbers of items, and other whole number values. - Values between 5 and 100"},"PaginationRequest":{"properties":{"page":{"type":"integer","minimum":1,"title":"Page","description":"Page number (1-based)","default":1},"per_page":{"type":"integer","maximum":1000,"minimum":1,"title":"Per Page","description":"Number of records per page (max 1000)","default":10}},"type":"object","title":"PaginationRequest","description":"Pagination parameters for API requests."},"SortOrder_ProfilerAddressHistoricalBalancesSortField_":{"properties":{"field":{"$ref":"#/components/schemas/ProfilerAddressHistoricalBalancesSortField","description":"Field to sort by"},"direction":{"$ref":"#/components/schemas/SortDirection","description":"Sort direction (ASC or DESC)"}},"type":"object","required":["field","direction"],"title":"SortOrder[ProfilerAddressHistoricalBalancesSortField]"},"ProfilerAddressHistoricalBalancesSortField":{"type":"string","enum":["block_timestamp","value_usd","token_symbol"],"title":"ProfilerAddressHistoricalBalancesSortField","description":"Enum for sortable fields in profiler address historical balances."},"SortDirection":{"type":"string","enum":["ASC","DESC"],"title":"SortDirection","description":"Enum for sort directions."},"ProfilerAddressHistoricalBalancesResponse":{"properties":{"pagination":{"$ref":"#/components/schemas/PaginationInfo","description":"Pagination information"},"data":{"items":{"$ref":"#/components/schemas/ProfilerHistoricalBalance"},"type":"array","title":"Data","description":"List of historical balance records"}},"type":"object","required":["pagination","data"],"title":"ProfilerAddressHistoricalBalancesResponse","description":"Response model for profiler address historical-balances endpoint.\n\nContains the filtered historical balance data with metadata."},"PaginationInfo":{"properties":{"page":{"type":"integer","minimum":1,"title":"Page","description":"Current page number","default":1},"per_page":{"type":"integer","maximum":1000,"minimum":1,"title":"Per Page","description":"Number of records per page","default":10},"is_last_page":{"type":"boolean","title":"Is Last Page","description":"Whether this is the last page","default":true}},"type":"object","title":"PaginationInfo","description":"Pagination information for API responses."},"ProfilerHistoricalBalance":{"properties":{"block_timestamp":{"type":"string","title":"Block Timestamp","description":"The block timestamp as date"},"token_address":{"type":"string","title":"Token Address","description":"Token Address"},"chain":{"type":"string","title":"Chain","description":"Chain"},"token_amount":{"anyOf":[{"type":"number"}],"title":"Token Amount","description":"Token amount"},"value_usd":{"anyOf":[{"type":"number"}],"title":"Value Usd","description":"Usd balance of the holdings"},"token_symbol":{"type":"string","title":"Token Symbol","description":"Symbol of the token"}},"type":"object","required":["block_timestamp","token_address","chain","token_symbol"],"title":"ProfilerHistoricalBalance","description":"Individual profiler historical balance record.\n\nRepresents a single historical token balance from the wallet profiler."}},"responses":{"BadRequestError":{"description":"Bad Request - Invalid request parameters or malformed request","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"UnauthorizedError":{"description":"Authentication error - No API key found in request","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"ForbiddenError":{"description":"Forbidden - User does not have required subscription tier","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"NotFoundError":{"description":"Not Found - The requested resource was not found","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"ValidationError":{"description":"Validation error - Invalid request parameters","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"loc":{"type":"array","items":{"type":"string"}},"msg":{"type":"string"},"type":{"type":"string"}}}}}}}}},"TooManyRequestsError":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"},"retry_after":{"type":"integer","description":"Seconds to wait before retrying"}}}}}},"InternalServerError":{"description":"Internal Server Error - An unexpected error occurred","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}}}},"paths":{"/api/v1/profiler/address/historical-balances":{"post":{"tags":["Profiler"],"summary":"Get Address Historical Balances Data","description":"Track token and native coin balance changes over time for addresses or entities. Provides snapshots at configurable intervals to analyze holding patterns, transaction activity, and portfolio evolution across multiple blockchains.\n\nWhat it helps to answer:\n\n- Portfolio value changes across different time periods\n- Token accumulation and distribution patterns over selected timeframes\n- New positions entered and exited during specific periods","operationId":"get_profiler_address_historical_balances_api_v1_profiler_address_historical_balances_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfilerAddressHistoricalBalancesRequest"}}},"required":true},"responses":{"200":{"description":"Address historical balances data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfilerAddressHistoricalBalancesResponse"}}}},"400":{"description":"Bad Request","$ref":"#/components/responses/BadRequestError"},"401":{"description":"Unauthorized","$ref":"#/components/responses/UnauthorizedError"},"403":{"description":"Forbidden","$ref":"#/components/responses/ForbiddenError"},"404":{"description":"Not Found","$ref":"#/components/responses/NotFoundError"},"422":{"description":"Unprocessable Content","$ref":"#/components/responses/ValidationError"},"429":{"description":"Too Many Requests","$ref":"#/components/responses/TooManyRequestsError"},"500":{"description":"Internal Server Error","$ref":"#/components/responses/InternalServerError"}}}}}} +``` +address transaction : +# Address Transactions + +## Get Address Transactions Data + +> Retrieve recent blockchain transactions for an address including token transfers, native currency movements, and contract interactions. + +```json +{"openapi":"3.1.0","info":{"title":"Nansen API","version":"1.0.0"},"tags":[{"name":"Profiler","description":"Wallet profiling and analysis"}],"servers":[{"url":"https://api.nansen.ai","description":"Production server"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"apiKey","description":"API key for authentication"}},"schemas":{"ProfilerAddressTransactionsRequest":{"properties":{"address":{"type":"string","title":"Address","description":"Address to get transactions for"},"chain":{"$ref":"#/components/schemas/ProfilerTransactionsChain","description":"Blockchain chain for the transactions"},"date":{"$ref":"#/components/schemas/DateRange","description":"Date range for the transactions"},"hide_spam_token":{"type":"boolean","title":"Hide Spam Token","description":"Removes suspicious tokens from the transaction list","default":true},"filters":{"anyOf":[{"$ref":"#/components/schemas/ProfilerAddressTransactionsFilters"}],"description":"Additional filters to apply. Only filters for columns that are being selected will be applied."},"pagination":{"$ref":"#/components/schemas/ProfilerPaginationRequest","description":"Pagination parameters (max 20 records per page for performance)"},"order_by":{"anyOf":[{"items":{"$ref":"#/components/schemas/SortOrder_ProfilerAddressTransactionsSortField_"},"type":"array"}],"title":"Order By","description":"Custom sort order to override the endpoint's default ordering"}},"additionalProperties":false,"type":"object","required":["address","chain","date"],"title":"ProfilerAddressTransactionsRequest","description":""},"ProfilerTransactionsChain":{"type":"string","enum":["arbitrum","avalanche","base","berachain","blast","bnb","ethereum","goat","iotaevm","linea","mantle","optimism","plasma","polygon","ronin","sei","scroll","sonic","unichain","zksync","solana","bitcoin","starknet","ton","tron"],"title":"ProfilerTransactionsChain","description":"Enum for chains supported in profiler analysis."},"DateRange":{"properties":{"from":{"anyOf":[{"type":"string"}],"title":"From","description":"Start date in ISO 8601 format"},"to":{"anyOf":[{"type":"string"}],"title":"To","description":"End date in ISO 8601 format"}},"type":"object","title":"DateRange","description":"Date range model matching the API schema."},"ProfilerAddressTransactionsFilters":{"properties":{"token_symbol":{"anyOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Token Symbol","description":"Token symbol filter"},"token_address":{"anyOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Token Address","description":"Token address filter"},"counterparty_name":{"anyOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Counterparty Name","description":"Counterparty name filter"},"volume_usd":{"anyOf":[{"$ref":"#/components/schemas/NumericRangeFilter"}],"description":"Transaction volume range filter in USD"},"method":{"anyOf":[{"type":"string"}],"title":"Method","description":"Transaction method filter"},"source_type":{"anyOf":[{"type":"string"}],"title":"Source Type","description":"Transaction source type filter"}},"additionalProperties":false,"type":"object","title":"ProfilerAddressTransactionsFilters","description":"Filters for profiler address transactions endpoint.\n\nThese filters control which transactions are included\nin the wallet transaction history."},"NumericRangeFilter":{"properties":{"min":{"anyOf":[{"type":"number"}],"title":"Min","description":"Minimum value (inclusive)"},"max":{"anyOf":[{"type":"number"}],"title":"Max","description":"Maximum value (inclusive)"}},"type":"object","title":"NumericRangeFilter","description":"Filter for numeric values (floats) with optional min/max bounds.\nUse for prices, volumes, ratios, and other decimal values. - Values between -10.5 and 100.75"},"ProfilerPaginationRequest":{"properties":{"page":{"type":"integer","minimum":1,"title":"Page","description":"Page number (1-based)","default":1},"per_page":{"type":"integer","maximum":20,"minimum":1,"title":"Per Page","description":"Number of records per page (max 20 for performance)","default":20}},"type":"object","title":"ProfilerPaginationRequest","description":"Pagination parameters for profiler endpoints with performance constraints."},"SortOrder_ProfilerAddressTransactionsSortField_":{"properties":{"field":{"$ref":"#/components/schemas/ProfilerAddressTransactionsSortField","description":"Field to sort by"},"direction":{"$ref":"#/components/schemas/SortDirection","description":"Sort direction (ASC or DESC)"}},"type":"object","required":["field","direction"],"title":"SortOrder[ProfilerAddressTransactionsSortField]"},"ProfilerAddressTransactionsSortField":{"type":"string","enum":["block_timestamp"],"title":"ProfilerAddressTransactionsSortField","description":"Enum for sortable fields in smart money inflows."},"SortDirection":{"type":"string","enum":["ASC","DESC"],"title":"SortDirection","description":"Enum for sort directions."},"ProfilerAddressTransactionsResponse":{"properties":{"pagination":{"$ref":"#/components/schemas/PaginationInfo","description":"Pagination information"},"data":{"items":{"$ref":"#/components/schemas/ProfilerTransaction"},"type":"array","title":"Data","description":"List of transaction records"}},"type":"object","required":["pagination","data"],"title":"ProfilerAddressTransactionsResponse","description":"Response model for profiler address transactions endpoint.\n\nContains the filtered transaction data with metadata."},"PaginationInfo":{"properties":{"page":{"type":"integer","minimum":1,"title":"Page","description":"Current page number","default":1},"per_page":{"type":"integer","maximum":1000,"minimum":1,"title":"Per Page","description":"Number of records per page","default":10},"is_last_page":{"type":"boolean","title":"Is Last Page","description":"Whether this is the last page","default":true}},"type":"object","title":"PaginationInfo","description":"Pagination information for API responses."},"ProfilerTransaction":{"properties":{"chain":{"type":"string","title":"Chain","description":"Blockchain chain"},"method":{"type":"string","title":"Method","description":"Transaction method (sent/received)"},"tokens_sent":{"anyOf":[{"items":{"$ref":"#/components/schemas/ProfilerTokenInfo"},"type":"array"}],"title":"Tokens Sent","description":"Tokens sent in the transaction"},"tokens_received":{"anyOf":[{"items":{"$ref":"#/components/schemas/ProfilerTokenInfo"},"type":"array"}],"title":"Tokens Received","description":"Tokens received in the transaction"},"volume_usd":{"anyOf":[{"type":"number"}],"title":"Volume Usd","description":"Transaction volume in USD"},"block_timestamp":{"type":"string","title":"Block Timestamp","description":"Block timestamp in ISO format"},"transaction_hash":{"type":"string","title":"Transaction Hash","description":"Transaction hash in hex format"},"source_type":{"type":"string","title":"Source Type","description":"Transaction source type"}},"type":"object","required":["chain","method","block_timestamp","transaction_hash","source_type"],"title":"ProfilerTransaction","description":"Individual profiler transaction record.\n\nRepresents a single transaction from the wallet profiler."},"ProfilerTokenInfo":{"properties":{"token_symbol":{"type":"string","title":"Token Symbol","description":"Token symbol"},"token_amount":{"type":"number","title":"Token Amount","description":"Token amount"},"price_usd":{"anyOf":[{"type":"number"}],"title":"Price Usd","description":"Token price in USD"},"value_usd":{"anyOf":[{"type":"number"}],"title":"Value Usd","description":"Token value in USD"},"token_address":{"type":"string","title":"Token Address","description":"Token contract address"},"chain":{"type":"string","title":"Chain","description":"Blockchain chain"},"from_address":{"type":"string","title":"From Address","description":"Source address"},"to_address":{"type":"string","title":"To Address","description":"Destination address"},"from_address_label":{"anyOf":[{"type":"string"}],"title":"From Address Label","description":"Source address label"},"to_address_label":{"anyOf":[{"type":"string"}],"title":"To Address Label","description":"Destination address label"}},"type":"object","required":["token_symbol","token_amount","token_address","chain","from_address","to_address"],"title":"ProfilerTokenInfo","description":"Token information for profiler transactions.\n\nRepresents detailed information about a token in a transaction."}},"responses":{"BadRequestError":{"description":"Bad Request - Invalid request parameters or malformed request","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"UnauthorizedError":{"description":"Authentication error - No API key found in request","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"ForbiddenError":{"description":"Forbidden - User does not have required subscription tier","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"NotFoundError":{"description":"Not Found - The requested resource was not found","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"ValidationError":{"description":"Validation error - Invalid request parameters","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"loc":{"type":"array","items":{"type":"string"}},"msg":{"type":"string"},"type":{"type":"string"}}}}}}}}},"TooManyRequestsError":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"},"retry_after":{"type":"integer","description":"Seconds to wait before retrying"}}}}}},"InternalServerError":{"description":"Internal Server Error - An unexpected error occurred","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}}}},"paths":{"/api/v1/profiler/address/transactions":{"post":{"tags":["Profiler"],"summary":"Get Address Transactions Data","description":"Retrieve recent blockchain transactions for an address including token transfers, native currency movements, and contract interactions.","operationId":"get_profiler_address_transactions_api_v1_profiler_address_transactions_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfilerAddressTransactionsRequest"}}},"required":true},"responses":{"200":{"description":"Address transaction data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfilerAddressTransactionsResponse"}}}},"400":{"description":"Bad Request","$ref":"#/components/responses/BadRequestError"},"401":{"description":"Unauthorized","$ref":"#/components/responses/UnauthorizedError"},"403":{"description":"Forbidden","$ref":"#/components/responses/ForbiddenError"},"404":{"description":"Not Found","$ref":"#/components/responses/NotFoundError"},"422":{"description":"Unprocessable Content","$ref":"#/components/responses/ValidationError"},"429":{"description":"Too Many Requests","$ref":"#/components/responses/TooManyRequestsError"},"500":{"description":"Internal Server Error","$ref":"#/components/responses/InternalServerError"}}}}}} +``` + +## Get Transaction with Token Transfer Lookup Data + +> Get comprehensive transaction information including token transfers and NFT transfers.\ +> This endpoint provides detailed information about a specific transaction including\ +> native cryptocurrency movements, token transfers, and NFT transfers with USD values. + +```json +{"openapi":"3.1.0","info":{"title":"Nansen API","version":"1.0.0"},"tags":[{"name":"Profiler","description":"Wallet profiling and analysis"}],"servers":[{"url":"https://api.nansen.ai","description":"Production server"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"apiKey","description":"API key for authentication"}},"schemas":{"TransactionLookupRequest":{"properties":{"chain":{"$ref":"#/components/schemas/TransactionLookupChain","description":"Blockchain chain for the transaction lookup"},"transaction_hash":{"type":"string","title":"Transaction Hash","description":"Transaction hash to lookup"},"block_timestamp":{"type":"string","title":"Block Timestamp","description":"Timestamp of the transaction"}},"additionalProperties":false,"type":"object","required":["chain","transaction_hash","block_timestamp"],"title":"TransactionLookupRequest","description":""},"TransactionLookupChain":{"type":"string","enum":["arbitrum","avalanche","base","berachain","blast","bnb","ethereum","hyperevm","iotaevm","linea","mantle","optimism","plasma","ronin","sei","scroll","sonic","unichain","zksync","bitcoin","ton","tron","starknet"],"title":"TransactionLookupChain","description":"Blockchain chain for the transaction lookup."},"TransactionLookupListResponse":{"properties":{"data":{"items":{"$ref":"#/components/schemas/TransactionLookupResponse"},"type":"array","title":"Data","description":"List of transaction lookup results"}},"type":"object","required":["data"],"title":"TransactionLookupListResponse","description":"Response model for transaction lookup endpoint returning a list of transactions."},"TransactionLookupResponse":{"properties":{"chain":{"type":"string","title":"Chain","description":"The blockchain network of the transaction"},"transaction_hash":{"type":"string","title":"Transaction Hash","description":"The unique identifier of the transaction"},"from_address":{"type":"string","title":"From Address","description":"The hexadecimal address of the sender"},"from_address_label":{"anyOf":[{"type":"string"}],"title":"From Address Label","description":"The name or label associated with the sender's address"},"to_address":{"type":"string","title":"To Address","description":"The hexadecimal address of the recipient"},"to_address_label":{"anyOf":[{"type":"string"}],"title":"To Address Label","description":"The name or label associated with the recipient's address"},"native_value":{"anyOf":[{"type":"number"}],"title":"Native Value","description":"The amount of native cryptocurrency transferred"},"dated_native_price":{"anyOf":[{"type":"number"}],"title":"Dated Native Price","description":"The price of the native cryptocurrency at the time of the transaction"},"dated_native_value_usd":{"anyOf":[{"type":"number"}],"title":"Dated Native Value Usd","description":"The USD value of the native cryptocurrency transferred at the time of the transaction"},"current_native_price":{"anyOf":[{"type":"number"}],"title":"Current Native Price","description":"The current price of the native cryptocurrency"},"current_native_value_usd":{"anyOf":[{"type":"number"}],"title":"Current Native Value Usd","description":"The current USD value of the native cryptocurrency transferred"},"receipt_status":{"anyOf":[{"type":"integer"}],"title":"Receipt Status","description":"The status of the transaction receipt (1 for success, 0 for failure)"},"block_timestamp":{"type":"string","title":"Block Timestamp","description":"The timestamp of the block in which the transaction was included"},"token_transfer_array":{"anyOf":[{"items":{"$ref":"#/components/schemas/TokenTransfer"},"type":"array"}],"title":"Token Transfer Array","description":"Information about any token transfers associated with this transaction"},"nft_transfer_array":{"anyOf":[{"items":{"$ref":"#/components/schemas/NFTTransfer"},"type":"array"}],"title":"Nft Transfer Array","description":"Information about any NFT transfers associated with this transaction"}},"type":"object","required":["chain","transaction_hash","from_address","from_address_label","to_address","to_address_label","native_value","dated_native_price","dated_native_value_usd","current_native_price","current_native_value_usd","receipt_status","block_timestamp","token_transfer_array","nft_transfer_array"],"title":"TransactionLookupResponse","description":"Response model for transaction lookup endpoint.\n\nContains comprehensive transaction information including token transfers and NFT transfers."},"TokenTransfer":{"properties":{"from_address":{"type":"string","title":"From Address","description":"From address"},"from_address_label":{"type":"string","title":"From Address Label","description":"From address label"},"to_address":{"type":"string","title":"To Address","description":"To address"},"to_address_label":{"type":"string","title":"To Address Label","description":"To address label"},"token_address":{"type":"string","title":"Token Address","description":"Token contract address"},"token_symbol":{"type":"string","title":"Token Symbol","description":"Token symbol"},"token_amount":{"type":"number","title":"Token Amount","description":"Token amount transferred"},"dated_price_usd":{"anyOf":[{"type":"number"}],"title":"Dated Price Usd","description":"Price of the token in USD at the time of the transaction"},"dated_value_usd":{"anyOf":[{"type":"number"}],"title":"Dated Value Usd","description":"USD value of the token transferred at the time of the transaction"},"current_price_usd":{"anyOf":[{"type":"number"}],"title":"Current Price Usd","description":"Current price of the token in USD"},"current_value_usd":{"anyOf":[{"type":"number"}],"title":"Current Value Usd","description":"Current USD value of the token transferred"},"transfer_id":{"type":"string","title":"Transfer Id","description":"Transfer ID"}},"type":"object","required":["from_address","from_address_label","to_address","to_address_label","token_address","token_symbol","token_amount","dated_price_usd","dated_value_usd","current_price_usd","current_value_usd","transfer_id"],"title":"TokenTransfer","description":"Model for token transfer information."},"NFTTransfer":{"properties":{"from_address":{"type":"string","title":"From Address","description":"From address"},"from_address_label":{"type":"string","title":"From Address Label","description":"From address label"},"to_address":{"type":"string","title":"To Address","description":"To address"},"to_address_label":{"type":"string","title":"To Address Label","description":"To address label"},"project_id":{"type":"string","title":"Project Id","description":"Project ID"},"collection_name":{"type":"string","title":"Collection Name","description":"Collection name"},"nft_id":{"type":"string","title":"Nft Id","description":"NFT ID"}},"type":"object","required":["from_address","from_address_label","to_address","to_address_label","project_id","collection_name","nft_id"],"title":"NFTTransfer","description":"Model for NFT transfer information."}},"responses":{"BadRequestError":{"description":"Bad Request - Invalid request parameters or malformed request","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"UnauthorizedError":{"description":"Authentication error - No API key found in request","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"ForbiddenError":{"description":"Forbidden - User does not have required subscription tier","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"NotFoundError":{"description":"Not Found - The requested resource was not found","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"ValidationError":{"description":"Validation error - Invalid request parameters","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"loc":{"type":"array","items":{"type":"string"}},"msg":{"type":"string"},"type":{"type":"string"}}}}}}}}},"TooManyRequestsError":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"},"retry_after":{"type":"integer","description":"Seconds to wait before retrying"}}}}}},"InternalServerError":{"description":"Internal Server Error - An unexpected error occurred","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}}}},"paths":{"/api/v1/transaction-with-token-transfer-lookup":{"post":{"tags":["Profiler"],"summary":"Get Transaction with Token Transfer Lookup Data","description":"Get comprehensive transaction information including token transfers and NFT transfers.\n This endpoint provides detailed information about a specific transaction including\n native cryptocurrency movements, token transfers, and NFT transfers with USD values.","operationId":"get_transaction_with_token_transfer_lookup_api_v1_transaction_with_token_transfer_lookup_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionLookupRequest"}}},"required":true},"responses":{"200":{"description":"Transaction lookup data with token and NFT transfer information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionLookupListResponse"}}}},"400":{"description":"Bad Request","$ref":"#/components/responses/BadRequestError"},"401":{"description":"Unauthorized","$ref":"#/components/responses/UnauthorizedError"},"403":{"description":"Forbidden","$ref":"#/components/responses/ForbiddenError"},"404":{"description":"Not Found","$ref":"#/components/responses/NotFoundError"},"422":{"description":"Unprocessable Content","$ref":"#/components/responses/ValidationError"},"429":{"description":"Too Many Requests","$ref":"#/components/responses/TooManyRequestsError"},"500":{"description":"Internal Server Error","$ref":"#/components/responses/InternalServerError"}}}}}} +``` +# Address Counterparties + +## Get Address Counterparties Data + +> Get top counterparties that wallet addresses have interacted with, supporting different\ +> grouping options (wallet or entity) and source filtering (Combined, Tokens, ETH).\ +> Returns interaction statistics including volume, frequency, and timing data.\ +> \ +> What it helps to answer:\ +> \ +> \- Most frequent transaction partners by count and volume\ +> \- Net value flows between addresses (inflows vs outflows)\ +> \- Exchange and protocol interaction patterns\ +> \- DeFi protocol usage and DEX trading counterparties\ +> \- High-value transfer relationships and funding sources + +```json +{"openapi":"3.1.0","info":{"title":"Nansen API","version":"1.0.0"},"tags":[{"name":"Profiler","description":"Wallet profiling and analysis"}],"servers":[{"url":"https://api.nansen.ai","description":"Production server"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"apiKey","description":"API key for authentication"}},"schemas":{"ProfilerAddressCounterpartiesRequest":{"properties":{"address":{"anyOf":[{"type":"string"}],"title":"Address","description":"Address to get counterparties for"},"entity_name":{"anyOf":[{"type":"string"}],"title":"Entity Name","description":"Entity name to get counterparties for"},"chain":{"$ref":"#/components/schemas/ProfilerChain","description":"Blockchain chain for the counterparties data"},"date":{"$ref":"#/components/schemas/DateRange","description":"Date range for the counterparties data"},"source_input":{"$ref":"#/components/schemas/SourceInput","description":"Type of interactions to include","default":"Combined"},"group_by":{"$ref":"#/components/schemas/GroupBy","description":"Group counterparties by wallet or entity","default":"wallet"},"filters":{"anyOf":[{"$ref":"#/components/schemas/ProfilerAddressCounterpartiesFilters"}],"description":"Additional filters to apply. Only filters for columns that are being selected will be applied."},"pagination":{"$ref":"#/components/schemas/PaginationRequest","description":"Pagination parameters"},"order_by":{"anyOf":[{"items":{"$ref":"#/components/schemas/SortOrder_ProfilerAddressCounterpartiesSortField_"},"type":"array"}],"title":"Order By","description":"Custom sort order to override the endpoint's default ordering.\n\nExamples:\n- [{\"field\": \"total_volume_usd\", \"direction\": \"DESC\"}] - Sort by total volume descending\n- [{\"field\": \"interaction_count\", \"direction\": \"ASC\"}] - Sort by interaction count ascending\n- [{\"field\": \"last_interaction_date\", \"direction\": \"DESC\"}] - Sort by last interaction date descending\n- [{\"field\": \"volume_in_usd\", \"direction\": \"DESC\"}] - Sort by incoming volume descending"}},"additionalProperties":false,"type":"object","required":["chain","date"],"title":"ProfilerAddressCounterpartiesRequest","description":""},"ProfilerChain":{"type":"string","enum":["all","arbitrum","avalanche","base","berachain","blast","bnb","ethereum","goat","hyperevm","iotaevm","linea","mantle","optimism","plasma","polygon","ronin","sei","scroll","sonic","unichain","zksync","solana","bitcoin","starknet","ton","tron"],"title":"ProfilerChain","description":"Enum for chains supported in profiler analysis."},"DateRange":{"properties":{"from":{"anyOf":[{"type":"string"}],"title":"From","description":"Start date in ISO 8601 format"},"to":{"anyOf":[{"type":"string"}],"title":"To","description":"End date in ISO 8601 format"}},"type":"object","title":"DateRange","description":"Date range model matching the API schema."},"SourceInput":{"type":"string","enum":["Combined","Tokens","ETH"],"title":"SourceInput","description":"Enum for source input types in counterparties endpoint."},"GroupBy":{"type":"string","enum":["wallet","entity"],"title":"GroupBy","description":"Enum for grouping types in counterparties endpoint."},"ProfilerAddressCounterpartiesFilters":{"properties":{"interaction_count":{"anyOf":[{"$ref":"#/components/schemas/IntegerRangeFilter"}],"description":"Interaction count range filter"},"total_volume_usd":{"anyOf":[{"$ref":"#/components/schemas/NumericRangeFilter"}],"description":"Total volume range filter in USD"},"volume_in_usd":{"anyOf":[{"$ref":"#/components/schemas/NumericRangeFilter"}],"description":"Volume in USD range filter"},"volume_out_usd":{"anyOf":[{"$ref":"#/components/schemas/NumericRangeFilter"}],"description":"Volume out USD range filter"},"include_smart_money_labels":{"anyOf":[{"items":{"$ref":"#/components/schemas/LabelType"},"type":"array"}],"title":"Include Smart Money Labels","description":"Include smart money labels for counterparties"},"exclude_smart_money_labels":{"anyOf":[{"items":{"$ref":"#/components/schemas/LabelType"},"type":"array"}],"title":"Exclude Smart Money Labels","description":"Exclude smart money labels for counterparties"}},"additionalProperties":false,"type":"object","title":"ProfilerAddressCounterpartiesFilters","description":"Filters for profiler address counterparties endpoint.\n\nThese filters control which counterparties and interactions are included."},"IntegerRangeFilter":{"properties":{"min":{"anyOf":[{"type":"integer"}],"title":"Min","description":"Minimum value (inclusive)"},"max":{"anyOf":[{"type":"integer"}],"title":"Max","description":"Maximum value (inclusive)"}},"type":"object","title":"IntegerRangeFilter","description":"Filter for integer values with optional min/max bounds.\nUse for counts, numbers of items, and other whole number values. - Values between 5 and 100"},"NumericRangeFilter":{"properties":{"min":{"anyOf":[{"type":"number"}],"title":"Min","description":"Minimum value (inclusive)"},"max":{"anyOf":[{"type":"number"}],"title":"Max","description":"Maximum value (inclusive)"}},"type":"object","title":"NumericRangeFilter","description":"Filter for numeric values (floats) with optional min/max bounds.\nUse for prices, volumes, ratios, and other decimal values. - Values between -10.5 and 100.75"},"LabelType":{"type":"string","enum":["30D Smart Trader","90D Smart Trader","180D Smart Trader","Fund","Smart Trader","Public Figure","Exchange","Whale","BananaGun Bot User","Top Maestro Bot User","Top BananaGun Bot User","Maestro Bot User","Early MAGIC Miner","First Mover LP","First Mover Staking","Profitable LP","Smart HL Perps Trader"],"title":"LabelType","description":"Enum for label filter options."},"PaginationRequest":{"properties":{"page":{"type":"integer","minimum":1,"title":"Page","description":"Page number (1-based)","default":1},"per_page":{"type":"integer","maximum":1000,"minimum":1,"title":"Per Page","description":"Number of records per page (max 1000)","default":10}},"type":"object","title":"PaginationRequest","description":"Pagination parameters for API requests."},"SortOrder_ProfilerAddressCounterpartiesSortField_":{"properties":{"field":{"$ref":"#/components/schemas/ProfilerAddressCounterpartiesSortField","description":"Field to sort by"},"direction":{"$ref":"#/components/schemas/SortDirection","description":"Sort direction (ASC or DESC)"}},"type":"object","required":["field","direction"],"title":"SortOrder[ProfilerAddressCounterpartiesSortField]"},"ProfilerAddressCounterpartiesSortField":{"type":"string","enum":["interaction_count","total_volume_usd","last_interaction_date","volume_in_usd","volume_out_usd"],"title":"ProfilerAddressCounterpartiesSortField","description":"Enum for sortable fields in profiler address counterparties."},"SortDirection":{"type":"string","enum":["ASC","DESC"],"title":"SortDirection","description":"Enum for sort directions."},"ProfilerAddressCounterpartiesResponse":{"properties":{"pagination":{"$ref":"#/components/schemas/PaginationInfo","description":"Pagination information"},"data":{"items":{"$ref":"#/components/schemas/ProfilerCounterparty"},"type":"array","title":"Data","description":"List of counterparty records"}},"type":"object","required":["pagination","data"],"title":"ProfilerAddressCounterpartiesResponse","description":"Response model for profiler address counterparties endpoint.\n\nContains the filtered counterparties data with metadata."},"PaginationInfo":{"properties":{"page":{"type":"integer","minimum":1,"title":"Page","description":"Current page number","default":1},"per_page":{"type":"integer","maximum":1000,"minimum":1,"title":"Per Page","description":"Number of records per page","default":10},"is_last_page":{"type":"boolean","title":"Is Last Page","description":"Whether this is the last page","default":true}},"type":"object","title":"PaginationInfo","description":"Pagination information for API responses."},"ProfilerCounterparty":{"properties":{"counterparty_address":{"type":"string","title":"Counterparty Address","description":"Counterparty address in hex format"},"tokens_info":{"anyOf":[{"items":{"$ref":"#/components/schemas/TokenInfo"},"type":"array"}],"title":"Tokens Info","description":"Information about tokens transferred with this counterparty"},"interaction_count":{"type":"integer","title":"Interaction Count","description":"Total number of interactions with this counterparty"},"total_volume_usd":{"anyOf":[{"type":"number"}],"title":"Total Volume Usd","description":"Total transaction volume in USD"},"volume_in_usd":{"anyOf":[{"type":"number"}],"title":"Volume In Usd","description":"Incoming transaction volume in USD"},"volume_out_usd":{"anyOf":[{"type":"number"}],"title":"Volume Out Usd","description":"Outgoing transaction volume in USD"},"counterparty_address_label":{"anyOf":[{"items":{"type":"string"},"type":"array"}],"title":"Counterparty Address Label","description":"List of labels associated with this counterparty"}},"type":"object","required":["counterparty_address","interaction_count"],"title":"ProfilerCounterparty","description":"Individual profiler counterparty record.\n\nRepresents a counterparty that a wallet has interacted with."},"TokenInfo":{"properties":{"token_address":{"type":"string","title":"Token Address","description":"Token contract address"},"token_symbol":{"type":"string","title":"Token Symbol","description":"Token symbol"},"token_name":{"type":"string","title":"Token Name","description":"Token name"},"num_transfer":{"type":"string","title":"Num Transfer","description":"Number of transfers"}},"type":"object","required":["token_address","token_symbol","token_name","num_transfer"],"title":"TokenInfo","description":"Token information for counterparty interactions."}},"responses":{"BadRequestError":{"description":"Bad Request - Invalid request parameters or malformed request","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"UnauthorizedError":{"description":"Authentication error - No API key found in request","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"ForbiddenError":{"description":"Forbidden - User does not have required subscription tier","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"NotFoundError":{"description":"Not Found - The requested resource was not found","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"ValidationError":{"description":"Validation error - Invalid request parameters","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"loc":{"type":"array","items":{"type":"string"}},"msg":{"type":"string"},"type":{"type":"string"}}}}}}}}},"TooManyRequestsError":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"},"retry_after":{"type":"integer","description":"Seconds to wait before retrying"}}}}}},"InternalServerError":{"description":"Internal Server Error - An unexpected error occurred","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}}}},"paths":{"/api/v1/profiler/address/counterparties":{"post":{"tags":["Profiler"],"summary":"Get Address Counterparties Data","description":"Get top counterparties that wallet addresses have interacted with, supporting different\ngrouping options (wallet or entity) and source filtering (Combined, Tokens, ETH).\nReturns interaction statistics including volume, frequency, and timing data.\n\nWhat it helps to answer:\n\n- Most frequent transaction partners by count and volume\n- Net value flows between addresses (inflows vs outflows)\n- Exchange and protocol interaction patterns\n- DeFi protocol usage and DEX trading counterparties\n- High-value transfer relationships and funding sources","operationId":"get_profiler_address_counterparties_api_v1_profiler_address_counterparties_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfilerAddressCounterpartiesRequest"}}},"required":true},"responses":{"200":{"description":"Address counterparties data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfilerAddressCounterpartiesResponse"}}}},"400":{"description":"Bad Request","$ref":"#/components/responses/BadRequestError"},"401":{"description":"Unauthorized","$ref":"#/components/responses/UnauthorizedError"},"403":{"description":"Forbidden","$ref":"#/components/responses/ForbiddenError"},"404":{"description":"Not Found","$ref":"#/components/responses/NotFoundError"},"422":{"description":"Unprocessable Content","$ref":"#/components/responses/ValidationError"},"429":{"description":"Too Many Requests","$ref":"#/components/responses/TooManyRequestsError"},"500":{"description":"Internal Server Error","$ref":"#/components/responses/InternalServerError"}}}}}} +``` + + + + + +# Address Related Wallets + +## Get Address Related Wallets Data + +> Get wallets that are related to the input address through various types\ +> of blockchain interactions and relationships. Returns detailed information\ +> about each related wallet including the relationship type, transaction details, and timing information. + +```json +{"openapi":"3.1.0","info":{"title":"Nansen API","version":"1.0.0"},"tags":[{"name":"Profiler","description":"Wallet profiling and analysis"}],"servers":[{"url":"https://api.nansen.ai","description":"Production server"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"apiKey","description":"API key for authentication"}},"schemas":{"ProfilerAddressRelatedWalletsRequest":{"properties":{"address":{"type":"string","title":"Address","description":"Address to get related wallets for"},"chain":{"$ref":"#/components/schemas/ProfilerAddressRelatedWalletsChain","description":"Blockchain chain for the related wallets data"},"pagination":{"$ref":"#/components/schemas/PaginationRequest","description":"Pagination parameters"},"order_by":{"anyOf":[{"items":{"$ref":"#/components/schemas/SortOrder_ProfilerAddressRelatedWalletsSortField_"},"type":"array"}],"title":"Order By","description":"Custom sort order to override the endpoint's default ordering"}},"additionalProperties":false,"type":"object","required":["address","chain"],"title":"ProfilerAddressRelatedWalletsRequest","description":""},"ProfilerAddressRelatedWalletsChain":{"type":"string","enum":["all","arbitrum","avalanche","base","berachain","blast","bnb","ethereum","goat","iotaevm","linea","mantle","optimism","plasma","polygon","ronin","sei","scroll","sonic","unichain","zksync","solana","bitcoin","starknet","ton","tron"],"title":"ProfilerAddressRelatedWalletsChain","description":"Enum for chains supported in profiler analysis."},"PaginationRequest":{"properties":{"page":{"type":"integer","minimum":1,"title":"Page","description":"Page number (1-based)","default":1},"per_page":{"type":"integer","maximum":1000,"minimum":1,"title":"Per Page","description":"Number of records per page (max 1000)","default":10}},"type":"object","title":"PaginationRequest","description":"Pagination parameters for API requests."},"SortOrder_ProfilerAddressRelatedWalletsSortField_":{"properties":{"field":{"$ref":"#/components/schemas/ProfilerAddressRelatedWalletsSortField","description":"Field to sort by"},"direction":{"$ref":"#/components/schemas/SortDirection","description":"Sort direction (ASC or DESC)"}},"type":"object","required":["field","direction"],"title":"SortOrder[ProfilerAddressRelatedWalletsSortField]"},"ProfilerAddressRelatedWalletsSortField":{"type":"string","enum":["order"],"title":"ProfilerAddressRelatedWalletsSortField","description":"Enum for sortable fields in profiler address related wallets."},"SortDirection":{"type":"string","enum":["ASC","DESC"],"title":"SortDirection","description":"Enum for sort directions."},"ProfilerAddressRelatedWalletsResponse":{"properties":{"pagination":{"$ref":"#/components/schemas/PaginationInfo","description":"Pagination information"},"data":{"items":{"$ref":"#/components/schemas/ProfilerRelatedWallet"},"type":"array","title":"Data","description":"List of related wallet records"}},"type":"object","required":["pagination","data"],"title":"ProfilerAddressRelatedWalletsResponse","description":"Response model for profiler address related wallets endpoint.\n\nContains the related wallets data with metadata."},"PaginationInfo":{"properties":{"page":{"type":"integer","minimum":1,"title":"Page","description":"Current page number","default":1},"per_page":{"type":"integer","maximum":1000,"minimum":1,"title":"Per Page","description":"Number of records per page","default":10},"is_last_page":{"type":"boolean","title":"Is Last Page","description":"Whether this is the last page","default":true}},"type":"object","title":"PaginationInfo","description":"Pagination information for API responses."},"ProfilerRelatedWallet":{"properties":{"address":{"type":"string","title":"Address","description":"Hexadecimal representation of the related address"},"address_label":{"anyOf":[{"type":"string"}],"title":"Address Label","description":"The label of the address"},"relation":{"type":"string","title":"Relation","description":"The type of relation between the address and the input address"},"transaction_hash":{"type":"string","title":"Transaction Hash","description":"Hexadecimal representation of the transaction hash"},"block_timestamp":{"type":"string","title":"Block Timestamp","description":"The timestamp of the transaction"},"order":{"type":"integer","title":"Order","description":"The order of the relation"},"chain":{"type":"string","title":"Chain","description":"The chain of the relation"}},"type":"object","required":["address","relation","transaction_hash","block_timestamp","order","chain"],"title":"ProfilerRelatedWallet","description":"Individual profiler related wallet record.\n\nRepresents a wallet that is related to the input address."}},"responses":{"BadRequestError":{"description":"Bad Request - Invalid request parameters or malformed request","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"UnauthorizedError":{"description":"Authentication error - No API key found in request","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"ForbiddenError":{"description":"Forbidden - User does not have required subscription tier","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"NotFoundError":{"description":"Not Found - The requested resource was not found","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"ValidationError":{"description":"Validation error - Invalid request parameters","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"loc":{"type":"array","items":{"type":"string"}},"msg":{"type":"string"},"type":{"type":"string"}}}}}}}}},"TooManyRequestsError":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"},"retry_after":{"type":"integer","description":"Seconds to wait before retrying"}}}}}},"InternalServerError":{"description":"Internal Server Error - An unexpected error occurred","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}}}},"paths":{"/api/v1/profiler/address/related-wallets":{"post":{"tags":["Profiler"],"summary":"Get Address Related Wallets Data","description":"Get wallets that are related to the input address through various types\nof blockchain interactions and relationships. Returns detailed information\nabout each related wallet including the relationship type, transaction details, and timing information.","operationId":"get_profiler_address_related_wallets_api_v1_profiler_address_related_wallets_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfilerAddressRelatedWalletsRequest"}}},"required":true},"responses":{"200":{"description":"Address related wallets data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfilerAddressRelatedWalletsResponse"}}}},"400":{"description":"Bad Request","$ref":"#/components/responses/BadRequestError"},"401":{"description":"Unauthorized","$ref":"#/components/responses/UnauthorizedError"},"403":{"description":"Forbidden","$ref":"#/components/responses/ForbiddenError"},"404":{"description":"Not Found","$ref":"#/components/responses/NotFoundError"},"422":{"description":"Unprocessable Content","$ref":"#/components/responses/ValidationError"},"429":{"description":"Too Many Requests","$ref":"#/components/responses/TooManyRequestsError"},"500":{"description":"Internal Server Error","$ref":"#/components/responses/InternalServerError"}}}}}} +``` +# Address PnL & Trade Performance + +## Get Address PnL Summary Data + +> Get aggregate PnL statistics and top profitable tokens for a specific wallet address.\ +> This endpoint provides comprehensive profit and loss analysis including realized PnL, win rate, and top performing tokens. + +```json +{"openapi":"3.1.0","info":{"title":"Nansen API","version":"1.0.0"},"tags":[{"name":"Profiler","description":"Wallet profiling and analysis"}],"servers":[{"url":"https://api.nansen.ai","description":"Production server"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"apiKey","description":"API key for authentication"}},"schemas":{"ProfilerAddressPnlSummaryRequest":{"properties":{"address":{"anyOf":[{"type":"string"}],"title":"Address","description":"Address to get PnL summary for"},"entity_name":{"anyOf":[{"type":"string"}],"title":"Entity Name","description":"Entity name to get PnL summary for"},"chain":{"$ref":"#/components/schemas/ProfilerChain","description":"Blockchain chain for the PnL data"},"date":{"$ref":"#/components/schemas/DateRange","description":"Date range for the PnL data"}},"additionalProperties":false,"type":"object","required":["chain","date"],"title":"ProfilerAddressPnlSummaryRequest","description":""},"ProfilerChain":{"type":"string","enum":["all","arbitrum","avalanche","base","berachain","blast","bnb","ethereum","goat","hyperevm","iotaevm","linea","mantle","optimism","plasma","polygon","ronin","sei","scroll","sonic","unichain","zksync","solana","bitcoin","starknet","ton","tron"],"title":"ProfilerChain","description":"Enum for chains supported in profiler analysis."},"DateRange":{"properties":{"from":{"anyOf":[{"type":"string"}],"title":"From","description":"Start date in ISO 8601 format"},"to":{"anyOf":[{"type":"string"}],"title":"To","description":"End date in ISO 8601 format"}},"type":"object","title":"DateRange","description":"Date range model matching the API schema."},"ProfilerAddressPnlSummaryResponse":{"properties":{"pagination":{"$ref":"#/components/schemas/PaginationInfo","description":"Pagination information"},"top5_tokens":{"items":{"$ref":"#/components/schemas/ProfilerTopToken"},"type":"array","title":"Top5 Tokens","description":"Top 5 tokens by realized profit"},"traded_token_count":{"type":"integer","title":"Traded Token Count","description":"Total number of different tokens that have been bought or sold"},"traded_times":{"type":"integer","title":"Traded Times","description":"Total number of sales (outflow or dex sell)"},"realized_pnl_usd":{"type":"number","title":"Realized Pnl Usd","description":"Total realized profit and loss in USD"},"realized_pnl_percent":{"type":"number","title":"Realized Pnl Percent","description":"Realized profit and loss as a percentage (not multiplied by 100)"},"win_rate":{"type":"number","title":"Win Rate","description":"Number of sales where price of the token was higher than cost basis"}},"type":"object","required":["pagination","top5_tokens","traded_token_count","traded_times","realized_pnl_usd","realized_pnl_percent","win_rate"],"title":"ProfilerAddressPnlSummaryResponse","description":"Response model for profiler address pnl-summary endpoint.\n\nContains aggregate PnL statistics and top profitable tokens."},"PaginationInfo":{"properties":{"page":{"type":"integer","minimum":1,"title":"Page","description":"Current page number","default":1},"per_page":{"type":"integer","maximum":1000,"minimum":1,"title":"Per Page","description":"Number of records per page","default":10},"is_last_page":{"type":"boolean","title":"Is Last Page","description":"Whether this is the last page","default":true}},"type":"object","title":"PaginationInfo","description":"Pagination information for API responses."},"ProfilerTopToken":{"properties":{"realized_pnl":{"anyOf":[{"type":"number"}],"title":"Realized Pnl","description":"Realized profit and loss in USD"},"realized_roi":{"anyOf":[{"type":"number"}],"title":"Realized Roi","description":"Realized return on investment as percentage"},"token_address":{"type":"string","title":"Token Address","description":"Token contract address"},"token_symbol":{"type":"string","title":"Token Symbol","description":"Token symbol"},"chain":{"type":"string","title":"Chain","description":"Blockchain chain"}},"type":"object","required":["realized_pnl","realized_roi","token_address","token_symbol","chain"],"title":"ProfilerTopToken","description":"Individual top token record for PnL summary.\n\nRepresents a top profitable token from the wallet's trading history."}},"responses":{"BadRequestError":{"description":"Bad Request - Invalid request parameters or malformed request","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"UnauthorizedError":{"description":"Authentication error - No API key found in request","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"ForbiddenError":{"description":"Forbidden - User does not have required subscription tier","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"NotFoundError":{"description":"Not Found - The requested resource was not found","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"ValidationError":{"description":"Validation error - Invalid request parameters","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"loc":{"type":"array","items":{"type":"string"}},"msg":{"type":"string"},"type":{"type":"string"}}}}}}}}},"TooManyRequestsError":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"},"retry_after":{"type":"integer","description":"Seconds to wait before retrying"}}}}}},"InternalServerError":{"description":"Internal Server Error - An unexpected error occurred","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}}}},"paths":{"/api/v1/profiler/address/pnl-summary":{"post":{"tags":["Profiler"],"summary":"Get Address PnL Summary Data","description":"Get aggregate PnL statistics and top profitable tokens for a specific wallet address.\nThis endpoint provides comprehensive profit and loss analysis including realized PnL, win rate, and top performing tokens.","operationId":"get_profiler_address_pnl_summary_api_v1_profiler_address_pnl_summary_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfilerAddressPnlSummaryRequest"}}},"required":true},"responses":{"200":{"description":"Address PnL summary data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfilerAddressPnlSummaryResponse"}}}},"400":{"description":"Bad Request","$ref":"#/components/responses/BadRequestError"},"401":{"description":"Unauthorized","$ref":"#/components/responses/UnauthorizedError"},"403":{"description":"Forbidden","$ref":"#/components/responses/ForbiddenError"},"404":{"description":"Not Found","$ref":"#/components/responses/NotFoundError"},"422":{"description":"Unprocessable Content","$ref":"#/components/responses/ValidationError"},"429":{"description":"Too Many Requests","$ref":"#/components/responses/TooManyRequestsError"},"500":{"description":"Internal Server Error","$ref":"#/components/responses/InternalServerError"}}}}}} +``` + +## Get Address PnL Data + +> Calculate profit and loss metrics for a specific address and token. Provides detailed trading performance including realized gains from sales and unrealized gains from current holdings.\ +> \ +> What it helps to answer:\ +> \ +> \- Realized profits or losses from completed token sales\ +> \- Unrealized gains or losses on current token holdings\ +> \- Average purchase and sale prices for the token\ +> \- Total return on investment +```json +{"openapi":"3.1.0","info":{"title":"Nansen API","version":"1.0.0"},"tags":[{"name":"Profiler","description":"Wallet profiling and analysis"}],"servers":[{"url":"https://api.nansen.ai","description":"Production server"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"apiKey","description":"API key for authentication"}},"schemas":{"ProfilerAddressPnlRequest":{"properties":{"address":{"anyOf":[{"type":"string"}],"title":"Address","description":"Wallet address to get PnL for"},"entity_name":{"anyOf":[{"type":"string"}],"title":"Entity Name","description":"Entity name to get PnL for"},"chain":{"$ref":"#/components/schemas/ProfilerChain","description":"Blockchain chain for the PnL data"},"date":{"anyOf":[{"$ref":"#/components/schemas/DateRange"}],"description":"Date range for PnL analysis"},"filters":{"anyOf":[{"$ref":"#/components/schemas/ProfilerAddressPnlFilters"}],"description":"Additional filters to apply."},"pagination":{"$ref":"#/components/schemas/PaginationRequest","description":"Pagination parameters"},"order_by":{"anyOf":[{"items":{"$ref":"#/components/schemas/SortOrder_ProfilerAddressPnlSortField_"},"type":"array"}],"title":"Order By","description":"Custom sort order to override the endpoint's default ordering (default: pnl_usd_realised DESC).\n\nIf the parameter show_realized is false, the default sort order is pnl_usd_unrealised DESC."}},"additionalProperties":false,"type":"object","required":["chain"],"title":"ProfilerAddressPnlRequest","description":""},"ProfilerChain":{"type":"string","enum":["all","arbitrum","avalanche","base","berachain","blast","bnb","ethereum","goat","hyperevm","iotaevm","linea","mantle","optimism","plasma","polygon","ronin","sei","scroll","sonic","unichain","zksync","solana","bitcoin","starknet","ton","tron"],"title":"ProfilerChain","description":"Enum for chains supported in profiler analysis."},"DateRange":{"properties":{"from":{"anyOf":[{"type":"string"}],"title":"From","description":"Start date in ISO 8601 format"},"to":{"anyOf":[{"type":"string"}],"title":"To","description":"End date in ISO 8601 format"}},"type":"object","title":"DateRange","description":"Date range model matching the API schema."},"ProfilerAddressPnlFilters":{"properties":{"show_realized":{"anyOf":[{"type":"boolean"}],"title":"Show Realized","description":"Include realized profit/loss in results","default":false},"token_address":{"anyOf":[{"type":"string"}],"title":"Token Address","description":"Token address filter for specific token PnL"}},"additionalProperties":false,"type":"object","title":"ProfilerAddressPnlFilters","description":"Filters for profiler address PnL endpoint.\n\nThese filters control token filtering and realized PnL options for analysis."},"PaginationRequest":{"properties":{"page":{"type":"integer","minimum":1,"title":"Page","description":"Page number (1-based)","default":1},"per_page":{"type":"integer","maximum":1000,"minimum":1,"title":"Per Page","description":"Number of records per page (max 1000)","default":10}},"type":"object","title":"PaginationRequest","description":"Pagination parameters for API requests."},"SortOrder_ProfilerAddressPnlSortField_":{"properties":{"field":{"$ref":"#/components/schemas/ProfilerAddressPnlSortField","description":"Field to sort by"},"direction":{"$ref":"#/components/schemas/SortDirection","description":"Sort direction (ASC or DESC)"}},"type":"object","required":["field","direction"],"title":"SortOrder[ProfilerAddressPnlSortField]"},"ProfilerAddressPnlSortField":{"type":"string","enum":["pnl_usd_realised","roi_percent_realised","pnl_usd_unrealised","roi_percent_unrealised","bought_usd","sold_usd","holding_usd"],"title":"ProfilerAddressPnlSortField","description":"Enum for sortable fields in profiler address PnL."},"SortDirection":{"type":"string","enum":["ASC","DESC"],"title":"SortDirection","description":"Enum for sort directions."},"ProfilerAddressPnlResponse":{"properties":{"pagination":{"$ref":"#/components/schemas/PaginationInfo","description":"Pagination information"},"data":{"items":{"$ref":"#/components/schemas/ProfilerAddressPnl"},"type":"array","title":"Data","description":"List of PnL records"}},"type":"object","required":["pagination","data"],"title":"ProfilerAddressPnlResponse","description":"Response model for profiler address pnl endpoint.\n\nContains the filtered PnL data with metadata."},"PaginationInfo":{"properties":{"page":{"type":"integer","minimum":1,"title":"Page","description":"Current page number","default":1},"per_page":{"type":"integer","maximum":1000,"minimum":1,"title":"Per Page","description":"Number of records per page","default":10},"is_last_page":{"type":"boolean","title":"Is Last Page","description":"Whether this is the last page","default":true}},"type":"object","title":"PaginationInfo","description":"Pagination information for API responses."},"ProfilerAddressPnl":{"properties":{"token_address":{"type":"string","title":"Token Address","description":"Hexadecimal representation of the token's address"},"token_symbol":{"type":"string","title":"Token Symbol","description":"Symbol of the token"},"token_price":{"anyOf":[{"type":"number"}],"title":"Token Price","description":"Price of the token on date_to"},"roi_percent_realised":{"anyOf":[{"type":"number"}],"title":"Roi Percent Realised","description":"Realised return on investment for only realised gains (not multiplied by 100)"},"pnl_usd_realised":{"anyOf":[{"type":"number"}],"title":"Pnl Usd Realised","description":"Realised profit and loss in USD"},"pnl_usd_unrealised":{"anyOf":[{"type":"number"}],"title":"Pnl Usd Unrealised","description":"Unrealised profit and loss in USD"},"roi_percent_unrealised":{"anyOf":[{"type":"number"}],"title":"Roi Percent Unrealised","description":"Unrealised return on investment for only unrealised gains (not multiplied by 100)"},"bought_amount":{"anyOf":[{"type":"number"}],"title":"Bought Amount","description":"Amount of tokens bought from date_from to date_to"},"bought_usd":{"anyOf":[{"type":"number"}],"title":"Bought Usd","description":"USD value of bought tokens"},"cost_basis_usd":{"anyOf":[{"type":"number"}],"title":"Cost Basis Usd","description":"Cost basis of tokens in USD as of date_to"},"sold_amount":{"anyOf":[{"type":"number"}],"title":"Sold Amount","description":"Amount of tokens sold from date_from to date_to"},"sold_usd":{"anyOf":[{"type":"number"}],"title":"Sold Usd","description":"USD value of sold tokens"},"avg_sold_price_usd":{"anyOf":[{"type":"number"}],"title":"Avg Sold Price Usd","description":"Average sale price of tokens sold in USD"},"holding_amount":{"anyOf":[{"type":"number"}],"title":"Holding Amount","description":"Current token balance"},"holding_usd":{"anyOf":[{"type":"number"}],"title":"Holding Usd","description":"USD value of token balance"},"nof_buys":{"type":"string","title":"Nof Buys","description":"Number of buys (either inflow or dex buy)"},"nof_sells":{"type":"string","title":"Nof Sells","description":"Number of sells (either outflow or dex sell)"},"max_balance_held":{"anyOf":[{"type":"number"}],"title":"Max Balance Held","description":"Maximum amount of tokens held at some point in time"},"max_balance_held_usd":{"anyOf":[{"type":"number"}],"title":"Max Balance Held Usd","description":"Maximum amount of tokens in current USD value, held at some point in time"}},"type":"object","required":["token_address","token_symbol","nof_buys","nof_sells"],"title":"ProfilerAddressPnl","description":"Individual profiler address PnL record.\n\nRepresents PnL data for a token traded by the wallet."}},"responses":{"BadRequestError":{"description":"Bad Request - Invalid request parameters or malformed request","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"UnauthorizedError":{"description":"Authentication error - No API key found in request","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"ForbiddenError":{"description":"Forbidden - User does not have required subscription tier","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"NotFoundError":{"description":"Not Found - The requested resource was not found","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"ValidationError":{"description":"Validation error - Invalid request parameters","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"loc":{"type":"array","items":{"type":"string"}},"msg":{"type":"string"},"type":{"type":"string"}}}}}}}}},"TooManyRequestsError":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"},"retry_after":{"type":"integer","description":"Seconds to wait before retrying"}}}}}},"InternalServerError":{"description":"Internal Server Error - An unexpected error occurred","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}}}},"paths":{"/api/v1/profiler/address/pnl":{"post":{"tags":["Profiler"],"summary":"Get Address PnL Data","description":"Calculate profit and loss metrics for a specific address and token. Provides detailed trading performance including realized gains from sales and unrealized gains from current holdings.\n\nWhat it helps to answer:\n\n- Realized profits or losses from completed token sales\n- Unrealized gains or losses on current token holdings\n- Average purchase and sale prices for the token\n- Total return on investment","operationId":"get_profiler_address_pnl_api_v1_profiler_address_pnl_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfilerAddressPnlRequest"}}},"required":true},"responses":{"200":{"description":"Address PnL data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfilerAddressPnlResponse"}}}},"400":{"description":"Bad Request","$ref":"#/components/responses/BadRequestError"},"401":{"description":"Unauthorized","$ref":"#/components/responses/UnauthorizedError"},"403":{"description":"Forbidden","$ref":"#/components/responses/ForbiddenError"},"404":{"description":"Not Found","$ref":"#/components/responses/NotFoundError"},"422":{"description":"Unprocessable Content","$ref":"#/components/responses/ValidationError"},"429":{"description":"Too Many Requests","$ref":"#/components/responses/TooManyRequestsError"},"500":{"description":"Internal Server Error","$ref":"#/components/responses/InternalServerError"}}}}}} +``` + + + +# Address Labels + +## profiler/address/labels + +> Address and its labels + +```json +{"openapi":"3.1.0","info":{"title":"Nansen API","version":"1.0.0"},"tags":[{"name":"Wallet Profiler","description":"Wallet profiling and analysis (Beta)"}],"servers":[{"url":"https://api.nansen.ai","description":"Production server"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"apiKey","description":"API key for authentication"}},"schemas":{"beta_profiler_address_labels_response":{"type":"object","description":"Address and its labels","properties":{"label":{"type":"string"},"category":{"type":"string"},"definition":{"type":"string"},"smEarnedDate":{"type":"string","format":"date-time"},"fullname":{"type":"string"}}}},"responses":{"beta_BadRequestError":{"description":"Bad request - Invalid parameters or request body","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"object","properties":{"parameters":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}}}}}}}}},"beta_ForbiddenError":{"description":"Forbidden - User does not have required subscription tier","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"beta_InternalServerError":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}}}},"paths":{"/api/beta/profiler/address/labels":{"post":{"summary":"profiler/address/labels","description":"Address and its labels","tags":["Wallet Profiler"],"requestBody":{"required":true,"description":"Parameters must be passed in a 'parameters' object in the request body","content":{"application/json":{"schema":{"type":"object","properties":{"parameters":{"type":"object","description":"Object containing all parameters for the endpoint","required":["address"],"properties":{"chain":{"type":"string","description":"","default":"ethereum"},"address":{"type":"string","description":""},"entity":{"type":"string","description":""},"label":{"type":"string","description":""}}},"pagination":{"type":"object","description":"Pagination options","properties":{"page":{"type":"integer","default":1,"description":"Page number"},"recordsPerPage":{"type":"integer","default":100,"description":"Number of records per page"}},"default":{"page":1,"recordsPerPage":100}}},"required":["parameters"]}}}},"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/beta_profiler_address_labels_response"}}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/responses/beta_BadRequestError"}}}},"401":{"description":"Authentication error","content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"detail":{"type":"string"}}},{"type":"object","properties":{"detail":{"type":"string"}}}]}}}},"403":{"description":"Forbidden - Subscription tier required","content":{"application/json":{"schema":{"$ref":"#/components/responses/beta_ForbiddenError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/responses/beta_InternalServerError"}}}}}}}}} +``` + +### Required Parameters + +
FieldTypeDescription
chainstringBlockchain network. Select all to query all EVM chains
addressstringThe blockchain address to query for labels
+ +### Response Structure + +The API returns an array of label objects with the following fields: + +| Field | Type | Description | +| -------------- | ----------- | -------------------------------------------------------------- | +| `label` | string | The specific label name assigned to the address | +| `category` | string | The category of the label (see categories below) | +| `definition` | string | Detailed description of what the label represents | +| `smEarnedDate` | string/null | Date when the address earned Smart Money status (ISO format) | +| `fullname` | string | Full descriptive name or entity name associated with the label | + +#### Label Categories + +* **`behavioral`** - Labels based on trading patterns and on-chain behavior +* **`defi`** - DeFi protocol interactions and usage +* **`social`** - Social identifiers and public profiles +* **`smart_money`** - Smart money and profitable trader classifications +* **`others`** - Miscellaneous labels including airdrops, platform usage, etc. + +### Example Request + +json + +```json +{ + "parameters": { + "chain": "solana", + "address": "H1gJR25VXi5Ape1gAU7fTWzZFWaCpuP3rzRtKun8Dwo2" + }, + "pagination": { + "page": 1, + "recordsPerPage": 100 + } +} +``` + +### Example Response + +json + +```json +[ + { + "label": "hornybeliever.sol", + "category": "social", + "definition": "Shows an address owns a particular Solana Name Service domain name (ex. user.sol).", + "smEarnedDate": null, + "fullname": "🤓 👤 pow" + }, + { + "label": "Top 100 on PENGU Leaderboard", + "category": "behavioral", + "definition": "Address is on the Top 100 Addresses by Realized PnL for the token.", + "smEarnedDate": null, + "fullname": "🤓 👤 pow" + }, + { + "label": "30D Smart Trader", + "category": "smart_money", + "definition": "Top addresses based on their realized and unrealized profit in the last 30 days.", + "smEarnedDate": null, + "fullname": "🤓 👤 pow" + } +] +``` + + + +portfolio : +# Portfolio + +## Get Portfolio DeFi Holdings Data + +> Get simplified DeFi holdings for a wallet address with aggregated tokens\ +> and protocol summaries in a user-friendly format. + +```json +{"openapi":"3.1.0","info":{"title":"Nansen API","version":"1.0.0"},"tags":[],"servers":[{"url":"https://api.nansen.ai","description":"Production server"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"apiKey","description":"API key for authentication"}},"schemas":{"PortfolioDefiHoldingsRequest":{"properties":{"wallet_address":{"type":"string","title":"Wallet Address","description":"Wallet address to get DeFi holdings for"}},"type":"object","required":["wallet_address"],"title":"PortfolioDefiHoldingsRequest","description":"Request model for portfolio DeFi holdings endpoint."},"PortfolioDefiHoldingsResponse":{"properties":{"summary":{"$ref":"#/components/schemas/HoldingsSummary","description":"Overall portfolio summary"},"protocols":{"items":{"$ref":"#/components/schemas/ProtocolHolding"},"type":"array","title":"Protocols","description":"Protocol-specific holdings with token breakdown"}},"type":"object","required":["summary","protocols"],"title":"PortfolioDefiHoldingsResponse","description":"Response model for portfolio DeFi holdings endpoint."},"HoldingsSummary":{"properties":{"total_value_usd":{"type":"number","title":"Total Value Usd","description":"Total USD value of all holdings"},"total_assets_usd":{"type":"number","title":"Total Assets Usd","description":"Total USD value of all assets"},"total_debts_usd":{"type":"number","title":"Total Debts Usd","description":"Total USD value of all debts"},"total_rewards_usd":{"type":"number","title":"Total Rewards Usd","description":"Total USD value of all rewards"},"token_count":{"type":"integer","title":"Token Count","description":"Total number of unique tokens"},"protocol_count":{"type":"integer","title":"Protocol Count","description":"Total number of protocols"}},"type":"object","required":["total_value_usd","total_assets_usd","total_debts_usd","total_rewards_usd","token_count","protocol_count"],"title":"HoldingsSummary","description":"Summary statistics for DeFi holdings."},"ProtocolHolding":{"properties":{"protocol_name":{"type":"string","title":"Protocol Name","description":"User-friendly protocol name"},"chain":{"type":"string","title":"Chain","description":"Blockchain network"},"total_value_usd":{"type":"number","title":"Total Value Usd","description":"Total USD value in this protocol"},"total_assets_usd":{"type":"number","title":"Total Assets Usd","description":"Total USD value of assets in this protocol"},"total_debts_usd":{"type":"number","title":"Total Debts Usd","description":"Total USD value of debts in this protocol"},"total_rewards_usd":{"type":"number","title":"Total Rewards Usd","description":"Total USD value of rewards in this protocol"},"tokens":{"items":{"$ref":"#/components/schemas/ProtocolToken"},"type":"array","title":"Tokens","description":"Token holdings in this protocol"}},"type":"object","required":["protocol_name","chain","total_value_usd","total_assets_usd","total_debts_usd","total_rewards_usd","tokens"],"title":"ProtocolHolding","description":"Holdings summary for a specific protocol."},"ProtocolToken":{"properties":{"address":{"anyOf":[{"type":"string"}],"title":"Address","description":"Token contract address (null for native tokens)"},"symbol":{"anyOf":[{"type":"string"}],"title":"Symbol","description":"Token symbol"},"amount":{"anyOf":[{"type":"number"}],"title":"Amount","description":"Token amount"},"value_usd":{"anyOf":[{"type":"number"}],"title":"Value Usd","description":"USD value"},"position_type":{"type":"string","title":"Position Type","description":"Position type: deposit, stake, borrow, or mixed"}},"type":"object","required":["symbol","amount","value_usd","position_type"],"title":"ProtocolToken","description":"Individual token holding within a protocol."}},"responses":{"BadRequestError":{"description":"Bad Request - Invalid request parameters or malformed request","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"UnauthorizedError":{"description":"Authentication error - No API key found in request","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"ForbiddenError":{"description":"Forbidden - User does not have required subscription tier","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"NotFoundError":{"description":"Not Found - The requested resource was not found","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}},"ValidationError":{"description":"Validation error - Invalid request parameters","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"loc":{"type":"array","items":{"type":"string"}},"msg":{"type":"string"},"type":{"type":"string"}}}}}}}}},"TooManyRequestsError":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"},"retry_after":{"type":"integer","description":"Seconds to wait before retrying"}}}}}},"InternalServerError":{"description":"Internal Server Error - An unexpected error occurred","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}}}}}}}},"paths":{"/api/v1/portfolio/defi-holdings":{"post":{"tags":["Portfolio"],"summary":"Get Portfolio DeFi Holdings Data","description":"Get simplified DeFi holdings for a wallet address with aggregated tokens\n and protocol summaries in a user-friendly format.","operationId":"portfolio_defi_holdings_v1_api_v1_portfolio_defi_holdings_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortfolioDefiHoldingsRequest"}}},"required":true},"responses":{"200":{"description":"Portfolio DeFi holdings data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortfolioDefiHoldingsResponse"}}}},"400":{"description":"Bad Request","$ref":"#/components/responses/BadRequestError"},"401":{"description":"Unauthorized","$ref":"#/components/responses/UnauthorizedError"},"403":{"description":"Forbidden","$ref":"#/components/responses/ForbiddenError"},"404":{"description":"Not Found","$ref":"#/components/responses/NotFoundError"},"422":{"description":"Unprocessable Content","$ref":"#/components/responses/ValidationError"},"429":{"description":"Too Many Requests","$ref":"#/components/responses/TooManyRequestsError"},"500":{"description":"Internal Server Error","$ref":"#/components/responses/InternalServerError"}}}}}} +``` + +### Output Field Meanings + +#### Top-Level Fields + +| Field | Description | +| -------------------- | --------------------------------------------------------------------------- | +| `protocolsUsed` | Array of protocol names the wallet actively uses (e.g., "aave-v3-ethereum") | +| `holdingsByProtocol` | Detailed breakdown of positions per protocol | +| `success` | Boolean indicating API call success | +| `totalProtocols` | Count of protocols with detected activity | + +#### Position Types within `holdingsByProtocol` + +| Type | Description | +| --------------------- | -------------------------------------------------------------------------------------------- | +| `deposits`/`lendings` | Assets supplied to lending protocols (Aave, Compound), including amounts, value, and rewards | +| `borrows` | Borrowed assets with debt ratios and health factors | +| `stakings` | Tokens staked for rewards (liquid staking, governance tokens) | +| `positions` | Complex positions like LP tokens, derivatives, or structured products | +| `locked` | Time-locked or vested tokens (e.g., vote-escrowed tokens) | +| `rewards` | Claimable but unclaimed protocol rewards | +| `farms` | Yield farming positions with staked LP tokens | + +#### Position Detail Structure + +| Field | Description | +| --------- | --------------------------------------------------------------------------------- | +| `type` | Position category (e.g., "lending", "common", "locked") | +| `summary` | High-level metrics (asset value, rewards, debt) | +| `detail` | Granular breakdown including individual token balances, prices, and price changes | + +## Supported Protocols + +You can find the list of supported protocols on each supported chain by [clicking here](https://app.nansen.ai/portfolio/protocols). + +## Usage Guide: Creating Complete Portfolio Overview + +Use the following steps to create a complete Portfolio Overview: + +**Step 1: Fetch DeFi Positions**\ +Get active protocol positions, staking rewards, and lending activities. This shows how assets are being used in DeFi. + +**Step 2: Fetch Wallet Balances** [**(Link Here)**](https://docs.nansen.ai/api/profiler/balances#post-beta-profiler-address-balances)\ +Retrieve all token holdings across chains, including idle tokens not actively deployed in protocols. + +**Step 3: Combine & Analyze** + +* Total Portfolio Value = DeFi positions + wallet balances +* Strategy Analysis: Compare liquid vs. staked vs. lending positions +* Chain Distribution: Identify multi-chain allocation patterns +* Risk Assessment: Analyze borrowing ratios, protocol concentration + From 269d7eab9f301fd7d868725fe9ed451bcca85f3c Mon Sep 17 00:00:00 2001 From: Sanyam Date: Tue, 14 Oct 2025 20:31:13 +0530 Subject: [PATCH 3/3] Refactor getDefiHoldings and getPnl actions for improved input handling and multi-chain support; add test scripts for both actions. --- .../Portfolio/getDefiHoldingsAction.ts | 198 ++------------- .../NansenAction/Profiler/getPnlAction.ts | 238 +++++++++--------- agentkit-demo/test-defi-holdings.ts | 11 + agentkit-demo/test-getPnl.ts | 22 ++ 4 files changed, 181 insertions(+), 288 deletions(-) create mode 100644 agentkit-demo/test-defi-holdings.ts create mode 100644 agentkit-demo/test-getPnl.ts diff --git a/agentkit-core/src/actions/NansenAction/Portfolio/getDefiHoldingsAction.ts b/agentkit-core/src/actions/NansenAction/Portfolio/getDefiHoldingsAction.ts index 13c421a..5b6e109 100644 --- a/agentkit-core/src/actions/NansenAction/Portfolio/getDefiHoldingsAction.ts +++ b/agentkit-core/src/actions/NansenAction/Portfolio/getDefiHoldingsAction.ts @@ -21,129 +21,27 @@ This endpoint requires a Nansen API key to be configured. export const GetDefiHoldingsInput = z .object({ wallet_address: z.string().describe("The wallet address to get DeFi holdings for"), - - chains: z - .array( - z.enum([ - "all", - "arbitrum", - "avalanche", - "base", - "berachain", - "blast", - "bnb", - "ethereum", - "goat", - "hyperevm", - "iotaevm", - "linea", - "mantle", - "optimism", - "plasma", - "polygon", - "ronin", - "sei", - "scroll", - "sonic", - "unichain", - "zksync", - "solana", - ]), - ) - .describe("Chains to include in the analysis. Use 'all' to include all available chains."), - - filters: z - .object({ - protocol_name: z.string().optional().describe("Protocol name filter"), - protocol_type: z.array(z.string()).optional().describe("Protocol type filter"), - token_address: z.string().optional().describe("Token address filter"), - token_symbol: z.string().optional().describe("Token symbol filter"), - position_type: z.array(z.string()).optional().describe("Position type filter"), - value_usd: z - .object({ - min: z.number().optional(), - max: z.number().optional(), - }) - .optional() - .describe("Value range filter in USD"), - timestamp: z - .object({ - from: z.string().optional(), - to: z.string().optional(), - }) - .optional() - .describe("Timestamp range filter"), - }) - .optional() - .describe("Additional filters to apply"), - - pagination: z - .object({ - page: z.number().min(1).default(1).describe("Page number (1-based)"), - per_page: z - .number() - .min(1) - .max(1000) - .default(10) - .describe("Number of records per page (max 1000)"), - }) - .optional() - .describe("Pagination parameters"), - - order_by: z - .array( - z.object({ - field: z - .enum([ - "chain", - "wallet_address", - "protocol_name", - "protocol_type", - "token_address", - "token_symbol", - "position_type", - "value_usd", - "timestamp", - ]) - .describe("Field to sort by"), - direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), - }), - ) - .optional() - .describe("Custom sort order to override the endpoint's default ordering"), }) - .strip() - .describe("Instructions for getting DeFi holdings data"); + .describe("Input schema for getting DeFi holdings data."); -/** - * Response interface for DeFi holdings data. - */ -interface DefiHolding { - chain: string; - wallet_address: string; - protocol_name: string; - protocol_type: string; - token_address: string; +interface TokenHolding { token_symbol: string; - position_type: string; - value_usd?: number; - timestamp: string; + amount: number; + value_usd: number; } -interface DefiHoldingsResponse { - data: DefiHolding[]; - pagination: { - page: number; - per_page: number; - is_last_page: boolean; - }; +interface ProtocolHolding { + protocol_name: string; + chain: string; + total_value_usd: number; + tokens: TokenHolding[]; } /** * Fetches DeFi holdings data from Nansen API. * * @param _wallet - The smart account (not used for this action). - * @param args - The input arguments containing wallet address, chains, filters, pagination, and sorting options. + * @param args - The input arguments containing wallet address. * @returns A formatted string containing the DeFi holdings data. */ export async function getDefiHoldings( @@ -156,83 +54,41 @@ export async function getDefiHoldings( return "Error: NANSEN_API_KEY environment variable is required but not set."; } - const requestBody = { - wallet_address: args.wallet_address, - chains: args.chains, - ...(args.filters && { filters: args.filters }), - ...(args.pagination && { pagination: args.pagination }), - ...(args.order_by && { order_by: args.order_by }), - }; - const response = await fetch("https://api.nansen.ai/api/v1/portfolio/defi-holdings", { method: "POST", headers: { "Content-Type": "application/json", apiKey: apiKey, - "User-Agent": "0xGasless-AgentKit/1.0", }, - body: JSON.stringify(requestBody), + body: JSON.stringify({ wallet_address: args.wallet_address }), }); if (!response.ok) { - if (response.status === 401) { - return "Error: Invalid Nansen API key. Please check your NANSEN_API_KEY environment variable."; - } - if (response.status === 403) { - return "Error: Insufficient subscription tier for this endpoint."; - } - if (response.status === 429) { - return "Error: Rate limit exceeded. Please wait before making another request."; - } - return `Error fetching DeFi holdings: ${response.status} ${response.statusText}`; + const errorData = await response.json(); + return `Error fetching DeFi holdings: ${response.statusText} - ${JSON.stringify(errorData)}`; } - const data: DefiHoldingsResponse = await response.json(); + const data = await response.json(); - if (!data.data || data.data.length === 0) { + if (!data.protocols || data.protocols.length === 0) { return `No DeFi holdings found for wallet ${args.wallet_address}.`; } let result = `🏦 DeFi Holdings for ${args.wallet_address}:\n\n`; - - data.data.forEach((holding, index) => { - const timestamp = new Date(holding.timestamp).toLocaleString(); - const protocolEmoji = - holding.protocol_type === "lending" - ? "💰" - : holding.protocol_type === "dex" - ? "🔄" - : holding.protocol_type === "yield" - ? "📈" - : holding.protocol_type === "staking" - ? "🔒" - : "🏛️"; - const positionEmoji = - holding.position_type === "supply" - ? "📤" - : holding.position_type === "borrow" - ? "📥" - : holding.position_type === "liquidity" - ? "💧" - : "📊"; - - result += `${index + 1}. DeFi Position ${protocolEmoji}${positionEmoji}\n`; - result += ` • Protocol: ${holding.protocol_name}\n`; - result += ` • Type: ${holding.protocol_type}\n`; - result += ` • Position: ${holding.position_type}\n`; - result += ` • Token: ${holding.token_symbol} (${holding.token_address})\n`; - result += ` • Chain: ${holding.chain}\n`; - if (holding.value_usd) { - result += ` • Value: $${holding.value_usd.toLocaleString()}\n`; - } - result += ` • Last Updated: ${timestamp}\n`; - result += "\n"; + result += `**Summary:**\n`; + result += ` - Total Value: $${data.summary.total_value_usd.toLocaleString()}\n`; + result += ` - Assets: $${data.summary.total_assets_usd.toLocaleString()}\n`; + result += ` - Debts: $${data.summary.total_debts_usd.toLocaleString()}\n\n`; + + result += `**Protocols:**\n`; + data.protocols.forEach((protocol: ProtocolHolding) => { + result += `\n- **${protocol.protocol_name} on ${protocol.chain}**\n`; + result += ` - Total Value: $${protocol.total_value_usd.toLocaleString()}\n`; + protocol.tokens.forEach((token: TokenHolding) => { + result += ` - ${token.token_symbol}: ${token.amount} ($${token.value_usd.toLocaleString()})\n`; + }); }); - if (!data.pagination.is_last_page) { - result += `Page ${data.pagination.page} of results. Use pagination to get more results.\n`; - } - return result; } catch (error) { const errorMessage = error instanceof Error ? error.message : "An unknown error occurred"; diff --git a/agentkit-core/src/actions/NansenAction/Profiler/getPnlAction.ts b/agentkit-core/src/actions/NansenAction/Profiler/getPnlAction.ts index f625f92..41d8b96 100644 --- a/agentkit-core/src/actions/NansenAction/Profiler/getPnlAction.ts +++ b/agentkit-core/src/actions/NansenAction/Profiler/getPnlAction.ts @@ -7,7 +7,7 @@ Retrieve detailed profit and loss information for a specific wallet address acro Key Features: - Detailed PnL information for a specific wallet -- Multi-chain support +- Multi-chain support (looped client-side) - Transaction-level PnL data - Individual trade performance - Detailed trading metrics @@ -15,17 +15,13 @@ Key Features: This endpoint requires a Nansen API key to be configured. `; -/** - * Input schema for getting PnL data. - */ +// Input schema (chains now ENUM but for API only one chain per request) export const GetPnlInput = z .object({ wallet_address: z.string().describe("The wallet address to get PnL data for"), - chains: z .array( z.enum([ - "all", "arbitrum", "avalanche", "base", @@ -50,79 +46,61 @@ export const GetPnlInput = z "solana", ]), ) - .describe("Chains to include in the analysis. Use 'all' to include all available chains."), - + .describe("Chains to include in the analysis. Each chain requested separately."), filters: z .object({ - transaction_hash: z.string().optional().describe("Transaction hash filter"), - token_address: z.string().optional().describe("Token address filter"), - token_symbol: z.string().optional().describe("Token symbol filter"), - token_sectors: z.array(z.string()).optional().describe("Token sectors filter"), + transaction_hash: z.string().optional(), + token_address: z.string().optional(), + token_symbol: z.string().optional(), + token_sectors: z.array(z.string()).optional(), pnl_usd: z .object({ min: z.number().optional(), max: z.number().optional(), }) - .optional() - .describe("PnL range filter in USD"), + .optional(), pnl_percent: z .object({ min: z.number().optional(), max: z.number().optional(), }) - .optional() - .describe("PnL percentage range filter"), + .optional(), timestamp: z .object({ from: z.string().optional(), to: z.string().optional(), }) - .optional() - .describe("Timestamp range filter"), + .optional(), }) - .optional() - .describe("Additional filters to apply"), - + .optional(), pagination: z .object({ - page: z.number().min(1).default(1).describe("Page number (1-based)"), - per_page: z - .number() - .min(1) - .max(1000) - .default(10) - .describe("Number of records per page (max 1000)"), + page: z.number().min(1).default(1), + per_page: z.number().min(1).max(1000).default(10), }) - .optional() - .describe("Pagination parameters"), - + .optional(), order_by: z .array( z.object({ - field: z - .enum([ - "chain", - "transaction_hash", - "token_address", - "token_symbol", - "token_sectors", - "pnl_usd", - "pnl_percent", - "timestamp", - ]) - .describe("Field to sort by"), - direction: z.enum(["ASC", "DESC"]).describe("Sort direction"), + field: z.enum([ + "chain", + "transaction_hash", + "token_address", + "token_symbol", + "token_sectors", + "pnl_usd", + "pnl_percent", + "timestamp", + ]), + direction: z.enum(["ASC", "DESC"]), }), ) - .optional() - .describe("Custom sort order to override the endpoint's default ordering"), + .optional(), }) .strip() .describe("Instructions for getting PnL data"); -/** - * Response interface for PnL data. - */ +// Response Interface interface Pnl { chain: string; transaction_hash: string; @@ -143,97 +121,123 @@ interface PnlResponse { }; } -/** - * Fetches PnL data from Nansen API. - * - * @param _wallet - The smart account (not used for this action). - * @param args - The input arguments containing wallet address, chains, filters, pagination, and sorting options. - * @returns A formatted string containing the PnL data. - */ +interface PnlRequestBody { + address: string; + chain: string; + date?: { from?: string; to?: string }; + pagination?: { page: number; per_page: number }; + order_by?: { field: string; direction: string }[]; + transaction_hash?: string; + token_address?: string; + token_symbol?: string; + token_sectors?: string[]; + pnl_usd?: { min?: number; max?: number }; + pnl_percent?: { min?: number; max?: number }; +} + +// Main function - loops over chains, fetches separately! export async function getPnl( _wallet: ZeroXgaslessSmartAccount, args: z.infer, ): Promise { try { const apiKey = process.env.NANSEN_API_KEY; - if (!apiKey) { - return "Error: NANSEN_API_KEY environment variable is required but not set."; - } - - const requestBody = { - wallet_address: args.wallet_address, - chains: args.chains, - ...(args.filters && { filters: args.filters }), - ...(args.pagination && { pagination: args.pagination }), - ...(args.order_by && { order_by: args.order_by }), - }; - - const response = await fetch("https://api.nansen.ai/api/v1/profiler/pnl", { - method: "POST", - headers: { - "Content-Type": "application/json", - apiKey: apiKey, - "User-Agent": "0xGasless-AgentKit/1.0", - }, - body: JSON.stringify(requestBody), - }); - - if (!response.ok) { - if (response.status === 401) { - return "Error: Invalid Nansen API key. Please check your NANSEN_API_KEY environment variable."; - } - if (response.status === 403) { - return "Error: Insufficient subscription tier for this endpoint."; + if (!apiKey) return "Error: NANSEN_API_KEY environment variable is required but not set."; + + let allResults = ""; + + for (const chain of args.chains) { + const requestBody: PnlRequestBody = { + address: args.wallet_address, // API expects 'address' + chain: chain, // API expects 'chain' (string) + }; + + // Time filter mapping + if (args.filters?.timestamp) { + requestBody.date = { + from: args.filters.timestamp.from, + to: args.filters.timestamp.to, + }; } - if (response.status === 429) { - return "Error: Rate limit exceeded. Please wait before making another request."; + + // Pagination + if (args.pagination) { + requestBody.pagination = args.pagination; } - return `Error fetching PnL: ${response.status} ${response.statusText}`; - } - const data: PnlResponse = await response.json(); + // If sorting, handle + if (args.order_by) { + requestBody.order_by = args.order_by; + } - if (!data.data || data.data.length === 0) { - return `No PnL data found for wallet ${args.wallet_address}.`; - } + // Other filters: flatten if present + if (args.filters) { + if (args.filters.transaction_hash) + requestBody.transaction_hash = args.filters.transaction_hash; + if (args.filters.token_address) requestBody.token_address = args.filters.token_address; + if (args.filters.token_symbol) requestBody.token_symbol = args.filters.token_symbol; + if (args.filters.token_sectors) requestBody.token_sectors = args.filters.token_sectors; + if (args.filters.pnl_usd) requestBody.pnl_usd = args.filters.pnl_usd; + if (args.filters.pnl_percent) requestBody.pnl_percent = args.filters.pnl_percent; + } - let result = `💰 PnL Details for ${args.wallet_address}:\n\n`; + const response = await fetch("https://api.nansen.ai/api/v1/profiler/address/pnl", { + method: "POST", + headers: { + "Content-Type": "application/json", + apiKey: apiKey, + }, + body: JSON.stringify(requestBody), + }); + + if (!response.ok) { + if (response.status === 401) + return "Error: Invalid Nansen API key. Please check your NANSEN_API_KEY environment variable."; + if (response.status === 403) + return "Error: Insufficient subscription tier for this endpoint."; + if (response.status === 429) + return "Error: Rate limit exceeded. Please wait before making another request."; + allResults += `Error fetching PnL: ${response.status} ${response.statusText} for chain ${chain}\n`; + continue; + } - data.data.forEach((pnl, index) => { - const timestamp = new Date(pnl.timestamp).toLocaleString(); - const pnlEmoji = pnl.pnl_usd && pnl.pnl_usd >= 0 ? "📈" : "📉"; + const data: PnlResponse = await response.json(); - result += `${index + 1}. PnL Transaction ${pnlEmoji}\n`; - result += ` • Token: ${pnl.token_symbol} (${pnl.token_address})\n`; - result += ` • Chain: ${pnl.chain}\n`; - if (pnl.pnl_usd !== undefined) { - result += ` • PnL: $${pnl.pnl_usd.toLocaleString()}\n`; - } - if (pnl.pnl_percent !== undefined) { - result += ` • PnL %: ${pnl.pnl_percent.toFixed(2)}%\n`; + if (!data.data || data.data.length === 0) { + allResults += `No PnL data found for wallet ${args.wallet_address} on ${chain}.\n`; + continue; } - if (pnl.token_sectors && pnl.token_sectors.length > 0) { - result += ` • Sectors: ${pnl.token_sectors.join(", ")}\n`; - } - result += ` • Time: ${timestamp}\n`; - result += ` • Tx Hash: ${pnl.transaction_hash}\n`; - result += "\n"; - }); - if (!data.pagination.is_last_page) { - result += `Page ${data.pagination.page} of results. Use pagination to get more results.\n`; + allResults += `💰 PnL Details for ${args.wallet_address} on ${chain}:\n\n`; + data.data.forEach((pnl, index) => { + const timestamp = pnl.timestamp ? new Date(pnl.timestamp).toLocaleString() : "N/A"; + const pnlEmoji = pnl.pnl_usd !== undefined && pnl.pnl_usd >= 0 ? "📈" : "📉"; + allResults += `${index + 1}. PnL Transaction ${pnlEmoji}\n`; + allResults += ` • Token: ${pnl.token_symbol} (${pnl.token_address})\n`; + allResults += ` • PnL: $${pnl.pnl_usd !== undefined ? pnl.pnl_usd.toLocaleString() : "N/A"}\n`; + allResults += ` • PnL %: ${pnl.pnl_percent !== undefined ? pnl.pnl_percent.toFixed(2) : "N/A"}%\n`; + if (pnl.token_sectors && pnl.token_sectors.length > 0) { + allResults += ` • Sectors: ${pnl.token_sectors.join(", ")}\n`; + } + allResults += ` • Time: ${timestamp}\n`; + allResults += ` • Tx Hash: ${pnl.transaction_hash}\n\n`; + }); + if (!data.pagination.is_last_page) { + allResults += `Page ${data.pagination.page} of results. Use pagination to get more results.\n`; + } } - return result; + return ( + allResults.trim() || + `No PnL data found for wallet ${args.wallet_address} on requested chains.` + ); } catch (error) { const errorMessage = error instanceof Error ? error.message : "An unknown error occurred"; return `Error fetching PnL: ${errorMessage}`; } } -/** - * Get PnL action. - */ +// AgentKit Action class export class GetPnlAction implements AgentkitAction { public name = "get_pnl"; public description = GET_PNL_PROMPT; diff --git a/agentkit-demo/test-defi-holdings.ts b/agentkit-demo/test-defi-holdings.ts new file mode 100644 index 0000000..e1abe73 --- /dev/null +++ b/agentkit-demo/test-defi-holdings.ts @@ -0,0 +1,11 @@ +import "dotenv/config"; +import { getDefiHoldings } from "@0xgasless/agentkit"; + +async function main() { + const result = await getDefiHoldings(null as any, { + wallet_address: "0x4062b997279de7213731dbe00485722a26718892", + }); + console.log(result); +} + +main().catch(console.error); diff --git a/agentkit-demo/test-getPnl.ts b/agentkit-demo/test-getPnl.ts new file mode 100644 index 0000000..dee577f --- /dev/null +++ b/agentkit-demo/test-getPnl.ts @@ -0,0 +1,22 @@ +import "dotenv/config"; // Loads NANSEN_API_KEY from .env +import { getPnl } from "@0xgasless/agentkit"; // Update path if needed + +async function main() { + const result = await getPnl(null as any, { + wallet_address: "0xde27d2e6b5009ead76ebc07452b54364fb54fdcd", // replace with any test wallet + chains: ["base"], // choose a supported chain + filters: { + // Optional: Uncomment and edit to filter by time range, symbol, etc + // timestamp: { from: "2024-01-01T00:00:00Z", to: "2025-12-31T23:59:59Z" } + }, + pagination: { + page: 1, + per_page: 10, + }, + // Optional: Sorting + // order_by: [{ field: "pnl_usd", direction: "DESC" }], + }); + console.log(result); +} + +main().catch(console.error);