From d277d0d2834155fab91bd909f0460d5628555499 Mon Sep 17 00:00:00 2001 From: michaelessiet Date: Wed, 1 Jan 2025 20:46:56 +0100 Subject: [PATCH 1/5] feat: get all token balances --- .../app/api/chat/route.ts | 80 +++++++++--------- .../data/DefaultRetrievalText.ts | 2 +- .../utils/markdownToHTML.ts | 30 +++---- src/actions/balance.ts | 1 - src/actions/createOrcaSingleSidedWhirlpool.ts | 2 +- src/actions/index.ts | 57 ++++++------- src/agent/index.ts | 30 +++++-- src/tools/get_balance.ts | 49 ++++++++++- src/utils/tokenMetadata.ts | 83 +++++++++++++++++++ test/index.ts | 2 +- 10 files changed, 239 insertions(+), 97 deletions(-) create mode 100644 src/utils/tokenMetadata.ts diff --git a/examples/agent-kit-nextjs-langchain/app/api/chat/route.ts b/examples/agent-kit-nextjs-langchain/app/api/chat/route.ts index 06e6911..badd6b3 100644 --- a/examples/agent-kit-nextjs-langchain/app/api/chat/route.ts +++ b/examples/agent-kit-nextjs-langchain/app/api/chat/route.ts @@ -5,24 +5,24 @@ import { createReactAgent } from "@langchain/langgraph/prebuilt"; import { SolanaAgentKit, createSolanaTools } from "solana-agent-kit"; const llm = new ChatOpenAI({ - temperature: 0.7, - model: "gpt-4o-mini", + temperature: 0.7, + model: "gpt-4o-mini", }); const solanaAgent = new SolanaAgentKit( - process.env.SOLANA_PRIVATE_KEY!, - process.env.RPC_URL, - process.env.OPENAI_API_KEY!, + process.env.SOLANA_PRIVATE_KEY!, + process.env.RPC_URL, + process.env.OPENAI_API_KEY!, ); const tools = createSolanaTools(solanaAgent); const memory = new MemorySaver(); const agent = createReactAgent({ - llm, - tools, - checkpointSaver: memory, - messageModifier: ` + llm, + tools, + checkpointSaver: memory, + messageModifier: ` You are a helpful agent that can interact onchain using the Solana Agent Kit. You are empowered to interact onchain using your tools. If you ever need funds, you can request them from the faucet. If not, you can provide your wallet details and request funds from the user. If there is a 5XX @@ -34,38 +34,38 @@ const agent = createReactAgent({ }); export async function POST(req: NextRequest) { - try { - const body = await req.json(); - const messages = body.messages ?? []; + try { + const body = await req.json(); + const messages = body.messages ?? []; - const eventStream = agent.streamEvents( - { - messages, - }, - { - version: "v2", - configurable: { - thread_id: "Solana Agent Kit!", - }, - }, - ); + const eventStream = agent.streamEvents( + { + messages, + }, + { + version: "v2", + configurable: { + thread_id: "Solana Agent Kit!", + }, + }, + ); - const textEncoder = new TextEncoder(); - const transformStream = new ReadableStream({ - async start(controller) { - for await (const { event, data } of eventStream) { - if (event === "on_chat_model_stream") { - if (!!data.chunk.content) { - controller.enqueue(textEncoder.encode(data.chunk.content)); - } - } - } - controller.close(); - }, - }); + const textEncoder = new TextEncoder(); + const transformStream = new ReadableStream({ + async start(controller) { + for await (const { event, data } of eventStream) { + if (event === "on_chat_model_stream") { + if (data.chunk.content) { + controller.enqueue(textEncoder.encode(data.chunk.content)); + } + } + } + controller.close(); + }, + }); - return new Response(transformStream); - } catch (e: any) { - return NextResponse.json({ error: e.message }, { status: e.status ?? 500 }); - } + return new Response(transformStream); + } catch (e: any) { + return NextResponse.json({ error: e.message }, { status: e.status ?? 500 }); + } } diff --git a/examples/agent-kit-nextjs-langchain/data/DefaultRetrievalText.ts b/examples/agent-kit-nextjs-langchain/data/DefaultRetrievalText.ts index 898acba..6973d98 100644 --- a/examples/agent-kit-nextjs-langchain/data/DefaultRetrievalText.ts +++ b/examples/agent-kit-nextjs-langchain/data/DefaultRetrievalText.ts @@ -537,4 +537,4 @@ const executor = await initializeAgentExecutorWithOptions(tools, llm, { }, }); \`\`\` -`; \ No newline at end of file +`; diff --git a/examples/agent-kit-nextjs-langchain/utils/markdownToHTML.ts b/examples/agent-kit-nextjs-langchain/utils/markdownToHTML.ts index dc265b1..135fdd9 100644 --- a/examples/agent-kit-nextjs-langchain/utils/markdownToHTML.ts +++ b/examples/agent-kit-nextjs-langchain/utils/markdownToHTML.ts @@ -2,29 +2,29 @@ import { marked } from "marked"; import DOMPurify from "isomorphic-dompurify"; interface MarkedOptions { - gfm: boolean; - breaks: boolean; - headerIds: boolean; - mangle: false; - highlight?: (code: string, lang: string) => string; + gfm: boolean; + breaks: boolean; + headerIds: boolean; + mangle: false; + highlight?: (code: string, lang: string) => string; } // Configure marked options const markedOptions: MarkedOptions = { - gfm: true, // GitHub Flavored Markdown - breaks: true, // Convert \n to
- headerIds: true, // Add ids to headers - mangle: false, // Don't escape HTML - highlight: function (code: string, lang: string): string { - // You can add syntax highlighting here if needed - return code; - }, + gfm: true, // GitHub Flavored Markdown + breaks: true, // Convert \n to
+ headerIds: true, // Add ids to headers + mangle: false, // Don't escape HTML + highlight: function (code: string, lang: string): string { + // You can add syntax highlighting here if needed + return code; + }, }; marked.setOptions(markedOptions); // Basic markdown to HTML conversion with sanitization export default function markdownToHtml(markdown: string) { - const rawHtml = marked.parse(markdown); - return DOMPurify.sanitize(rawHtml as string); + const rawHtml = marked.parse(markdown); + return DOMPurify.sanitize(rawHtml as string); } diff --git a/src/actions/balance.ts b/src/actions/balance.ts index 381b2a5..1ee1b56 100644 --- a/src/actions/balance.ts +++ b/src/actions/balance.ts @@ -54,7 +54,6 @@ const balanceAction: Action = { return { status: "success", balance: balance, - token: input.tokenAddress || "SOL", }; }, }; diff --git a/src/actions/createOrcaSingleSidedWhirlpool.ts b/src/actions/createOrcaSingleSidedWhirlpool.ts index affc445..3a1fb52 100644 --- a/src/actions/createOrcaSingleSidedWhirlpool.ts +++ b/src/actions/createOrcaSingleSidedWhirlpool.ts @@ -87,7 +87,7 @@ const createOrcaSingleSidedWhirlpoolAction: Action = { const otherTokenMint = new PublicKey(input.otherTokenMint); const initialPrice = new Decimal(input.initialPrice); const maxPrice = new Decimal(input.maxPrice); - const feeTier = input.feeTier + const feeTier = input.feeTier; // Create the whirlpool const signature = await orcaCreateSingleSidedLiquidityPool( diff --git a/src/actions/index.ts b/src/actions/index.ts index b66c89e..1ccdb64 100644 --- a/src/actions/index.ts +++ b/src/actions/index.ts @@ -28,34 +28,35 @@ import createOrcaSingleSidedWhirlpoolAction from "./createOrcaSingleSidedWhirlpo import launchPumpfunTokenAction from "./launchPumpfunToken"; export const ACTIONS = { - "DEPLOY_TOKEN_ACTION" : deployTokenAction, - "BALANCE_ACTION" : balanceAction, - "TRANSFER_ACTION" : transferAction, - "DEPLOY_COLLECTION_ACTION" : deployCollectionAction, - "MINT_NFT_ACTION" : mintNFTAction, - "TRADE_ACTION" : tradeAction, - "REQUEST_FUNDS_ACTION" : requestFundsAction, - "RESOLVE_DOMAIN_ACTION" : resolveDomainAction, - "GET_TOKEN_DATA_ACTION" : getTokenDataAction, - "GET_TPS_ACTION" : getTPSAction, - "FETCH_PRICE_ACTION" : fetchPriceAction, - "STAKE_WITH_JUP_ACTION" : stakeWithJupAction, - "REGISTER_DOMAIN_ACTION" : registerDomainAction, - "LEND_ASSET_ACTION" : lendAssetAction, - "CREATE_GIBWORK_TASK_ACTION" : createGibworkTaskAction, - "RESOLVE_SOL_DOMAIN_ACTION" : resolveSolDomainAction, - "PYTH_FETCH_PRICE_ACTION" : pythFetchPriceAction, - "GET_OWNED_DOMAINS_FOR_TLD_ACTION" : getOwnedDomainsForTLDAction, - "GET_PRIMARY_DOMAIN_ACTION" : getPrimaryDomainAction, - "GET_ALL_DOMAINS_TLDS_ACTION" : getAllDomainsTLDsAction, - "GET_OWNED_ALL_DOMAINS_ACTION" : getOwnedAllDomainsAction, - "CREATE_IMAGE_ACTION" : createImageAction, - "GET_MAIN_ALL_DOMAINS_DOMAIN_ACTION" : getMainAllDomainsDomainAction, - "GET_ALL_REGISTERED_ALL_DOMAINS_ACTION" : getAllRegisteredAllDomainsAction, - "RAYDIUM_CREATE_CPMM_ACTION" : raydiumCreateCpmmAction, - "RAYDIUM_CREATE_AMM_V4_ACTION" : raydiumCreateAmmV4Action, - "CREATE_ORCA_SINGLE_SIDED_WHIRLPOOL_ACTION" : createOrcaSingleSidedWhirlpoolAction, - "LAUNCH_PUMPFUN_TOKEN_ACTION" : launchPumpfunTokenAction, + DEPLOY_TOKEN_ACTION: deployTokenAction, + BALANCE_ACTION: balanceAction, + TRANSFER_ACTION: transferAction, + DEPLOY_COLLECTION_ACTION: deployCollectionAction, + MINT_NFT_ACTION: mintNFTAction, + TRADE_ACTION: tradeAction, + REQUEST_FUNDS_ACTION: requestFundsAction, + RESOLVE_DOMAIN_ACTION: resolveDomainAction, + GET_TOKEN_DATA_ACTION: getTokenDataAction, + GET_TPS_ACTION: getTPSAction, + FETCH_PRICE_ACTION: fetchPriceAction, + STAKE_WITH_JUP_ACTION: stakeWithJupAction, + REGISTER_DOMAIN_ACTION: registerDomainAction, + LEND_ASSET_ACTION: lendAssetAction, + CREATE_GIBWORK_TASK_ACTION: createGibworkTaskAction, + RESOLVE_SOL_DOMAIN_ACTION: resolveSolDomainAction, + PYTH_FETCH_PRICE_ACTION: pythFetchPriceAction, + GET_OWNED_DOMAINS_FOR_TLD_ACTION: getOwnedDomainsForTLDAction, + GET_PRIMARY_DOMAIN_ACTION: getPrimaryDomainAction, + GET_ALL_DOMAINS_TLDS_ACTION: getAllDomainsTLDsAction, + GET_OWNED_ALL_DOMAINS_ACTION: getOwnedAllDomainsAction, + CREATE_IMAGE_ACTION: createImageAction, + GET_MAIN_ALL_DOMAINS_DOMAIN_ACTION: getMainAllDomainsDomainAction, + GET_ALL_REGISTERED_ALL_DOMAINS_ACTION: getAllRegisteredAllDomainsAction, + RAYDIUM_CREATE_CPMM_ACTION: raydiumCreateCpmmAction, + RAYDIUM_CREATE_AMM_V4_ACTION: raydiumCreateAmmV4Action, + CREATE_ORCA_SINGLE_SIDED_WHIRLPOOL_ACTION: + createOrcaSingleSidedWhirlpoolAction, + LAUNCH_PUMPFUN_TOKEN_ACTION: launchPumpfunTokenAction, }; export type { Action, ActionExample, Handler } from "../types/action"; diff --git a/src/agent/index.ts b/src/agent/index.ts index 4acf694..8191a80 100644 --- a/src/agent/index.ts +++ b/src/agent/index.ts @@ -83,24 +83,30 @@ export class SolanaAgentKit { * @deprecated Using openai_api_key directly in constructor is deprecated. * Please use the new constructor with Config object instead: * @example - * const agent = new SolanaAgentKit(privateKey, rpcUrl, { + * const agent = new SolanaAgentKit(privateKey, rpcUrl, { * OPENAI_API_KEY: 'your-key' * }); */ - constructor(private_key: string, rpc_url: string, openai_api_key: string | null); + constructor( + private_key: string, + rpc_url: string, + openai_api_key: string | null, + ); constructor(private_key: string, rpc_url: string, config: Config); constructor( private_key: string, rpc_url: string, configOrKey: Config | string | null, ) { - this.connection = new Connection(rpc_url || "https://api.mainnet-beta.solana.com"); + this.connection = new Connection( + rpc_url || "https://api.mainnet-beta.solana.com", + ); this.wallet = Keypair.fromSecretKey(bs58.decode(private_key)); this.wallet_address = this.wallet.publicKey; // Handle both old and new patterns - if (typeof configOrKey === 'string' || configOrKey === null) { - this.config = { OPENAI_API_KEY: configOrKey || '' }; + if (typeof configOrKey === "string" || configOrKey === null) { + this.config = { OPENAI_API_KEY: configOrKey || "" }; } else { this.config = configOrKey; } @@ -127,7 +133,19 @@ export class SolanaAgentKit { return deploy_collection(this, options); } - async getBalance(token_address?: PublicKey): Promise { + async getBalance(token_address?: PublicKey): Promise< + | number + | { + sol: number; + tokens: Array<{ + tokenAddress: string; + name: string; + symbol: string; + balance: number; + decimals: number; + }>; + } + > { return get_balance(this, token_address); } diff --git a/src/tools/get_balance.ts b/src/tools/get_balance.ts index a1e3736..3e30021 100644 --- a/src/tools/get_balance.ts +++ b/src/tools/get_balance.ts @@ -1,5 +1,7 @@ import { LAMPORTS_PER_SOL, PublicKey } from "@solana/web3.js"; import { SolanaAgentKit } from "../index"; +import { TOKEN_PROGRAM_ID } from "@solana/spl-token"; +import { getTokenMetadata } from "../utils/tokenMetadata"; /** * Get the balance of SOL or an SPL token for the agent's wallet @@ -10,12 +12,51 @@ import { SolanaAgentKit } from "../index"; export async function get_balance( agent: SolanaAgentKit, token_address?: PublicKey, -): Promise { +): Promise< + | number + | { + sol: number; + tokens: Array<{ + tokenAddress: string; + name: string; + symbol: string; + balance: number; + decimals: number; + }>; + } +> { if (!token_address) { - return ( - (await agent.connection.getBalance(agent.wallet_address)) / - LAMPORTS_PER_SOL + const [lamportsBalance, tokenAccountData] = await Promise.all([ + agent.connection.getBalance(agent.wallet_address), + agent.connection.getParsedTokenAccountsByOwner(agent.wallet_address, { + programId: TOKEN_PROGRAM_ID, + }), + ]); + + const removedZeroBalance = tokenAccountData.value.filter( + (v) => v.account.data.parsed.info.tokenAmount.uiAmount !== 0, ); + + const tokenBalances = await Promise.all( + removedZeroBalance.map(async (v) => { + const mint = v.account.data.parsed.info.mint; + const mintInfo = await getTokenMetadata(agent.connection, mint); + return { + tokenAddress: mint, + name: mintInfo.name ?? "", + symbol: mintInfo.symbol ?? "", + balance: v.account.data.parsed.info.tokenAmount.uiAmount as number, + decimals: v.account.data.parsed.info.tokenAmount.decimals as number, + }; + }), + ); + + const solBalance = lamportsBalance / LAMPORTS_PER_SOL; + + return { + sol: solBalance, + tokens: tokenBalances, + }; } const token_account = diff --git a/src/utils/tokenMetadata.ts b/src/utils/tokenMetadata.ts new file mode 100644 index 0000000..514a208 --- /dev/null +++ b/src/utils/tokenMetadata.ts @@ -0,0 +1,83 @@ +import { Connection, PublicKey } from "@solana/web3.js"; + +export async function getTokenMetadata( + connection: Connection, + tokenMint: string, +) { + const METADATA_PROGRAM_ID = new PublicKey( + "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s", + ); + + const [metadataPDA] = PublicKey.findProgramAddressSync( + [ + Buffer.from("metadata"), + METADATA_PROGRAM_ID.toBuffer(), + new PublicKey(tokenMint).toBuffer(), + ], + METADATA_PROGRAM_ID, + ); + + const metadata = await connection.getAccountInfo(metadataPDA); + if (!metadata?.data) { + throw new Error("Metadata not found"); + } + + let offset = 1 + 32 + 32; // key + update auth + mint + const data = metadata.data; + const decoder = new TextDecoder(); + + // Read variable length strings + const readString = () => { + let nameLength = data[offset]; + + while (nameLength === 0) { + offset++; + nameLength = data[offset]; + if (offset >= data.length) { + return null; + } + } + + offset++; + const name = decoder + .decode(data.slice(offset, offset + nameLength)) + // @eslint-disable-next-line no-control-regex + .replace(new RegExp(String.fromCharCode(0), "g"), ""); + offset += nameLength; + return name; + }; + + const name = readString(); + const symbol = readString(); + const uri = readString(); + + // Read remaining data + const sellerFeeBasisPoints = data.readUInt16LE(offset); + offset += 2; + + let creators: + | { address: PublicKey; verified: boolean; share: number }[] + | null = null; + if (data[offset] === 1) { + offset++; + const numCreators = data[offset]; + offset++; + creators = [...Array(numCreators)].map(() => { + const creator = { + address: new PublicKey(data.slice(offset, offset + 32)), + verified: data[offset + 32] === 1, + share: data[offset + 33], + }; + offset += 34; + return creator; + }); + } + + return { + name, + symbol, + uri, + sellerFeeBasisPoints, + creators, + }; +} diff --git a/test/index.ts b/test/index.ts index 2a3312b..00f9976 100644 --- a/test/index.ts +++ b/test/index.ts @@ -1,4 +1,4 @@ -import { SolanaAgentKit , ACTIONS} from "../src"; +import { SolanaAgentKit, ACTIONS } from "../src"; import { createSolanaTools } from "../src/langchain"; import { HumanMessage } from "@langchain/core/messages"; import { MemorySaver } from "@langchain/langgraph"; From ad23d8c92b3f8cbc3feffe9d7d3b92cf8b26e780 Mon Sep 17 00:00:00 2001 From: michaelessiet Date: Fri, 10 Jan 2025 17:08:02 +0100 Subject: [PATCH 2/5] catch up to main --- package.json | 157 +++++++++++++++---------------- pnpm-lock.yaml | 248 +++++++++++++++++++++++++------------------------ 2 files changed, 208 insertions(+), 197 deletions(-) diff --git a/package.json b/package.json index e64c039..63f82e7 100644 --- a/package.json +++ b/package.json @@ -1,81 +1,82 @@ { - "name": "solana-agent-kit", - "version": "1.3.7", - "description": "connect any ai agents to solana protocols", - "main": "dist/index.js", - "types": "dist/index.d.ts", - "scripts": { - "build": "tsc", - "docs": "typedoc src --out docs", - "test": "ts-node test/index.ts", - "test:vercel-ai": "ts-node test/agent_sdks/vercel_ai.ts", - "generate": "ts-node src/utils/keypair.ts", - "lint": "eslint . --ext .ts", - "lint:fix": "eslint . --ext .ts --fix", - "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", - "prepare": "husky" - }, - "engines": { - "node": ">=22.0.0", - "pnpm": ">=8.0.0" - }, - "keywords": [], - "author": "sendaifun", - "license": "Apache-2.0", - "dependencies": { - "@3land/listings-sdk": "^0.0.4", - "@ai-sdk/openai": "^1.0.11", - "@bonfida/spl-name-service": "^3.0.7", - "@cks-systems/manifest-sdk": "0.1.59", - "@coral-xyz/anchor": "0.29", - "@langchain/core": "^0.3.26", - "@langchain/groq": "^0.1.2", - "@langchain/langgraph": "^0.2.36", - "@langchain/openai": "^0.3.16", - "@lightprotocol/compressed-token": "^0.17.1", - "@lightprotocol/stateless.js": "^0.17.1", - "@metaplex-foundation/mpl-core": "^1.1.1", - "@metaplex-foundation/mpl-token-metadata": "^3.3.0", - "@metaplex-foundation/mpl-toolbox": "^0.9.4", - "@metaplex-foundation/umi": "^0.9.2", - "@metaplex-foundation/umi-bundle-defaults": "^0.9.2", - "@metaplex-foundation/umi-web3js-adapters": "^0.9.2", - "@onsol/tldparser": "^0.6.7", - "@orca-so/common-sdk": "0.6.4", - "@orca-so/whirlpools-sdk": "^0.13.12", - "@pythnetwork/hermes-client": "^1.3.0", - "@raydium-io/raydium-sdk-v2": "0.1.95-alpha", - "@solana/spl-token": "^0.4.9", - "@solana/web3.js": "^1.98.0", - "@tensor-oss/tensorswap-sdk": "^4.5.0", + "name": "solana-agent-kit", + "version": "1.3.7", + "description": "connect any ai agents to solana protocols", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "scripts": { + "build": "tsc", + "docs": "typedoc src --out docs", + "test": "ts-node test/index.ts", + "test:vercel-ai": "ts-node test/agent_sdks/vercel_ai.ts", + "generate": "ts-node src/utils/keypair.ts", + "lint": "eslint . --ext .ts", + "lint:fix": "eslint . --ext .ts --fix", + "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", + "prepare": "husky" + }, + "engines": { + "node": ">=22.0.0", + "pnpm": ">=8.0.0" + }, + "keywords": [], + "author": "sendaifun", + "license": "Apache-2.0", + "dependencies": { + "@3land/listings-sdk": "^0.0.4", + "@ai-sdk/openai": "^1.0.11", + "@bonfida/spl-name-service": "^3.0.7", + "@cks-systems/manifest-sdk": "0.1.59", + "@coral-xyz/anchor": "0.29", + "@langchain/core": "^0.3.26", + "@langchain/groq": "^0.1.2", + "@langchain/langgraph": "^0.2.36", + "@langchain/openai": "^0.3.16", + "@lightprotocol/compressed-token": "^0.17.1", + "@lightprotocol/stateless.js": "^0.17.1", + "@metaplex-foundation/mpl-core": "^1.1.1", + "@metaplex-foundation/mpl-token-metadata": "^3.3.0", + "@metaplex-foundation/mpl-toolbox": "^0.9.4", + "@metaplex-foundation/umi": "^0.9.2", + "@metaplex-foundation/umi-bundle-defaults": "^0.9.2", + "@metaplex-foundation/umi-web3js-adapters": "^0.9.2", + "@onsol/tldparser": "^0.6.7", + "@orca-so/common-sdk": "0.6.4", + "@orca-so/whirlpools-sdk": "^0.13.12", + "@pythnetwork/hermes-client": "^1.3.0", + "@raydium-io/raydium-sdk-v2": "0.1.95-alpha", + "@solana/spl-token": "^0.4.9", + "@solana/web3.js": "^1.98.0", + "@tensor-oss/tensorswap-sdk": "^4.5.0", "@sqds/multisig": "^2.1.3", - "@tiplink/api": "^0.3.1", - "ai": "^4.0.22", - "bn.js": "^5.2.1", - "bs58": "^6.0.0", - "chai": "^5.1.2", - "decimal.js": "^10.4.3", - "dotenv": "^16.4.7", - "flash-sdk": "^2.24.3", - "form-data": "^4.0.1", - "langchain": "^0.3.8", - "openai": "^4.77.0", - "typedoc": "^0.27.6", - "zod": "^3.24.1" - }, - "devDependencies": { - "@types/bn.js": "^5.1.6", - "@types/chai": "^5.0.1", - "@types/node": "^22.10.2", - "@typescript-eslint/eslint-plugin": "^8.18.2", - "@typescript-eslint/parser": "^8.18.2", - "eslint": "^8.56.0", - "eslint-config-prettier": "^9.1.0", - "eslint-plugin-prettier": "^5.2.1", - "husky": "^9.1.7", - "lint-staged": "^15.3.0", - "prettier": "^3.4.2", - "ts-node": "^10.9.2", - "typescript": "^5.7.2" - } + "@tiplink/api": "^0.3.1", + "ai": "^4.0.22", + "bn.js": "^5.2.1", + "bs58": "^6.0.0", + "chai": "^5.1.2", + "decimal.js": "^10.4.3", + "dotenv": "^16.4.7", + "flash-sdk": "^2.24.3", + "form-data": "^4.0.1", + "langchain": "^0.3.8", + "openai": "^4.77.0", + "typedoc": "^0.27.6", + "zod": "^3.24.1" + }, + "devDependencies": { + "@types/bn.js": "^5.1.6", + "@types/chai": "^5.0.1", + "@types/node": "^22.10.2", + "@typescript-eslint/eslint-plugin": "^8.18.2", + "@typescript-eslint/parser": "^8.18.2", + "eslint": "^8.56.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-prettier": "^5.2.1", + "husky": "^9.1.7", + "lint-staged": "^15.3.0", + "prettier": "^3.4.2", + "ts-node": "^10.9.2", + "typescript": "^5.7.2" + }, + "packageManager": "pnpm@9.15.3" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b98d918..2ef0c43 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,10 +10,10 @@ importers: dependencies: '@3land/listings-sdk': specifier: ^0.0.4 - version: 0.0.4(@types/node@22.10.5)(arweave@1.15.5)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) + version: 0.0.4(@types/node@22.10.5)(arweave@1.15.5)(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) '@ai-sdk/openai': specifier: ^1.0.11 - version: 1.0.13(zod@3.24.1) + version: 1.0.11(zod@3.24.1) '@bonfida/spl-name-service': specifier: ^3.0.7 version: 3.0.7(@solana/web3.js@1.98.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) @@ -109,7 +109,7 @@ importers: version: 16.4.7 flash-sdk: specifier: ^2.24.3 - version: 2.24.3(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) + version: 2.24.3(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) form-data: specifier: ^4.0.1 version: 4.0.1 @@ -134,7 +134,7 @@ importers: version: 5.0.1 '@types/node': specifier: ^22.10.2 - version: 22.10.2 + version: 22.10.5 '@typescript-eslint/eslint-plugin': specifier: ^8.18.2 version: 8.19.0(@typescript-eslint/parser@8.19.0(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1)(typescript@5.7.2) @@ -161,7 +161,7 @@ importers: version: 3.4.2 ts-node: specifier: ^10.9.2 - version: 10.9.2(@types/node@22.10.2)(typescript@5.7.2) + version: 10.9.2(@types/node@22.10.5)(typescript@5.7.2) typescript: specifier: ^5.7.2 version: 5.7.2 @@ -855,6 +855,9 @@ packages: '@shikijs/vscode-textmate@10.0.1': resolution: {integrity: sha512-fTIQwLF+Qhuws31iw7Ncl1R3HUDtGwIipiJ9iU+UsDUwMhegFcQKQHd51nZjb7CArq0MvON8rbgCGQYWHUKAdg==} + '@shikijs/vscode-textmate@9.3.1': + resolution: {integrity: sha512-79QfK1393x9Ho60QFyLti+QfdJzRQCVLFb97kOIV7Eo9vQU/roINgk7m24uv0a7AUvN//RDH36FLjjK48v0s9g==} + '@sindresorhus/is@4.6.0': resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} engines: {node: '>=10'} @@ -1036,6 +1039,10 @@ packages: '@solana/web3.js@1.98.0': resolution: {integrity: sha512-nz3Q5OeyGFpFCR+erX2f6JPt3sKhzhYcSycBCSPkWjzSVDh/Rr1FqTVMRe58FKO16/ivTUcuJjeS5MyBvpkbzA==} + '@sqds/multisig@2.1.3': + resolution: {integrity: sha512-WOiL7La+RSiJsz7jVO85yhSiiSvNMUthiWuLPeWVOoD6IYa34BEAzanF1RdXRWGglSbRFYCTkyr+Ay1WmXmSRQ==} + engines: {node: '>=14'} + '@supercharge/promise-pool@3.2.0': resolution: {integrity: sha512-pj0cAALblTZBPtMltWOlZTQSLT07jIaFNeM8TWoJD1cQMgDB9mcMlVMoetiB35OzNJpqQ2b+QEtwiR9f20mADg==} engines: {node: '>=8'} @@ -2121,12 +2128,8 @@ packages: resolution: {integrity: sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==} engines: {node: '>=18'} - get-intrinsic@1.2.7: - resolution: {integrity: sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==} - engines: {node: '>= 0.4'} - - get-proto@1.0.1: - resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + get-intrinsic@1.2.6: + resolution: {integrity: sha512-qxsEs+9A+u85HhllWJJFicJfPDhRmjzoYdl64aMWW9yRIJmSyxdn8IEkuIM530/7T+lv0TIHd8L6Q/ra0tEoeA==} engines: {node: '>= 0.4'} get-stream@5.2.0: @@ -2284,6 +2287,9 @@ packages: resolution: {integrity: sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==} engines: {node: '>=12.0.0'} + invariant@2.2.4: + resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} + ipaddr.js@1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} @@ -2347,10 +2353,6 @@ packages: resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} engines: {node: '>=8'} - is-regex@1.2.1: - resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} - engines: {node: '>= 0.4'} - is-retry-allowed@2.2.0: resolution: {integrity: sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg==} engines: {node: '>=10'} @@ -3060,8 +3062,8 @@ packages: regex-utilities@2.3.0: resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==} - regex@5.1.1: - resolution: {integrity: sha512-dN5I359AVGPnwzJm2jN1k0W9LPZ+ePvoOeVMMfqIMFz53sSwXkxaJoxr50ptnsC771lK95BnTrVSZxq0b9yCGw==} + regex@5.0.2: + resolution: {integrity: sha512-/pczGbKIQgfTMRV0XjABvc5RzLqQmwqxLHdQao2RTXPk+pmTXB2P0IaUHYdYyk412YLwUIkaeMd5T+RzVgTqnQ==} resolve-alpn@1.2.1: resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} @@ -3661,14 +3663,14 @@ packages: snapshots: - '@3land/listings-sdk@0.0.4(@types/node@22.10.5)(arweave@1.15.5)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10)': + '@3land/listings-sdk@0.0.4(@types/node@22.10.5)(arweave@1.15.5)(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10)': dependencies: - '@coral-xyz/borsh': 0.30.1(@solana/web3.js@1.98.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@irys/sdk': 0.2.11(arweave@1.15.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@coral-xyz/borsh': 0.30.1(@solana/web3.js@1.98.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)) + '@irys/sdk': 0.2.11(arweave@1.15.5)(bufferutil@4.0.8)(utf-8-validate@5.0.10) '@metaplex-foundation/beet': 0.7.2 - '@metaplex-foundation/mpl-token-metadata': 2.13.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) - '@project-serum/anchor': 0.26.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@metaplex-foundation/mpl-token-metadata': 2.13.0(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) + '@project-serum/anchor': 0.26.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) + '@solana/web3.js': 1.98.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) bn: 1.0.5 bn.js: 5.2.1 bs58: 6.0.0 @@ -3743,8 +3745,8 @@ snapshots: dependencies: '@aptos-labs/aptos-cli': 1.0.2 '@aptos-labs/aptos-client': 0.1.1 - '@noble/curves': 1.8.0 - '@noble/hashes': 1.7.0 + '@noble/curves': 1.7.0 + '@noble/hashes': 1.6.1 '@scure/bip32': 1.4.0 '@scure/bip39': 1.3.0 eventemitter3: 5.0.1 @@ -3838,16 +3840,16 @@ snapshots: - encoding - utf-8-validate - '@coral-xyz/anchor@0.27.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + '@coral-xyz/anchor@0.27.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)': dependencies: - '@coral-xyz/borsh': 0.27.0(@solana/web3.js@1.98.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@coral-xyz/borsh': 0.27.0(@solana/web3.js@1.98.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)) + '@solana/web3.js': 1.98.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) base64-js: 1.5.1 bn.js: 5.2.1 bs58: 4.0.1 buffer-layout: 1.2.2 camelcase: 6.3.0 - cross-fetch: 3.2.0 + cross-fetch: 3.1.8 crypto-hash: 1.3.0 eventemitter3: 4.0.7 js-sha256: 0.9.0 @@ -3860,7 +3862,7 @@ snapshots: - encoding - utf-8-validate - '@coral-xyz/anchor@0.29.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + '@coral-xyz/anchor@0.29.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)': dependencies: '@coral-xyz/borsh': 0.29.0(@solana/web3.js@1.98.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)) '@noble/hashes': 1.6.1 @@ -3887,27 +3889,27 @@ snapshots: bn.js: 5.2.1 buffer-layout: 1.2.2 - '@coral-xyz/borsh@0.27.0(@solana/web3.js@1.98.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + '@coral-xyz/borsh@0.27.0(@solana/web3.js@1.98.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))': dependencies: - '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@solana/web3.js': 1.98.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) bn.js: 5.2.1 buffer-layout: 1.2.2 - '@coral-xyz/borsh@0.28.0(@solana/web3.js@1.95.8(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + '@coral-xyz/borsh@0.28.0(@solana/web3.js@1.95.8(bufferutil@4.0.8)(utf-8-validate@5.0.10))': dependencies: - '@solana/web3.js': 1.95.8(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@solana/web3.js': 1.95.8(bufferutil@4.0.8)(utf-8-validate@5.0.10) bn.js: 5.2.1 buffer-layout: 1.2.2 - '@coral-xyz/borsh@0.29.0(@solana/web3.js@1.98.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + '@coral-xyz/borsh@0.29.0(@solana/web3.js@1.98.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))': dependencies: - '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@solana/web3.js': 1.98.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) bn.js: 5.2.1 buffer-layout: 1.2.2 - '@coral-xyz/borsh@0.30.1(@solana/web3.js@1.98.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + '@coral-xyz/borsh@0.30.1(@solana/web3.js@1.98.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))': dependencies: - '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@solana/web3.js': 1.98.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) bn.js: 5.2.1 buffer-layout: 1.2.2 @@ -4122,7 +4124,7 @@ snapshots: dependencies: '@ethersproject/logger': 5.7.0 - '@ethersproject/providers@5.7.2(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + '@ethersproject/providers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10)': dependencies: '@ethersproject/abstract-provider': 5.7.0 '@ethersproject/abstract-signer': 5.7.0 @@ -4143,7 +4145,7 @@ snapshots: '@ethersproject/transactions': 5.7.0 '@ethersproject/web': 5.7.1 bech32: 1.1.4 - ws: 7.4.6(bufferutil@4.0.9)(utf-8-validate@5.0.10) + ws: 7.4.6(bufferutil@4.0.8)(utf-8-validate@5.0.10) transitivePeerDependencies: - bufferutil - utf-8-validate @@ -4271,22 +4273,22 @@ snapshots: transitivePeerDependencies: - debug - '@irys/sdk@0.2.11(arweave@1.15.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + '@irys/sdk@0.2.11(arweave@1.15.5)(bufferutil@4.0.8)(utf-8-validate@5.0.10)': dependencies: '@aptos-labs/ts-sdk': 1.33.1 '@ethersproject/bignumber': 5.7.0 '@ethersproject/contracts': 5.7.0 - '@ethersproject/providers': 5.7.2(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@ethersproject/providers': 5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10) '@ethersproject/wallet': 5.7.0 '@irys/query': 0.0.8 '@near-js/crypto': 0.0.3 '@near-js/keystores-browser': 0.0.3 '@near-js/providers': 0.0.4 '@near-js/transactions': 0.1.1 - '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@solana/web3.js': 1.98.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) '@supercharge/promise-pool': 3.2.0 algosdk: 1.24.1 - arbundles: 0.11.2(arweave@1.15.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10) + arbundles: 0.11.2(arweave@1.15.5)(bufferutil@4.0.8)(utf-8-validate@5.0.10) async-retry: 1.3.3 axios: 1.7.9 base64url: 3.0.1 @@ -4778,7 +4780,7 @@ snapshots: '@noble/curves@1.7.0': dependencies: - '@noble/hashes': 1.7.0 + '@noble/hashes': 1.6.0 '@noble/ed25519@1.7.3': {} @@ -4839,16 +4841,16 @@ snapshots: '@pkgr/core@0.1.1': {} - '@project-serum/anchor@0.26.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + '@project-serum/anchor@0.26.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)': dependencies: - '@coral-xyz/borsh': 0.26.0(@solana/web3.js@1.98.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@coral-xyz/borsh': 0.26.0(@solana/web3.js@1.98.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)) + '@solana/web3.js': 1.98.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) base64-js: 1.5.1 bn.js: 5.2.1 bs58: 4.0.1 buffer-layout: 1.2.2 camelcase: 6.3.0 - cross-fetch: 3.2.0 + cross-fetch: 3.1.8 crypto-hash: 1.3.0 eventemitter3: 4.0.7 js-sha256: 0.9.0 @@ -4861,11 +4863,11 @@ snapshots: - encoding - utf-8-validate - '@pythnetwork/client@2.22.0(@solana/web3.js@1.95.8(bufferutil@4.0.9)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + '@pythnetwork/client@2.22.0(@solana/web3.js@1.95.8(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(utf-8-validate@5.0.10)': dependencies: - '@coral-xyz/anchor': 0.29.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@coral-xyz/borsh': 0.28.0(@solana/web3.js@1.95.8(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana/web3.js': 1.95.8(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@coral-xyz/anchor': 0.29.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) + '@coral-xyz/borsh': 0.28.0(@solana/web3.js@1.95.8(bufferutil@4.0.8)(utf-8-validate@5.0.10)) + '@solana/web3.js': 1.95.8(bufferutil@4.0.8)(utf-8-validate@5.0.10) buffer: 6.0.3 transitivePeerDependencies: - bufferutil @@ -4880,15 +4882,15 @@ snapshots: transitivePeerDependencies: - axios - '@pythnetwork/price-service-client@1.9.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + '@pythnetwork/price-service-client@1.9.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)': dependencies: '@pythnetwork/price-service-sdk': 1.8.0 '@types/ws': 8.5.13 axios: 1.7.9 axios-retry: 3.9.1 - isomorphic-ws: 4.0.1(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + isomorphic-ws: 4.0.1(ws@8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)) ts-log: 2.2.7 - ws: 8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) transitivePeerDependencies: - bufferutil - debug @@ -4906,7 +4908,7 @@ snapshots: '@randlabs/communication-bridge': 1.0.1 optional: true - '@raydium-io/raydium-sdk-v2@0.1.95-alpha(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10)': + '@raydium-io/raydium-sdk-v2@0.1.95-alpha(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10)': dependencies: '@solana/buffer-layout': 4.0.1 '@solana/spl-token': 0.4.9(@solana/web3.js@1.98.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) @@ -4997,9 +4999,11 @@ snapshots: '@shikijs/vscode-textmate@10.0.1': {} + '@shikijs/vscode-textmate@9.3.1': {} + '@sindresorhus/is@4.6.0': {} - '@solana/buffer-layout-utils@0.2.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + '@solana/buffer-layout-utils@0.2.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)': dependencies: '@solana/buffer-layout': 4.0.1 '@solana/web3.js': 1.98.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) @@ -5266,15 +5270,15 @@ snapshots: - fastestsmallesttextencoderdecoder - typescript - '@solana/spl-token-metadata@0.1.6(@solana/web3.js@1.95.8(bufferutil@4.0.9)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)': + '@solana/spl-token-metadata@0.1.6(@solana/web3.js@1.95.8(bufferutil@4.0.8)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)': dependencies: '@solana/codecs': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2) - '@solana/web3.js': 1.95.8(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@solana/web3.js': 1.95.8(bufferutil@4.0.8)(utf-8-validate@5.0.10) transitivePeerDependencies: - fastestsmallesttextencoderdecoder - typescript - '@solana/spl-token-metadata@0.1.6(@solana/web3.js@1.98.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@4.9.5)': + '@solana/spl-token-metadata@0.1.6(@solana/web3.js@1.98.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@4.9.5)': dependencies: '@solana/codecs': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@4.9.5) '@solana/web3.js': 1.98.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) @@ -5303,12 +5307,12 @@ snapshots: - encoding - utf-8-validate - '@solana/spl-token@0.3.11(@solana/web3.js@1.95.8(bufferutil@4.0.9)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10)': + '@solana/spl-token@0.3.11(@solana/web3.js@1.95.8(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10)': dependencies: '@solana/buffer-layout': 4.0.1 - '@solana/buffer-layout-utils': 0.2.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@solana/spl-token-metadata': 0.1.6(@solana/web3.js@1.95.8(bufferutil@4.0.9)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2) - '@solana/web3.js': 1.95.8(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@solana/buffer-layout-utils': 0.2.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) + '@solana/spl-token-metadata': 0.1.6(@solana/web3.js@1.95.8(bufferutil@4.0.8)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2) + '@solana/web3.js': 1.95.8(bufferutil@4.0.8)(utf-8-validate@5.0.10) buffer: 6.0.3 transitivePeerDependencies: - bufferutil @@ -5317,7 +5321,7 @@ snapshots: - typescript - utf-8-validate - '@solana/spl-token@0.3.11(@solana/web3.js@1.98.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@4.9.5)(utf-8-validate@5.0.10)': + '@solana/spl-token@0.3.11(@solana/web3.js@1.98.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@4.9.5)(utf-8-validate@5.0.10)': dependencies: '@solana/buffer-layout': 4.0.1 '@solana/buffer-layout-utils': 0.2.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) @@ -5400,7 +5404,7 @@ snapshots: '@noble/curves': 1.7.0 '@noble/hashes': 1.6.1 '@solana/buffer-layout': 4.0.1 - agentkeepalive: 4.5.0 + agentkeepalive: 4.6.0 bigint-buffer: 1.1.5 bn.js: 5.2.1 borsh: 0.7.0 @@ -5416,11 +5420,11 @@ snapshots: - encoding - utf-8-validate - '@solana/web3.js@1.95.8(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + '@solana/web3.js@1.95.8(bufferutil@4.0.8)(utf-8-validate@5.0.10)': dependencies: '@babel/runtime': 7.26.0 - '@noble/curves': 1.8.0 - '@noble/hashes': 1.7.0 + '@noble/curves': 1.7.0 + '@noble/hashes': 1.6.1 '@solana/buffer-layout': 4.0.1 agentkeepalive: 4.6.0 bigint-buffer: 1.1.5 @@ -5429,7 +5433,7 @@ snapshots: bs58: 4.0.1 buffer: 6.0.3 fast-stable-stringify: 1.0.0 - jayson: 4.1.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) + jayson: 4.1.3(bufferutil@4.0.8)(utf-8-validate@5.0.10) node-fetch: 2.7.0 rpc-websockets: 9.0.4 superstruct: 2.0.2 @@ -5438,13 +5442,13 @@ snapshots: - encoding - utf-8-validate - '@solana/web3.js@1.98.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + '@solana/web3.js@1.98.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)': dependencies: '@babel/runtime': 7.26.0 '@noble/curves': 1.7.0 '@noble/hashes': 1.6.1 '@solana/buffer-layout': 4.0.1 - agentkeepalive: 4.5.0 + agentkeepalive: 4.6.0 bigint-buffer: 1.1.5 bn.js: 5.2.1 borsh: 0.7.0 @@ -5460,6 +5464,26 @@ snapshots: - encoding - utf-8-validate + '@sqds/multisig@2.1.3(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10)': + dependencies: + '@metaplex-foundation/beet': 0.7.1 + '@metaplex-foundation/beet-solana': 0.4.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) + '@metaplex-foundation/cusper': 0.0.2 + '@solana/spl-token': 0.3.11(@solana/web3.js@1.98.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) + '@solana/web3.js': 1.98.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) + '@types/bn.js': 5.1.6 + assert: 2.1.0 + bn.js: 5.2.1 + buffer: 6.0.3 + invariant: 2.2.4 + transitivePeerDependencies: + - bufferutil + - encoding + - fastestsmallesttextencoderdecoder + - supports-color + - typescript + - utf-8-validate + '@supercharge/promise-pool@3.2.0': {} '@swc/helpers@0.5.15': @@ -5470,7 +5494,7 @@ snapshots: dependencies: defer-to-connect: 2.0.1 - '@tensor-hq/tensor-common@8.3.1(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10)': + '@tensor-hq/tensor-common@8.3.1(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10)': dependencies: '@coral-xyz/anchor': 0.26.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) '@metaplex-foundation/mpl-auction-house': 2.5.1(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) @@ -5550,7 +5574,7 @@ snapshots: '@types/bn.js@5.1.6': dependencies: - '@types/node': 22.10.2 + '@types/node': 22.10.5 '@types/body-parser@1.19.5': dependencies: @@ -5570,7 +5594,7 @@ snapshots: '@types/connect@3.4.38': dependencies: - '@types/node': 22.10.2 + '@types/node': 22.10.5 '@types/deep-eql@4.0.2': {} @@ -5580,7 +5604,7 @@ snapshots: '@types/express-serve-static-core@4.19.6': dependencies: - '@types/node': 22.10.2 + '@types/node': 22.10.5 '@types/qs': 6.9.17 '@types/range-parser': 1.2.7 '@types/send': 0.17.4 @@ -5614,7 +5638,7 @@ snapshots: '@types/node-fetch@2.6.12': dependencies: - '@types/node': 22.10.2 + '@types/node': 22.10.5 form-data: 4.0.1 '@types/node@11.11.6': {} @@ -5652,12 +5676,12 @@ snapshots: '@types/send@0.17.4': dependencies: '@types/mime': 1.3.5 - '@types/node': 22.10.2 + '@types/node': 22.10.5 '@types/serve-static@1.15.7': dependencies: '@types/http-errors': 2.0.4 - '@types/node': 22.10.2 + '@types/node': 22.10.5 '@types/send': 0.17.4 '@types/unist@3.0.3': {} @@ -5668,11 +5692,11 @@ snapshots: '@types/ws@7.4.7': dependencies: - '@types/node': 22.10.2 + '@types/node': 22.10.5 '@types/ws@8.5.13': dependencies: - '@types/node': 22.10.2 + '@types/node': 22.10.5 '@typescript-eslint/eslint-plugin@8.19.0(@typescript-eslint/parser@8.19.0(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1)(typescript@5.7.2)': dependencies: @@ -5814,7 +5838,7 @@ snapshots: dependencies: algo-msgpack-with-bigint: 2.1.1 buffer: 6.0.3 - cross-fetch: 3.2.0 + cross-fetch: 3.1.8 hi-base32: 0.5.1 js-sha256: 0.9.0 js-sha3: 0.8.0 @@ -5847,11 +5871,11 @@ snapshots: ansicolors@0.3.2: {} - arbundles@0.11.2(arweave@1.15.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10): + arbundles@0.11.2(arweave@1.15.5)(bufferutil@4.0.8)(utf-8-validate@5.0.10): dependencies: '@ethersproject/bytes': 5.7.0 '@ethersproject/hash': 5.7.0 - '@ethersproject/providers': 5.7.2(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@ethersproject/providers': 5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10) '@ethersproject/signing-key': 5.7.0 '@ethersproject/transactions': 5.7.0 '@ethersproject/wallet': 5.7.0 @@ -5901,7 +5925,7 @@ snapshots: asn1.js@5.4.1: dependencies: - bn.js: 4.11.6 + bn.js: 4.12.1 inherits: 2.0.4 minimalistic-assert: 1.0.1 safer-buffer: 2.1.2 @@ -6715,13 +6739,13 @@ snapshots: locate-path: 6.0.0 path-exists: 4.0.0 - flash-sdk@2.24.3(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10): + flash-sdk@2.24.3(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10): dependencies: - '@coral-xyz/anchor': 0.27.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@pythnetwork/client': 2.22.0(@solana/web3.js@1.95.8(bufferutil@4.0.9)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@pythnetwork/price-service-client': 1.9.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@solana/spl-token': 0.3.11(@solana/web3.js@1.95.8(bufferutil@4.0.9)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) - '@solana/web3.js': 1.95.8(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@coral-xyz/anchor': 0.27.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) + '@pythnetwork/client': 2.22.0(@solana/web3.js@1.95.8(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(utf-8-validate@5.0.10) + '@pythnetwork/price-service-client': 1.9.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) + '@solana/spl-token': 0.3.11(@solana/web3.js@1.95.8(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) + '@solana/web3.js': 1.95.8(bufferutil@4.0.8)(utf-8-validate@5.0.10) '@types/node': 20.17.11 bignumber.js: 9.1.2 bs58: 5.0.0 @@ -6809,11 +6833,6 @@ snapshots: hasown: 2.0.2 math-intrinsics: 1.1.0 - get-proto@1.0.1: - dependencies: - dunder-proto: 1.0.1 - es-object-atoms: 1.0.0 - get-stream@5.2.0: dependencies: pump: 3.0.2 @@ -6892,7 +6911,7 @@ snapshots: '@types/node': 18.19.68 '@types/node-fetch': 2.6.12 abort-controller: 3.0.0 - agentkeepalive: 4.5.0 + agentkeepalive: 4.6.0 form-data-encoder: 1.7.2 formdata-node: 4.4.1 node-fetch: 2.7.0 @@ -7026,6 +7045,10 @@ snapshots: through: 2.3.8 wrap-ansi: 6.2.0 + invariant@2.2.4: + dependencies: + loose-envify: 1.4.0 + ipaddr.js@1.9.1: {} ipaddr.js@2.2.0: {} @@ -7070,13 +7093,6 @@ snapshots: is-path-inside@3.0.3: {} - is-regex@1.2.1: - dependencies: - call-bound: 1.0.3 - gopd: 1.2.0 - has-tostringtag: 1.0.2 - hasown: 2.0.2 - is-retry-allowed@2.2.0: {} is-stream@3.0.0: {} @@ -7093,11 +7109,11 @@ snapshots: isomorphic-ws@4.0.1(ws@7.5.10(bufferutil@4.0.8)(utf-8-validate@5.0.10)): dependencies: - ws: 7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10) + ws: 7.5.10(bufferutil@4.0.8)(utf-8-validate@5.0.10) - isomorphic-ws@4.0.1(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)): + isomorphic-ws@4.0.1(ws@8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)): dependencies: - ws: 8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) jackspeak@3.4.3: dependencies: @@ -7553,7 +7569,7 @@ snapshots: '@types/node': 18.19.68 '@types/node-fetch': 2.6.12 abort-controller: 3.0.0 - agentkeepalive: 4.5.0 + agentkeepalive: 4.6.0 form-data-encoder: 1.7.2 formdata-node: 4.4.1 node-fetch: 2.7.0 @@ -7817,12 +7833,6 @@ snapshots: safe-buffer@5.2.1: {} - safe-regex-test@1.1.0: - dependencies: - call-bound: 1.0.3 - es-errors: 1.3.0 - is-regex: 1.2.1 - safer-buffer@2.1.2: {} scrypt-js@3.0.1: {} @@ -8116,7 +8126,7 @@ snapshots: '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 22.10.2 + '@types/node': 22.10.5 acorn: 8.14.0 acorn-walk: 8.3.4 arg: 4.1.3 @@ -8338,12 +8348,12 @@ snapshots: wrappy@1.0.2: {} - ws@7.4.6(bufferutil@4.0.9)(utf-8-validate@5.0.10): + ws@7.4.6(bufferutil@4.0.8)(utf-8-validate@5.0.10): optionalDependencies: - bufferutil: 4.0.9 + bufferutil: 4.0.8 utf-8-validate: 5.0.10 - ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10): + ws@7.5.10(bufferutil@4.0.8)(utf-8-validate@5.0.10): optionalDependencies: bufferutil: 4.0.8 utf-8-validate: 5.0.10 From 272f77f851071eef212873dc39c95a5dde6bfd44 Mon Sep 17 00:00:00 2001 From: michaelessiet Date: Fri, 10 Jan 2025 17:31:08 +0100 Subject: [PATCH 3/5] feat: token balances --- src/actions/balance.ts | 5 ++- src/actions/index.ts | 2 + src/actions/tokenBalances.ts | 80 +++++++++++++++++++++++++++++++++ src/tools/get_balance.ts | 53 +++------------------- src/tools/get_token_balances.ts | 65 +++++++++++++++++++++++++++ test/agent_sdks/vercel_ai.ts | 1 - 6 files changed, 156 insertions(+), 50 deletions(-) create mode 100644 src/actions/tokenBalances.ts create mode 100644 src/tools/get_token_balances.ts diff --git a/src/actions/balance.ts b/src/actions/balance.ts index 1ee1b56..437e479 100644 --- a/src/actions/balance.ts +++ b/src/actions/balance.ts @@ -1,6 +1,6 @@ import { PublicKey } from "@solana/web3.js"; -import { Action } from "../types/action"; -import { SolanaAgentKit } from "../agent"; +import type { Action } from "../types/action"; +import type { SolanaAgentKit } from "../agent"; import { z } from "zod"; import { get_balance } from "../tools"; @@ -54,6 +54,7 @@ const balanceAction: Action = { return { status: "success", balance: balance, + token: input.tokenAddress || "SOL", }; }, }; diff --git a/src/actions/index.ts b/src/actions/index.ts index c974209..9eec07d 100644 --- a/src/actions/index.ts +++ b/src/actions/index.ts @@ -30,9 +30,11 @@ import launchPumpfunTokenAction from "./launchPumpfunToken"; import getWalletAddressAction from "./getWalletAddress"; import flashOpenTradeAction from "./flashOpenTrade"; import flashCloseTradeAction from "./flashCloseTrade"; +import tokenBalancesAction from "./tokenBalances"; export const ACTIONS = { WALLET_ADDRESS_ACTION: getWalletAddressAction, + TOKEN_BALANCES_ACTION: tokenBalancesAction, DEPLOY_TOKEN_ACTION: deployTokenAction, BALANCE_ACTION: balanceAction, TRANSFER_ACTION: transferAction, diff --git a/src/actions/tokenBalances.ts b/src/actions/tokenBalances.ts new file mode 100644 index 0000000..960fca1 --- /dev/null +++ b/src/actions/tokenBalances.ts @@ -0,0 +1,80 @@ +import { PublicKey } from "@solana/web3.js"; +import type { Action } from "../types/action"; +import type { SolanaAgentKit } from "../agent"; +import { z } from "zod"; +import { get_token_balance } from "../tools/get_token_balances"; + +const tokenBalancesAction: Action = { + name: "TOKEN_BALANCE_ACTION", + similes: [ + "check token balances", + "get wallet token balances", + "view token balances", + "show token balances", + "check token balance", + ], + description: `Get the token balances of a Solana wallet. + If you want to get the balance of your wallet, you don't need to provide the wallet address.`, + examples: [ + [ + { + input: {}, + output: { + status: "success", + balance: { + sol: 100, + tokens: [ + { + tokenAddress: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", + name: "USD Coin", + symbol: "USDC", + balance: 100, + decimals: 9, + }, + ], + }, + }, + explanation: "Get token balances of the wallet", + }, + ], + [ + { + input: { + walletAddress: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", + }, + output: { + status: "success", + balance: { + sol: 100, + tokens: [ + { + tokenAddress: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", + name: "USD Coin", + symbol: "USDC", + balance: 100, + decimals: 9, + }, + ], + }, + }, + explanation: "Get address token balance", + }, + ], + ], + schema: z.object({ + walletAddress: z.string().optional(), + }), + handler: async (agent: SolanaAgentKit, input: Record) => { + const balance = await get_token_balance( + agent, + input.tokenAddress && new PublicKey(input.tokenAddress), + ); + + return { + status: "success", + balance: balance, + }; + }, +}; + +export default tokenBalancesAction; diff --git a/src/tools/get_balance.ts b/src/tools/get_balance.ts index 3e30021..f7a6a1e 100644 --- a/src/tools/get_balance.ts +++ b/src/tools/get_balance.ts @@ -1,7 +1,5 @@ -import { LAMPORTS_PER_SOL, PublicKey } from "@solana/web3.js"; -import { SolanaAgentKit } from "../index"; -import { TOKEN_PROGRAM_ID } from "@solana/spl-token"; -import { getTokenMetadata } from "../utils/tokenMetadata"; +import { LAMPORTS_PER_SOL, type PublicKey } from "@solana/web3.js"; +import type { SolanaAgentKit } from "../index"; /** * Get the balance of SOL or an SPL token for the agent's wallet @@ -12,51 +10,12 @@ import { getTokenMetadata } from "../utils/tokenMetadata"; export async function get_balance( agent: SolanaAgentKit, token_address?: PublicKey, -): Promise< - | number - | { - sol: number; - tokens: Array<{ - tokenAddress: string; - name: string; - symbol: string; - balance: number; - decimals: number; - }>; - } -> { +): Promise { if (!token_address) { - const [lamportsBalance, tokenAccountData] = await Promise.all([ - agent.connection.getBalance(agent.wallet_address), - agent.connection.getParsedTokenAccountsByOwner(agent.wallet_address, { - programId: TOKEN_PROGRAM_ID, - }), - ]); - - const removedZeroBalance = tokenAccountData.value.filter( - (v) => v.account.data.parsed.info.tokenAmount.uiAmount !== 0, + return ( + (await agent.connection.getBalance(agent.wallet_address)) / + LAMPORTS_PER_SOL ); - - const tokenBalances = await Promise.all( - removedZeroBalance.map(async (v) => { - const mint = v.account.data.parsed.info.mint; - const mintInfo = await getTokenMetadata(agent.connection, mint); - return { - tokenAddress: mint, - name: mintInfo.name ?? "", - symbol: mintInfo.symbol ?? "", - balance: v.account.data.parsed.info.tokenAmount.uiAmount as number, - decimals: v.account.data.parsed.info.tokenAmount.decimals as number, - }; - }), - ); - - const solBalance = lamportsBalance / LAMPORTS_PER_SOL; - - return { - sol: solBalance, - tokens: tokenBalances, - }; } const token_account = diff --git a/src/tools/get_token_balances.ts b/src/tools/get_token_balances.ts new file mode 100644 index 0000000..00e6310 --- /dev/null +++ b/src/tools/get_token_balances.ts @@ -0,0 +1,65 @@ +import { LAMPORTS_PER_SOL, type PublicKey } from "@solana/web3.js"; +import type { SolanaAgentKit } from "../index"; +import { TOKEN_PROGRAM_ID } from "@solana/spl-token"; +import { getTokenMetadata } from "../utils/tokenMetadata"; + +/** + * Get the token balances of a Solana wallet + * @param agent - SolanaAgentKit instance + * @param token_address - Optional SPL token mint address. If not provided, returns SOL balance + * @returns Promise resolving to the balance as an object containing sol balance and token balances with their respective mints, symbols, names and decimals + */ +export async function get_token_balance( + agent: SolanaAgentKit, + token_address?: PublicKey, +): Promise< + | number + | { + sol: number; + tokens: Array<{ + tokenAddress: string; + name: string; + symbol: string; + balance: number; + decimals: number; + }>; + } +> { + if (!token_address) { + const [lamportsBalance, tokenAccountData] = await Promise.all([ + agent.connection.getBalance(agent.wallet_address), + agent.connection.getParsedTokenAccountsByOwner(agent.wallet_address, { + programId: TOKEN_PROGRAM_ID, + }), + ]); + + const removedZeroBalance = tokenAccountData.value.filter( + (v) => v.account.data.parsed.info.tokenAmount.uiAmount !== 0, + ); + + const tokenBalances = await Promise.all( + removedZeroBalance.map(async (v) => { + const mint = v.account.data.parsed.info.mint; + const mintInfo = await getTokenMetadata(agent.connection, mint); + return { + tokenAddress: mint, + name: mintInfo.name ?? "", + symbol: mintInfo.symbol ?? "", + balance: v.account.data.parsed.info.tokenAmount.uiAmount as number, + decimals: v.account.data.parsed.info.tokenAmount.decimals as number, + }; + }), + ); + + const solBalance = lamportsBalance / LAMPORTS_PER_SOL; + + return { + sol: solBalance, + tokens: tokenBalances, + }; + } + + const token_account = + await agent.connection.getTokenAccountBalance(token_address); + return token_account.value.uiAmount || 0; +} diff --git a/test/agent_sdks/vercel_ai.ts b/test/agent_sdks/vercel_ai.ts index 77fda22..bf1585e 100644 --- a/test/agent_sdks/vercel_ai.ts +++ b/test/agent_sdks/vercel_ai.ts @@ -95,7 +95,6 @@ async function runChatMode() { ); const tools = createVercelAITools(solanaAgent); - console.log(tools); const rl = readline.createInterface({ input: process.stdin, From 51cf665c74c1a647c7598984e59f82758993c0eb Mon Sep 17 00:00:00 2001 From: michaelessiet Date: Fri, 10 Jan 2025 17:31:29 +0100 Subject: [PATCH 4/5] lint --- src/tools/squads_multisig/deposit_to_multisig.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/squads_multisig/deposit_to_multisig.ts b/src/tools/squads_multisig/deposit_to_multisig.ts index 11a2582..e2b23ad 100644 --- a/src/tools/squads_multisig/deposit_to_multisig.ts +++ b/src/tools/squads_multisig/deposit_to_multisig.ts @@ -54,7 +54,7 @@ export async function deposit_to_multisig( mint, agent.wallet_address, ); - let transaction = new Transaction(); + const transaction = new Transaction(); const toAta = await getAssociatedTokenAddress(mint, to, true); const toTokenAccountInfo = await agent.connection.getAccountInfo(toAta); // Create associated token account if it doesn't exist From 6ef55a04dad4173387523d62de2b6a1a5d2898e7 Mon Sep 17 00:00:00 2001 From: michaelessiet Date: Fri, 10 Jan 2025 17:38:20 +0100 Subject: [PATCH 5/5] fix: parse provided wallet address to token balances --- src/agent/index.ts | 28 ++++++----- src/tools/get_token_balances.ts | 86 +++++++++++++++------------------ 2 files changed, 55 insertions(+), 59 deletions(-) diff --git a/src/agent/index.ts b/src/agent/index.ts index 0238b0d..2eec42a 100644 --- a/src/agent/index.ts +++ b/src/agent/index.ts @@ -92,6 +92,7 @@ import { create_proposal } from "../tools/squads_multisig/create_proposal"; import { approve_proposal } from "../tools/squads_multisig/approve_proposal"; import { execute_transaction } from "../tools/squads_multisig/execute_proposal"; import { reject_proposal } from "../tools/squads_multisig/reject_proposal"; +import { get_token_balance } from "../tools/get_token_balances"; /** * Main class for interacting with Solana blockchain @@ -163,22 +164,23 @@ export class SolanaAgentKit { return deploy_collection(this, options); } - async getBalance(token_address?: PublicKey): Promise< - | number - | { - sol: number; - tokens: Array<{ - tokenAddress: string; - name: string; - symbol: string; - balance: number; - decimals: number; - }>; - } - > { + async getBalance(token_address?: PublicKey): Promise { return get_balance(this, token_address); } + async getTokenBalances(wallet_address?: PublicKey): Promise<{ + sol: number; + tokens: Array<{ + tokenAddress: string; + name: string; + symbol: string; + balance: number; + decimals: number; + }>; + }> { + return get_token_balance(this, wallet_address); + } + async getBalanceOther( walletAddress: PublicKey, tokenAddress?: PublicKey, diff --git a/src/tools/get_token_balances.ts b/src/tools/get_token_balances.ts index 00e6310..01f2f2d 100644 --- a/src/tools/get_token_balances.ts +++ b/src/tools/get_token_balances.ts @@ -11,55 +11,49 @@ import { getTokenMetadata } from "../utils/tokenMetadata"; */ export async function get_token_balance( agent: SolanaAgentKit, - token_address?: PublicKey, -): Promise< - | number - | { - sol: number; - tokens: Array<{ - tokenAddress: string; - name: string; - symbol: string; - balance: number; - decimals: number; - }>; - } -> { - if (!token_address) { - const [lamportsBalance, tokenAccountData] = await Promise.all([ - agent.connection.getBalance(agent.wallet_address), - agent.connection.getParsedTokenAccountsByOwner(agent.wallet_address, { + walletAddress?: PublicKey, +): Promise<{ + sol: number; + tokens: Array<{ + tokenAddress: string; + name: string; + symbol: string; + balance: number; + decimals: number; + }>; +}> { + const [lamportsBalance, tokenAccountData] = await Promise.all([ + agent.connection.getBalance(walletAddress ?? agent.wallet_address), + agent.connection.getParsedTokenAccountsByOwner( + walletAddress ?? agent.wallet_address, + { programId: TOKEN_PROGRAM_ID, - }), - ]); + }, + ), + ]); - const removedZeroBalance = tokenAccountData.value.filter( - (v) => v.account.data.parsed.info.tokenAmount.uiAmount !== 0, - ); + const removedZeroBalance = tokenAccountData.value.filter( + (v) => v.account.data.parsed.info.tokenAmount.uiAmount !== 0, + ); - const tokenBalances = await Promise.all( - removedZeroBalance.map(async (v) => { - const mint = v.account.data.parsed.info.mint; - const mintInfo = await getTokenMetadata(agent.connection, mint); - return { - tokenAddress: mint, - name: mintInfo.name ?? "", - symbol: mintInfo.symbol ?? "", - balance: v.account.data.parsed.info.tokenAmount.uiAmount as number, - decimals: v.account.data.parsed.info.tokenAmount.decimals as number, - }; - }), - ); + const tokenBalances = await Promise.all( + removedZeroBalance.map(async (v) => { + const mint = v.account.data.parsed.info.mint; + const mintInfo = await getTokenMetadata(agent.connection, mint); + return { + tokenAddress: mint, + name: mintInfo.name ?? "", + symbol: mintInfo.symbol ?? "", + balance: v.account.data.parsed.info.tokenAmount.uiAmount as number, + decimals: v.account.data.parsed.info.tokenAmount.decimals as number, + }; + }), + ); - const solBalance = lamportsBalance / LAMPORTS_PER_SOL; + const solBalance = lamportsBalance / LAMPORTS_PER_SOL; - return { - sol: solBalance, - tokens: tokenBalances, - }; - } - - const token_account = - await agent.connection.getTokenAccountBalance(token_address); - return token_account.value.uiAmount || 0; + return { + sol: solBalance, + tokens: tokenBalances, + }; }