From f84a618c6c465a4f5bd96909e1d5a2fe8b5be941 Mon Sep 17 00:00:00 2001 From: Arihant Bansal <17180950+arihantbansal@users.noreply.github.com> Date: Sun, 22 Dec 2024 00:47:25 +0530 Subject: [PATCH 01/17] feat: fix readme issues, and add types --- README.md | 90 ++++--------------------- src/agent/index.ts | 106 +++++++++++++++--------------- src/tools/get_balance.ts | 12 ++-- src/tools/launch_pumpfun_token.ts | 78 +++++++++++++--------- 4 files changed, 122 insertions(+), 164 deletions(-) diff --git a/README.md b/README.md index 98708ec..a4a0093 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ An open-source toolkit for connecting AI agents to Solana protocols. Now, any agent, using any model can autonomously perform 15+ Solana actions: - Trade tokens -- Launch new tokens +- Launch new tokens - Lend assets - Send compressed airdrops - Execute blinks @@ -96,10 +96,10 @@ const tools = createSolanaTools(agent); ### Deploy a New Token ```typescript -import { deploy_token } from "solana-agent-kit"; - -const result = await deploy_token( - agent, +const result = await agent.deployToken( + "my ai token", // name + "uri", // uri + "token", // symbol 9, // decimals 1000000 // initial supply ); @@ -110,9 +110,7 @@ console.log("Token Mint Address:", result.mint.toString()); ### Create NFT Collection ```typescript -import { deploy_collection } from "solana-agent-kit"; - -const collection = await deploy_collection(agent, { +const collection = await agent.deployCollection({ name: "My NFT Collection", uri: "https://arweave.net/metadata.json", royaltyBasisPoints: 500, // 5% @@ -128,11 +126,9 @@ const collection = await deploy_collection(agent, { ### Swap Tokens ```typescript -import { trade } from "solana-agent-kit"; import { PublicKey } from "@solana/web3.js"; -const signature = await trade( - agent, +const signature = await agent.trade( new PublicKey("target-token-mint"), 100, // amount new PublicKey("source-token-mint"), @@ -143,46 +139,24 @@ const signature = await trade( ### Lend Tokens ```typescript -import { lendAsset } from "solana-agent-kit"; import { PublicKey } from "@solana/web3.js"; -const signature = await lendAsset( - agent, - 100 // amount +const signature = await agent.lendAssets( + 100 // amount of USDC to lend ); ``` ### Stake SOL ```typescript -import { stakeWithJup } from "solana-agent-kit"; - -const signature = await stakeWithJup( - agent, - 1 // amount in SOL +const signature = await agent.stake( + 1 // amount in SOL to stake ); ``` -### Fetch Token Price - -```typescript -import { fetchPrice } from "solana-agent-kit"; - -const price = await fetchPrice( - agent, - "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN" // Token mint address -); - -console.log("Price in USDC:", price); -``` - ### Send an SPL Token Airdrop via ZK Compression ```typescript -import { - sendCompressedAirdrop, - getAirdropCostEstimate, -} from "solana-agent-kit"; import { PublicKey } from "@solana/web3.js"; (async () => { @@ -194,8 +168,7 @@ import { PublicKey } from "@solana/web3.js"; ) ); - const signature = await sendCompressedAirdrop( - agent, + const signature = await agent.sendCompressedAirdrop( new PublicKey("JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN"), // mint 42, // amount per recipient [ @@ -207,45 +180,6 @@ import { PublicKey } from "@solana/web3.js"; })(); ``` -## API Reference - -### Core Functions - -#### `deploy_token(agent, decimals?, name, uri, symbol, initialSupply?)` - -Deploy a new SPL token with optional initial supply. If not specified, decimals default to 9. - -#### `deploy_collection(agent, options)` - -Create a new NFT collection with customizable metadata and royalties. - -#### `mintCollectionNFT(agent, collectionMint, metadata, recipient?)` - -Mint a new NFT as part of an existing collection. - -#### `transfer(agent, to, amount, mint?)` - -Transfer SOL or SPL tokens to a recipient. - -#### `trade(agent, outputMint, inputAmount, inputMint?, slippageBps?)` - -Swap tokens using Jupiter Exchange integration. - -#### `get_balance(agent, token_address)` - -Check SOL or token balance for the agent's wallet. - -#### `lendAsset(agent, assetMint, amount, apiKey)` - -Lend idle assets to earn interest with Lulo. - -#### `stakeWithJup(agent, amount)` - -Stake SOL with Jupiter to earn rewards. - -#### `sendCompressedAirdrop(agent, mintAddress, amount, recipients, priorityFeeInLamports?, shouldLog?)` - -Send an SPL token airdrop to many recipients at low cost via ZK Compression. ## Dependencies diff --git a/src/agent/index.ts b/src/agent/index.ts index 721e464..90e47ef 100644 --- a/src/agent/index.ts +++ b/src/agent/index.ts @@ -1,4 +1,4 @@ -import { Connection, Keypair, PublicKey } from "@solana/web3.js";; +import { Connection, Keypair, PublicKey } from "@solana/web3.js"; import bs58 from "bs58"; import Decimal from "decimal.js"; import { DEFAULT_OPTIONS } from "../constants"; @@ -25,9 +25,16 @@ import { stakeWithJup, sendCompressedAirdrop, createOrcaSingleSidedWhirlpool, - FEE_TIERS + FEE_TIERS, } from "../tools"; -import { CollectionOptions, PumpFunTokenOptions } from "../types"; +import { + CollectionDeployment, + CollectionOptions, + JupiterTokenData, + MintCollectionNFTResponse, + PumpfunLaunchResponse, + PumpFunTokenOptions, +} from "../types"; import { BN } from "@coral-xyz/anchor"; /** @@ -48,7 +55,7 @@ export class SolanaAgentKit { constructor( private_key: string, rpc_url = "https://api.mainnet-beta.solana.com", - openai_api_key: string + openai_api_key: string, ) { this.connection = new Connection(rpc_url); this.wallet = Keypair.fromSecretKey(bs58.decode(private_key)); @@ -66,40 +73,46 @@ export class SolanaAgentKit { uri: string, symbol: string, decimals: number = DEFAULT_OPTIONS.TOKEN_DECIMALS, - initialSupply?: number - ) { + initialSupply?: number, + ): Promise<{ mint: PublicKey }> { return deploy_token(this, name, uri, symbol, decimals, initialSupply); } - async deployCollection(options: CollectionOptions) { + async deployCollection( + options: CollectionOptions, + ): Promise { return deploy_collection(this, options); } - async getBalance(token_address?: PublicKey) { + async getBalance(token_address?: PublicKey): Promise { return get_balance(this, token_address); } async mintNFT( collectionMint: PublicKey, metadata: Parameters[2], - recipient?: PublicKey - ) { + recipient?: PublicKey, + ): Promise { return mintCollectionNFT(this, collectionMint, metadata, recipient); } - async transfer(to: PublicKey, amount: number, mint?: PublicKey) { + async transfer( + to: PublicKey, + amount: number, + mint?: PublicKey, + ): Promise { return transfer(this, to, amount, mint); } - async registerDomain(name: string, spaceKB?: number) { + async registerDomain(name: string, spaceKB?: number): Promise { return registerDomain(this, name, spaceKB); } - async resolveSolDomain(domain: string) { + async resolveSolDomain(domain: string): Promise { return resolveSolDomain(this, domain); } - async getPrimaryDomain(account: PublicKey) { + async getPrimaryDomain(account: PublicKey): Promise { return getPrimaryDomain(this, account); } @@ -107,24 +120,28 @@ export class SolanaAgentKit { outputMint: PublicKey, inputAmount: number, inputMint?: PublicKey, - slippageBps: number = DEFAULT_OPTIONS.SLIPPAGE_BPS - ) { + slippageBps: number = DEFAULT_OPTIONS.SLIPPAGE_BPS, + ): Promise { return trade(this, outputMint, inputAmount, inputMint, slippageBps); } - async lendAssets(amount: number) { + async lendAssets(amount: number): Promise { return lendAsset(this, amount); } - async getTPS() { + async getTPS(): Promise { return getTPS(this); } - async getTokenDataByAddress(mint: string) { + async getTokenDataByAddress( + mint: string, + ): Promise { return getTokenDataByAddress(new PublicKey(mint)); } - async getTokenDataByTicker(ticker: string) { + async getTokenDataByTicker( + ticker: string, + ): Promise { return getTokenDataByTicker(ticker); } @@ -133,19 +150,19 @@ export class SolanaAgentKit { tokenTicker: string, description: string, imageUrl: string, - options?: PumpFunTokenOptions - ) { + options?: PumpFunTokenOptions, + ): Promise { return launchPumpFunToken( this, tokenName, tokenTicker, description, imageUrl, - options + options, ); } - async stake(amount: number) { + async stake(amount: number): Promise { return stakeWithJup(this, amount); } @@ -155,7 +172,7 @@ export class SolanaAgentKit { decimals: number, recipients: string[], priorityFeeInLamports: number, - shouldLog: boolean + shouldLog: boolean, ): Promise { return await sendCompressedAirdrop( this, @@ -164,7 +181,7 @@ export class SolanaAgentKit { decimals, recipients.map((recipient) => new PublicKey(recipient)), priorityFeeInLamports, - shouldLog + shouldLog, ); } @@ -175,7 +192,7 @@ export class SolanaAgentKit { initialPrice: Decimal, maxPrice: Decimal, feeTier: keyof typeof FEE_TIERS, - ) { + ): Promise { return createOrcaSingleSidedWhirlpool( this, depositTokenAmount, @@ -183,18 +200,16 @@ export class SolanaAgentKit { otherTokenMint, initialPrice, maxPrice, - feeTier - ) + feeTier, + ); } async raydiumCreateAmmV4( marketId: PublicKey, - baseAmount: BN, quoteAmount: BN, - startTime: BN, - ) { + ): Promise { return raydiumCreateAmmV4( this, marketId, @@ -203,64 +218,51 @@ export class SolanaAgentKit { quoteAmount, startTime, - ) + ); } async raydiumCreateClmm( mint1: PublicKey, mint2: PublicKey, - configId: PublicKey, - initialPrice: Decimal, startTime: BN, - ) { + ): Promise { return raydiumCreateClmm( this, - mint1, mint2, - configId, - initialPrice, startTime, - ) + ); } async raydiumCreateCpmm( mint1: PublicKey, mint2: PublicKey, - configId: PublicKey, - mintAAmount: BN, mintBAmount: BN, - startTime: BN, - ) { + ): Promise { return raydiumCreateCpmm( this, - mint1, mint2, - configId, - mintAAmount, mintBAmount, - startTime, - ) + ); } async openbookCreateMarket( baseMint: PublicKey, quoteMint: PublicKey, - lotSize: number = 1, tickSize: number = 0.01, - ) { + ): Promise { return openbookCreateMarket( this, baseMint, @@ -268,6 +270,6 @@ export class SolanaAgentKit { lotSize, tickSize, - ) + ); } } diff --git a/src/tools/get_balance.ts b/src/tools/get_balance.ts index 2bdf3f2..36cdfef 100644 --- a/src/tools/get_balance.ts +++ b/src/tools/get_balance.ts @@ -9,11 +9,15 @@ import { SolanaAgentKit } from "../index"; */ export async function get_balance( agent: SolanaAgentKit, - token_address?: PublicKey -) { + token_address?: PublicKey, +): Promise { if (!token_address) - return await agent.connection.getBalance(agent.wallet_address) / LAMPORTS_PER_SOL + return ( + (await agent.connection.getBalance(agent.wallet_address)) / + LAMPORTS_PER_SOL + ); - const token_account = await agent.connection.getTokenAccountBalance(token_address); + const token_account = + await agent.connection.getTokenAccountBalance(token_address); return token_account.value.uiAmount; } diff --git a/src/tools/launch_pumpfun_token.ts b/src/tools/launch_pumpfun_token.ts index 397a177..0c3e6f5 100644 --- a/src/tools/launch_pumpfun_token.ts +++ b/src/tools/launch_pumpfun_token.ts @@ -1,23 +1,27 @@ // src/tools/launch_pumpfun_token.ts import { VersionedTransaction, Keypair } from "@solana/web3.js"; -import { PumpFunTokenOptions, SolanaAgentKit } from "../index"; +import { + PumpfunLaunchResponse, + PumpFunTokenOptions, + SolanaAgentKit, +} from "../index"; async function uploadMetadata( - tokenName: string, + tokenName: string, tokenTicker: string, description: string, imageUrl: string, - options?: PumpFunTokenOptions + options?: PumpFunTokenOptions, ): Promise { // Create metadata object const formData = new URLSearchParams(); - formData.append('name', tokenName); + formData.append("name", tokenName); formData.append("symbol", tokenTicker); formData.append("description", description); formData.append("showName", "true"); - if (options?.twitter) formData.append('twitter', options.twitter); + if (options?.twitter) formData.append("twitter", options.twitter); if (options?.telegram) formData.append("telegram", options.telegram); if (options?.website) formData.append("website", options.website); @@ -35,13 +39,12 @@ async function uploadMetadata( } // Add file if exists if (files?.file) { - finalFormData.append('file', files.file); + finalFormData.append("file", files.file); } - const metadataResponse = await fetch("https://pump.fun/api/ipfs", { method: "POST", - body: finalFormData + body: finalFormData, }); if (!metadataResponse.ok) { @@ -55,7 +58,7 @@ async function createTokenTransaction( agent: SolanaAgentKit, mintKeypair: Keypair, metadataResponse: any, - options?: PumpFunTokenOptions + options?: PumpFunTokenOptions, ) { const payload = { publicKey: agent.wallet_address.toBase58(), @@ -78,12 +81,14 @@ async function createTokenTransaction( headers: { "Content-Type": "application/json", }, - body: JSON.stringify(payload) + body: JSON.stringify(payload), }); if (!response.ok) { const errorText = await response.text(); - throw new Error(`Transaction creation failed: ${response.status} - ${errorText}`); + throw new Error( + `Transaction creation failed: ${response.status} - ${errorText}`, + ); } return response; @@ -92,12 +97,13 @@ async function createTokenTransaction( async function signAndSendTransaction( kit: SolanaAgentKit, tx: VersionedTransaction, - mintKeypair: Keypair + mintKeypair: Keypair, ) { try { // Get the latest blockhash - const { blockhash, lastValidBlockHeight } = await kit.connection.getLatestBlockhash(); - + const { blockhash, lastValidBlockHeight } = + await kit.connection.getLatestBlockhash(); + // Update transaction with latest blockhash tx.message.recentBlockhash = blockhash; @@ -107,15 +113,15 @@ async function signAndSendTransaction( // Send and confirm transaction with options const signature = await kit.connection.sendTransaction(tx, { skipPreflight: false, - preflightCommitment: 'confirmed', - maxRetries: 5 + preflightCommitment: "confirmed", + maxRetries: 5, }); // Wait for confirmation const confirmation = await kit.connection.confirmTransaction({ signature, blockhash, - lastValidBlockHeight + lastValidBlockHeight, }); if (confirmation.value.err) { @@ -124,9 +130,9 @@ async function signAndSendTransaction( return signature; } catch (error) { - console.error('Transaction send error:', error); - if (error instanceof Error && 'logs' in error) { - console.error('Transaction logs:', error.logs); + console.error("Transaction send error:", error); + if (error instanceof Error && "logs" in error) { + console.error("Transaction logs:", error.logs); } throw error; } @@ -140,6 +146,7 @@ async function signAndSendTransaction( * @param description - Description of the token * @param imageUrl - URL of the token image * @param options - Optional token options (twitter, telegram, website, initialLiquiditySOL, slippageBps, priorityFee) + * @returns - Signature of the transaction, mint address and metadata URI, if successful, else error */ export async function launchPumpFunToken( agent: SolanaAgentKit, @@ -147,15 +154,27 @@ export async function launchPumpFunToken( tokenTicker: string, description: string, imageUrl: string, - options?: PumpFunTokenOptions -) { + options?: PumpFunTokenOptions, +): Promise { try { - const mintKeypair = Keypair.generate(); - const metadataResponse = await uploadMetadata(tokenName, tokenTicker, description, imageUrl, options); - const response = await createTokenTransaction(agent, mintKeypair, metadataResponse, options); + const metadataResponse = await uploadMetadata( + tokenName, + tokenTicker, + description, + imageUrl, + options, + ); + const response = await createTokenTransaction( + agent, + mintKeypair, + metadataResponse, + options, + ); const transactionData = await response.arrayBuffer(); - const tx = VersionedTransaction.deserialize(new Uint8Array(transactionData)); + const tx = VersionedTransaction.deserialize( + new Uint8Array(transactionData), + ); const signature = await signAndSendTransaction(agent, tx, mintKeypair); return { @@ -163,12 +182,11 @@ export async function launchPumpFunToken( mint: mintKeypair.publicKey.toBase58(), metadataUri: metadataResponse.metadataUri, }; - } catch (error) { console.error("Error in launchpumpfuntoken:", error); - if (error instanceof Error && 'logs' in error) { - console.error('Transaction logs:', (error as any).logs); + if (error instanceof Error && "logs" in error) { + console.error("Transaction logs:", (error as any).logs); } throw error; } -} \ No newline at end of file +} From 7d076c8f4cc17c079138445816d295e14941a572 Mon Sep 17 00:00:00 2001 From: Zhe <106411133+zhe-t@users.noreply.github.com> Date: Sun, 22 Dec 2024 19:27:23 +0000 Subject: [PATCH 02/17] chore: add pyth dep --- package.json | 1 + pnpm-lock.yaml | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/package.json b/package.json index 5c085fe..790b80c 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "@metaplex-foundation/umi-web3js-adapters": "^0.9.2", "@orca-so/common-sdk": "0.6.4", "@orca-so/whirlpools-sdk": "^0.13.12", + "@pythnetwork/price-service-client": "^1.9.0", "@raydium-io/raydium-sdk-v2": "0.1.95-alpha", "@solana/spl-token": "^0.4.9", "@solana/web3.js": "^1.95.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7aa38c3..289b940 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -38,6 +38,9 @@ importers: '@metaplex-foundation/mpl-token-metadata': specifier: ^3.3.0 version: 3.3.0(@metaplex-foundation/umi@0.9.2) + '@metaplex-foundation/mpl-toolbox': + specifier: ^0.9.4 + version: 0.9.4(@metaplex-foundation/umi@0.9.2) '@metaplex-foundation/umi': specifier: ^0.9.2 version: 0.9.2 @@ -53,6 +56,9 @@ importers: '@orca-so/whirlpools-sdk': specifier: ^0.13.12 version: 0.13.12(@coral-xyz/anchor@0.29.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@orca-so/common-sdk@0.6.4(@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))(@solana/web3.js@1.98.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(decimal.js@10.4.3))(@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))(@solana/web3.js@1.98.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(decimal.js@10.4.3) + '@pythnetwork/price-service-client': + specifier: ^1.9.0 + version: 1.9.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) '@raydium-io/raydium-sdk-v2': specifier: 0.1.95-alpha version: 0.1.95-alpha(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) @@ -316,6 +322,13 @@ packages: '@solana/web3.js': ^1.90.0 decimal.js: ^10.4.3 + '@pythnetwork/price-service-client@1.9.0': + resolution: {integrity: sha512-SLm3IFcfmy9iMqHeT4Ih6qMNZhJEefY14T9yTlpsH2D/FE5+BaGGnfcexUifVlfH6M7mwRC4hEFdNvZ6ebZjJg==} + deprecated: This package is deprecated and is no longer maintained. Please use @pythnetwork/hermes-client instead. + + '@pythnetwork/price-service-sdk@1.8.0': + resolution: {integrity: sha512-tFZ1thj3Zja06DzPIX2dEWSi7kIfIyqreoywvw5NQ3Z1pl5OJHQGMEhxt6Li3UCGSp2ooYZS9wl8/8XfrfrNSA==} + '@raydium-io/raydium-sdk-v2@0.1.95-alpha': resolution: {integrity: sha512-+u7yxo/R1JDysTCzOuAlh90ioBe2DlM2Hbcz/tFsxP/YzmnYQzShvNjcmc0361a4zJhmlrEJfpFXW0J3kkX5vA==} @@ -592,6 +605,9 @@ packages: asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + axios-retry@3.9.1: + resolution: {integrity: sha512-8PJDLJv7qTTMMwdnbMvrLYuvB47M81wRtxQmEdV5w4rgbTXTt+vtPkXwajOfOdSyv/wZICJOC+/UhXH4aQ/R+w==} + axios@1.7.9: resolution: {integrity: sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==} @@ -826,6 +842,10 @@ packages: resolution: {integrity: sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==} engines: {node: '>= 10'} + is-retry-allowed@2.2.0: + resolution: {integrity: sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg==} + engines: {node: '>=10'} + isomorphic-ws@4.0.1: resolution: {integrity: sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==} peerDependencies: @@ -1126,6 +1146,9 @@ packages: trim-lines@3.0.1: resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + ts-log@2.2.7: + resolution: {integrity: sha512-320x5Ggei84AxzlXp91QkIGSw5wgaLT6GeAH0KsqDmRZdVWW2OiSeVvElVoatk3f7nicwXlElXsoFkARiGE2yg==} + ts-node@10.9.2: resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} hasBin: true @@ -1576,6 +1599,24 @@ snapshots: decimal.js: 10.4.3 tiny-invariant: 1.3.3 + '@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.8)(utf-8-validate@5.0.10)) + ts-log: 2.2.7 + ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) + transitivePeerDependencies: + - bufferutil + - debug + - utf-8-validate + + '@pythnetwork/price-service-sdk@1.8.0': + dependencies: + bn.js: 5.2.1 + '@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 @@ -2016,6 +2057,11 @@ snapshots: asynckit@0.4.0: {} + axios-retry@3.9.1: + dependencies: + '@babel/runtime': 7.26.0 + is-retry-allowed: 2.2.0 + axios@1.7.9: dependencies: follow-redirects: 1.15.9 @@ -2235,10 +2281,16 @@ snapshots: ipaddr.js@2.2.0: {} + is-retry-allowed@2.2.0: {} + 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.8)(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.8)(utf-8-validate@5.0.10) + jayson@4.1.3(bufferutil@4.0.8)(utf-8-validate@5.0.10): dependencies: '@types/connect': 3.4.38 @@ -2522,6 +2574,8 @@ snapshots: trim-lines@3.0.1: {} + ts-log@2.2.7: {} + ts-node@10.9.2(@types/node@22.10.2)(typescript@5.7.2): dependencies: '@cspotcode/source-map-support': 0.8.1 From 761299e4f22979be341723472e938d2aec444af9 Mon Sep 17 00:00:00 2001 From: Zhe <106411133+zhe-t@users.noreply.github.com> Date: Sun, 22 Dec 2024 19:27:49 +0000 Subject: [PATCH 03/17] feat: add fetch price from pyth tool --- src/tools/index.ts | 7 ++--- src/tools/pyth_fetch_price.ts | 48 +++++++++++++++++++++++++++++++++++ src/types/index.ts | 8 ++++++ 3 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 src/tools/pyth_fetch_price.ts diff --git a/src/tools/index.ts b/src/tools/index.ts index 303cde2..eee0471 100644 --- a/src/tools/index.ts +++ b/src/tools/index.ts @@ -15,8 +15,9 @@ export * from "./get_token_data"; export * from "./stake_with_jup"; export * from "./fetch_price"; export * from "./send_compressed_airdrop"; - -export * from "./create_orca_single_sided_whirlpool";export * from "./raydium_create_ammV4"; +export * from "./create_orca_single_sided_whirlpool"; +export * from "./raydium_create_ammV4"; export * from "./raydium_create_clmm"; export * from "./raydium_create_cpmm"; -export * from "./openbook_create_market"; \ No newline at end of file +export * from "./openbook_create_market"; +export * from "./pyth_fetch_price"; \ No newline at end of file diff --git a/src/tools/pyth_fetch_price.ts b/src/tools/pyth_fetch_price.ts new file mode 100644 index 0000000..5ff7317 --- /dev/null +++ b/src/tools/pyth_fetch_price.ts @@ -0,0 +1,48 @@ +import { PublicKey } from "@solana/web3.js"; +import { SolanaAgentKit } from "../index"; +import { Tool } from "langchain/tools"; +import { PriceServiceConnection } from "@pythnetwork/price-service-client"; +import BN from "bn.js"; + +/** + * Fetch the price of a given price feed from Pyth + * @param agent SolanaAgentKit instance + * @param priceFeedID Price feed ID + * @returns Latest price value from feed + * + * You can find priceFeedIDs here: https://www.pyth.network/developers/price-feed-ids#stable + */ +export async function pythFetchPrice( + agent: SolanaAgentKit, + priceFeedID: string +) { + // get Hermes service URL from https://docs.pyth.network/price-feeds/api-instances-and-providers/hermes + const stableHermesServiceUrl: string = "https://hermes.pyth.network"; + const connection = new PriceServiceConnection(stableHermesServiceUrl); + const feeds = [priceFeedID]; + + try { + const currentPrice = await connection.getLatestPriceFeeds(feeds); + + if (currentPrice === undefined) { + throw new Error("Price data not available for the given token."); + } + + if (currentPrice.length === 0) { + throw new Error("Price data not available for the given token."); + } + + // get price and exponent from price feed + let price = new BN(currentPrice[0].getPriceUnchecked().price); + let exponent = new BN(currentPrice[0].getPriceUnchecked().expo); + + // convert to scaled price + let scaledPrice = price.div(new BN(10).pow(exponent)); + + return scaledPrice.toString(); + } catch (error: any) { + throw new Error(`Fetching price from Pyth failed: ${error.message}`); + } +} + + diff --git a/src/types/index.ts b/src/types/index.ts index 28d64cb..6c9dc16 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -77,3 +77,11 @@ export interface FetchPriceResponse { message?: string; code?: string; } + +export interface PythFetchPriceResponse { + status: "success" | "error"; + priceFeedID: string; + price?: string; + message?: string; + code?: string; +} From c675e18648937563c94fe947eec64072592d57d9 Mon Sep 17 00:00:00 2001 From: Zhe <106411133+zhe-t@users.noreply.github.com> Date: Sun, 22 Dec 2024 19:28:49 +0000 Subject: [PATCH 04/17] feat: add tool implementation --- src/agent/index.ts | 7 ++++++- src/langchain/index.ts | 36 +++++++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/agent/index.ts b/src/agent/index.ts index 721e464..6b79575 100644 --- a/src/agent/index.ts +++ b/src/agent/index.ts @@ -25,7 +25,8 @@ import { stakeWithJup, sendCompressedAirdrop, createOrcaSingleSidedWhirlpool, - FEE_TIERS + FEE_TIERS, + pythFetchPrice } from "../tools"; import { CollectionOptions, PumpFunTokenOptions } from "../types"; import { BN } from "@coral-xyz/anchor"; @@ -270,4 +271,8 @@ export class SolanaAgentKit { tickSize, ) } + + async pythFetchPrice(priceFeedID: string) { + return pythFetchPrice(this, priceFeedID); + } } diff --git a/src/langchain/index.ts b/src/langchain/index.ts index 930b0bf..afb214f 100644 --- a/src/langchain/index.ts +++ b/src/langchain/index.ts @@ -1,7 +1,7 @@ import { PublicKey } from "@solana/web3.js"; import Decimal from "decimal.js"; import { Tool } from "langchain/tools"; -import { SolanaAgentKit } from "../index"; +import { PythFetchPriceResponse, SolanaAgentKit } from "../index"; import { create_image } from "../tools/create_image"; import { fetchPrice } from "../tools/fetch_price"; import { BN } from "@coral-xyz/anchor"; @@ -980,6 +980,38 @@ export class SolanaOpenbookCreateMarket extends Tool { } } +export class SolanaPythFetchPrice extends Tool { + name = "solana_pyth_fetch_price"; + description = `Fetch the price of a given price feed from Pyth's Hermes service + + Inputs: + priceFeedID: string, the price feed ID, e.g., "0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43" for BTC/USD`; + + constructor(private solanaKit: SolanaAgentKit) { + super(); + } + + async _call(input: string): Promise { + try { + const price = await this.solanaKit.pythFetchPrice(input); + let response: PythFetchPriceResponse = { + status: "success", + priceFeedID: input, + price: price, + }; + return JSON.stringify(response); + } catch (error: any) { + let response: PythFetchPriceResponse = { + status: "error", + priceFeedID: input, + message: error.message, + code: error.code || "UNKNOWN_ERROR", + }; + return JSON.stringify(response); + } + } +} + export function createSolanaTools(solanaKit: SolanaAgentKit) { return [ new SolanaBalanceTool(solanaKit), @@ -1007,5 +1039,7 @@ export function createSolanaTools(solanaKit: SolanaAgentKit) { new SolanaRaydiumCreateCpmm(solanaKit), new SolanaOpenbookCreateMarket(solanaKit), new SolanaCreateSingleSidedWhirlpoolTool(solanaKit), + new SolanaPythFetchPrice(solanaKit), ]; } + From 6dc0478e2c21752ce9918e1487ccd0f640fb1764 Mon Sep 17 00:00:00 2001 From: Zhe <106411133+zhe-t@users.noreply.github.com> Date: Sun, 22 Dec 2024 19:29:11 +0000 Subject: [PATCH 05/17] feat: add pyth example to readme --- README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/README.md b/README.md index 98708ec..4d85a43 100644 --- a/README.md +++ b/README.md @@ -207,6 +207,19 @@ import { PublicKey } from "@solana/web3.js"; })(); ``` +### Fetch Price Data from Pyth + +```typescript +import { pythFetchPrice } from "solana-agent-kit"; + +const price = await pythFetchPrice( + agent, + "0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43" +); + +console.log("Price in BTC/USD:", price); +``` + ## API Reference ### Core Functions @@ -247,6 +260,10 @@ Stake SOL with Jupiter to earn rewards. Send an SPL token airdrop to many recipients at low cost via ZK Compression. +#### `pythFetchPrice(agent, priceFeedID)` + +Fetch price data from Pyth's Hermes service. + ## Dependencies The toolkit relies on several key Solana and Metaplex libraries: @@ -258,6 +275,7 @@ The toolkit relies on several key Solana and Metaplex libraries: - @metaplex-foundation/umi - @lightprotocol/compressed-token - @lightprotocol/stateless.js +- @pythnetwork/price-service-client ## Contributing From c11b3b4596d477fae43a9372d0bbb7fe7fd7faf1 Mon Sep 17 00:00:00 2001 From: Zhe <106411133+zhe-t@users.noreply.github.com> Date: Sun, 22 Dec 2024 19:29:31 +0000 Subject: [PATCH 06/17] chore: fix add your own tool docs --- guides/add_your_own_tool.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/guides/add_your_own_tool.md b/guides/add_your_own_tool.md index 63d1172..803198c 100644 --- a/guides/add_your_own_tool.md +++ b/guides/add_your_own_tool.md @@ -19,7 +19,7 @@ Create a new TypeScript file in the `src/tools/` directory for your tool (e.g., ### 2. Implement the Tool Class -```typescript:src/tools/custom_tool.ts +```typescript:src/langchain/index.ts import { Tool } from "langchain/tools"; import { SolanaAgentKit } from "../agent"; @@ -86,6 +86,8 @@ export function createSolanaTools(agent: SolanaAgentKit) { ### 6. Usage Example +Add a code example in the `README.md` file. + ```typescript import { SolanaAgentKit, createSolanaTools } from "solana-agent-kit"; From 373a1ed9714add694aa03a7295ab4c883c7d2f85 Mon Sep 17 00:00:00 2001 From: metasal <54984459+metasal1@users.noreply.github.com> Date: Mon, 23 Dec 2024 15:27:12 +1100 Subject: [PATCH 07/17] Update index.ts with new url https://www.solanaagentkit.xyz --- test/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/index.ts b/test/index.ts index 9522c23..00faade 100644 --- a/test/index.ts +++ b/test/index.ts @@ -70,7 +70,7 @@ async function initializeAgent() { faucet. If not, you can provide your wallet details and request funds from the user. If there is a 5XX (internal) HTTP error code, ask the user to try again later. If someone asks you to do something you can't do with your currently available tools, you must say so, and encourage them to implement it - themselves using the Solana Agent Kit, recommend they go to https://sendai.fun/kit for more information. Be + themselves using the Solana Agent Kit, recommend they go to https://www.solanaagentkit.xyz for more information. Be concise and helpful with your responses. Refrain from restating your tools' descriptions unless it is explicitly requested. `, From 0ff6d261f54b05cc6d1643c82fca50264e683894 Mon Sep 17 00:00:00 2001 From: aryan Date: Mon, 23 Dec 2024 11:16:09 +0530 Subject: [PATCH 08/17] chore --- pnpm-lock.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7aa38c3..4b61c9e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -38,6 +38,9 @@ importers: '@metaplex-foundation/mpl-token-metadata': specifier: ^3.3.0 version: 3.3.0(@metaplex-foundation/umi@0.9.2) + '@metaplex-foundation/mpl-toolbox': + specifier: ^0.9.4 + version: 0.9.4(@metaplex-foundation/umi@0.9.2) '@metaplex-foundation/umi': specifier: ^0.9.2 version: 0.9.2 From c82f59533b87175f5560e77b61dd14c1dcd0daf4 Mon Sep 17 00:00:00 2001 From: aryan Date: Mon, 23 Dec 2024 11:29:11 +0530 Subject: [PATCH 09/17] fix: type for get_balance --- src/agent/index.ts | 2 +- src/tools/get_balance.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/agent/index.ts b/src/agent/index.ts index 90e47ef..d8086b8 100644 --- a/src/agent/index.ts +++ b/src/agent/index.ts @@ -84,7 +84,7 @@ export class SolanaAgentKit { return deploy_collection(this, options); } - async getBalance(token_address?: PublicKey): Promise { + async getBalance(token_address?: PublicKey): Promise { return get_balance(this, token_address); } diff --git a/src/tools/get_balance.ts b/src/tools/get_balance.ts index 36cdfef..05a56a1 100644 --- a/src/tools/get_balance.ts +++ b/src/tools/get_balance.ts @@ -10,7 +10,7 @@ import { SolanaAgentKit } from "../index"; export async function get_balance( agent: SolanaAgentKit, token_address?: PublicKey, -): Promise { +): Promise { if (!token_address) return ( (await agent.connection.getBalance(agent.wallet_address)) / @@ -19,5 +19,5 @@ export async function get_balance( const token_account = await agent.connection.getTokenAccountBalance(token_address); - return token_account.value.uiAmount; + return token_account.value.uiAmount || 0; } From fbd6ac600226dbe5435c4dd76a3d8322ac855952 Mon Sep 17 00:00:00 2001 From: adpthegreat Date: Fri, 20 Dec 2024 19:25:30 +0100 Subject: [PATCH 10/17] added domain methods --- src/tools/get_all_active_tlds.ts | 0 src/tools/get_all_registered_all_domains.ts | 0 src/tools/get_domains_on_tld.ts | 23 +++++++++++ src/tools/get_main_domain.ts | 21 +++++++++++ src/tools/lookup_owner.ts | 21 +++++++++++ src/tools/resolve_domain.ts | 42 +++++++++++++++++++++ 6 files changed, 107 insertions(+) create mode 100644 src/tools/get_all_active_tlds.ts create mode 100644 src/tools/get_all_registered_all_domains.ts create mode 100644 src/tools/get_domains_on_tld.ts create mode 100644 src/tools/get_main_domain.ts create mode 100644 src/tools/lookup_owner.ts create mode 100644 src/tools/resolve_domain.ts diff --git a/src/tools/get_all_active_tlds.ts b/src/tools/get_all_active_tlds.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/tools/get_all_registered_all_domains.ts b/src/tools/get_all_registered_all_domains.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/tools/get_domains_on_tld.ts b/src/tools/get_domains_on_tld.ts new file mode 100644 index 0000000..045f44a --- /dev/null +++ b/src/tools/get_domains_on_tld.ts @@ -0,0 +1,23 @@ +import { SolanaAgentKit } from "../agent"; +import { getOwnedAllDomains } from "./lookup_owner"; +import { PublicKey } from "@solana/web3.js"; + +/** + * Get all domains owned by an address for a specific TLD + * @param agent SolanaAgentKit instance + * @param owner Owner's public key + * @param tld Top-level domain (e.g., "sol") + * @returns Array of owned domain names for the specified TLD + */ +export async function getOwnedDomainsForTLD( + agent: SolanaAgentKit, + owner: PublicKey, + tld: string +): Promise { + try { + const allDomains = await getOwnedAllDomains(agent, owner); + return allDomains.filter(domain => domain.endsWith(`.${tld}`)); + } catch (error: any) { + throw new Error(`Failed to fetch domains for TLD: ${error.message}`); + } +} diff --git a/src/tools/get_main_domain.ts b/src/tools/get_main_domain.ts new file mode 100644 index 0000000..775c343 --- /dev/null +++ b/src/tools/get_main_domain.ts @@ -0,0 +1,21 @@ +import { getFavoriteDomain as _getFavoriteDomain } from "@bonfida/spl-name-service"; +import { PublicKey } from "@solana/web3.js"; + + +/** + * Get the user's main/favorite domain for a SolanaAgentKit instance + * @param agent SolanaAgentKit instance + * @param owner Owner's public key + * @returns Promise resolving to the main domain name or null if not set + */ +export async function getMainAllDomainsDomain( + agent: any, + owner: PublicKey +): Promise { + try { + const favDomain = await _getFavoriteDomain(agent.connection, owner); + return favDomain.stale ? null : favDomain.reverse; + } catch (error: any) { + throw new Error(`Failed to fetch main domain: ${error.message}`); + } +} \ No newline at end of file diff --git a/src/tools/lookup_owner.ts b/src/tools/lookup_owner.ts new file mode 100644 index 0000000..9243467 --- /dev/null +++ b/src/tools/lookup_owner.ts @@ -0,0 +1,21 @@ +import { getAllDomains } from "@bonfida/spl-name-service"; +import { SolanaAgentKit } from "../agent"; +import { PublicKey } from "@solana/web3.js"; + +/** + * Get all domains owned by a specific address + * @param agent SolanaAgentKit instance + * @param owner Owner's public key + * @returns Array of owned domain names + */ +export async function getOwnedAllDomains( + agent: SolanaAgentKit, + owner: PublicKey +): Promise { + try { + const domains = await getAllDomains(agent.connection, owner); + return domains.map(domain => domain.name); + } catch (error: any) { + throw new Error(`Failed to fetch owned domains: ${error.message}`); + } +} diff --git a/src/tools/resolve_domain.ts b/src/tools/resolve_domain.ts new file mode 100644 index 0000000..3ea5e41 --- /dev/null +++ b/src/tools/resolve_domain.ts @@ -0,0 +1,42 @@ +import { Buffer } from "buffer"; +import { PublicKey } from "@solana/web3.js"; +import { + getNameAccountKeySync, + NAME_PROGRAM_ID, +} from "@bonfida/spl-name-service"; +import { SolanaAgentKit } from "../index"; + +/** + * Resolve a domain to its public key + * @param agent SolanaAgentKit instance + * @param domain Domain name to resolve + * @returns Associated public key or null if not found + */ +export async function resolveAllDomains( + agent: SolanaAgentKit, + domain: string +): Promise { + try { + // Convert domain name to buffer for hashing + const hashedDomain = Buffer.from(domain); + + // Get the name account key using the new sync method + const nameAccountKey = getNameAccountKeySync( + hashedDomain, + undefined, // nameClass + undefined // nameParent + ); + + // Get the account info to retrieve the owner + const owner = await agent.connection.getAccountInfo(nameAccountKey); + + if (!owner) { + return null; + } + + // The owner's public key is stored in the data buffer starting at offset 32 + return new PublicKey(owner.data.slice(32, 64)); + } catch (error: any) { + throw new Error(`Domain resolution failed: ${error.message}`); + } +} From 9e1fa3fae054831013c8d8bc2b06bafd22e95b7c Mon Sep 17 00:00:00 2001 From: adpthegreat Date: Fri, 20 Dec 2024 19:35:13 +0100 Subject: [PATCH 11/17] modified package lock --- package-lock.json | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 package-lock.json diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..e69de29 From 1fc965c0174c0a87e1f2444fccd29c2643825700 Mon Sep 17 00:00:00 2001 From: adpthegreat Date: Fri, 20 Dec 2024 20:12:16 +0100 Subject: [PATCH 12/17] feat:updated domains methods, added fixes --- src/tools/get_all_active_tlds.ts | 65 +++++++++++++++++++++ src/tools/get_all_registered_all_domains.ts | 36 ++++++++++++ src/tools/lookup_owner.ts | 2 +- 3 files changed, 102 insertions(+), 1 deletion(-) diff --git a/src/tools/get_all_active_tlds.ts b/src/tools/get_all_active_tlds.ts index e69de29..929fbfc 100644 --- a/src/tools/get_all_active_tlds.ts +++ b/src/tools/get_all_active_tlds.ts @@ -0,0 +1,65 @@ +import { + NameRegistryState, + getAllDomains, + ROOT_DOMAIN_ACCOUNT, +} from "@bonfida/spl-name-service"; +import { Connection, PublicKey } from "@solana/web3.js"; +import { SolanaAgentKit } from "../index"; + +/** + * Get all active top-level domains (TLDs) in the Solana name service + * @param agent SolanaAgentKit instance + * @returns Array of active TLD strings + */ +export async function getAllDomainsTLDs( + agent: SolanaAgentKit +): Promise { + try { + // Get the root domain record + const rootAccount = await NameRegistryState.retrieve( + agent.connection, + ROOT_DOMAIN_ACCOUNT + ); + + if (!rootAccount) { + throw new Error("Root domain account not found"); + } + + // Fetch all TLD records under the root domain + const tldAccounts = await agent.connection.getProgramAccounts( + new PublicKey("namesLPneVptA9Z5rqUDD9tMTWEJwofgaYwp8cawRkX"), + { + filters: [ + { + memcmp: { + offset: 0, + bytes: rootAccount.registry.owner.toBase58(), + }, + }, + ], + } + ); + + // Parse the TLD names from the accounts + const tlds: string[] = []; + for (const account of tldAccounts) { + const registry = await NameRegistryState.retrieve( + agent.connection, + account.pubkey + ); + + if (registry && registry.registry.data) { + const tldName = Buffer.from(registry.registry.data) + .toString() + .replace(/\0/g, ""); + if (tldName) { + tlds.push(tldName); + } + } + } + + return tlds; + } catch (error: any) { + throw new Error(`Failed to fetch TLDs: ${error.message}`); + } +} diff --git a/src/tools/get_all_registered_all_domains.ts b/src/tools/get_all_registered_all_domains.ts index e69de29..dc0f0a4 100644 --- a/src/tools/get_all_registered_all_domains.ts +++ b/src/tools/get_all_registered_all_domains.ts @@ -0,0 +1,36 @@ +import { getAllDomains } from "@bonfida/spl-name-service"; +import { SolanaAgentKit } from "../agent"; +import { PublicKey } from "@solana/web3.js"; +import { getAllDomainsTLDs } from "./get_all_active_tlds"; + +/** + * Get all registered domains across all TLDs + * @param agent SolanaAgentKit instance + * @returns Array of all registered domain names with their TLDs + */ +export async function getAllRegisteredAllDomains( + agent: SolanaAgentKit +): Promise { + try { + // First get all TLDs + const tlds = await getAllDomainsTLDs(agent); + const allDomains: string[] = []; + + // For each TLD, fetch all registered domains + for (const tld of tlds) { + const domains = await getAllDomains( + agent.connection, + new PublicKey("namesLPneVptA9Z5rqUDD9tMTWEJwofgaYwp8cawRkX"), + ); + + // Add domains with TLD suffix + domains.forEach((domain) => { + allDomains.push(`${domain}.${tld}`); + }); + } + + return allDomains; + } catch (error: any) { + throw new Error(`Failed to fetch all registered domains: ${error.message}`); + } +} diff --git a/src/tools/lookup_owner.ts b/src/tools/lookup_owner.ts index 9243467..cffd264 100644 --- a/src/tools/lookup_owner.ts +++ b/src/tools/lookup_owner.ts @@ -14,7 +14,7 @@ export async function getOwnedAllDomains( ): Promise { try { const domains = await getAllDomains(agent.connection, owner); - return domains.map(domain => domain.name); + return domains.map(domain => domain.toString()); } catch (error: any) { throw new Error(`Failed to fetch owned domains: ${error.message}`); } From b12b2a61d4cfec19b1481258d0e2866b1eab9832 Mon Sep 17 00:00:00 2001 From: adpthegreat Date: Fri, 20 Dec 2024 20:22:34 +0100 Subject: [PATCH 13/17] feat : added domain methods to solana agent kit --- src/agent/index.ts | 40 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/src/agent/index.ts b/src/agent/index.ts index 56cfe74..c5dca61 100644 --- a/src/agent/index.ts +++ b/src/agent/index.ts @@ -37,6 +37,12 @@ import { PumpFunTokenOptions, } from "../types"; import { BN } from "@coral-xyz/anchor"; +import { getAllDomainsTLDs } from "../tools/get_all_active_tlds"; +import { getAllRegisteredAllDomains } from "../tools/get_all_registered_all_domains"; +import { getOwnedDomainsForTLD } from "../tools/get_domains_on_tld"; +import { getMainAllDomainsDomain } from "../tools/get_main_domain"; +import { getOwnedAllDomains } from "../tools/lookup_owner"; +import { resolveAllDomains } from "../tools/resolve_domain"; /** * Main class for interacting with Solana blockchain @@ -192,8 +198,8 @@ export class SolanaAgentKit { otherTokenMint: PublicKey, initialPrice: Decimal, maxPrice: Decimal, - feeTier: keyof typeof FEE_TIERS, - ): Promise { + feeTier: keyof typeof FEE_TIERS + ) { return createOrcaSingleSidedWhirlpool( this, depositTokenAmount, @@ -201,10 +207,38 @@ export class SolanaAgentKit { otherTokenMint, initialPrice, maxPrice, - feeTier, + feeTier ); } + // New domain-related methods + async resolveAllDomains(domain: string): Promise { + return resolveAllDomains(this, domain); + } + + async getOwnedAllDomains(owner: PublicKey): Promise { + return getOwnedAllDomains(this, owner); + } + + async getOwnedDomainsForTLD( + owner: PublicKey, + tld: string + ): Promise { + return getOwnedDomainsForTLD(this, owner, tld); + } + + async getAllDomainsTLDs(): Promise { + return getAllDomainsTLDs(this); + } + + async getAllRegisteredAllDomains(): Promise { + return getAllRegisteredAllDomains(this); + } + + async getMainAllDomainsDomain(owner: PublicKey): Promise { + return getMainAllDomainsDomain(this, owner); + } + async raydiumCreateAmmV4( marketId: PublicKey, baseAmount: BN, From e2239a5029c04b76613c03eae8039e3302a24076 Mon Sep 17 00:00:00 2001 From: adpthegreat Date: Fri, 20 Dec 2024 21:03:58 +0100 Subject: [PATCH 14/17] feat:removed package-lock update pnpm lock, modified agent/index.ts --- src/agent/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/agent/index.ts b/src/agent/index.ts index c5dca61..5d63b9e 100644 --- a/src/agent/index.ts +++ b/src/agent/index.ts @@ -211,7 +211,6 @@ export class SolanaAgentKit { ); } - // New domain-related methods async resolveAllDomains(domain: string): Promise { return resolveAllDomains(this, domain); } From 93ceb6732804526079b3108411f705c60e6369f7 Mon Sep 17 00:00:00 2001 From: adpthegreat Date: Fri, 20 Dec 2024 21:12:33 +0100 Subject: [PATCH 15/17] updated imports for methods --- src/agent/index.ts | 12 ++++++------ src/tools/index.ts | 8 +++++++- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/agent/index.ts b/src/agent/index.ts index 5d63b9e..344c47a 100644 --- a/src/agent/index.ts +++ b/src/agent/index.ts @@ -27,6 +27,12 @@ import { createOrcaSingleSidedWhirlpool, FEE_TIERS, pythFetchPrice, + getAllDomainsTLDs, + getAllRegisteredAllDomains, + getOwnedDomainsForTLD, + getMainAllDomainsDomain, + getOwnedAllDomains, + resolveAllDomains, } from "../tools"; import { CollectionDeployment, @@ -37,12 +43,6 @@ import { PumpFunTokenOptions, } from "../types"; import { BN } from "@coral-xyz/anchor"; -import { getAllDomainsTLDs } from "../tools/get_all_active_tlds"; -import { getAllRegisteredAllDomains } from "../tools/get_all_registered_all_domains"; -import { getOwnedDomainsForTLD } from "../tools/get_domains_on_tld"; -import { getMainAllDomainsDomain } from "../tools/get_main_domain"; -import { getOwnedAllDomains } from "../tools/lookup_owner"; -import { resolveAllDomains } from "../tools/resolve_domain"; /** * Main class for interacting with Solana blockchain diff --git a/src/tools/index.ts b/src/tools/index.ts index eee0471..a82b52a 100644 --- a/src/tools/index.ts +++ b/src/tools/index.ts @@ -16,7 +16,13 @@ export * from "./stake_with_jup"; export * from "./fetch_price"; export * from "./send_compressed_airdrop"; export * from "./create_orca_single_sided_whirlpool"; -export * from "./raydium_create_ammV4"; + +export * from "../tools/get_all_active_tlds"; +export * from "../tools/get_all_registered_all_domains"; +export * from "../tools/get_domains_on_tld"; +export * from "../tools/get_main_domain"; +export * from "../tools/lookup_owner"; +export * from "../tools/resolve_domain";export * from "./raydium_create_ammV4"; export * from "./raydium_create_clmm"; export * from "./raydium_create_cpmm"; export * from "./openbook_create_market"; From b1fcd6b56e2691f2a75680347dd8cb87aa9c3412 Mon Sep 17 00:00:00 2001 From: adpthegreat Date: Fri, 20 Dec 2024 21:26:06 +0100 Subject: [PATCH 16/17] feat: update imports in index.ts --- src/tools/index.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/tools/index.ts b/src/tools/index.ts index a82b52a..85e338a 100644 --- a/src/tools/index.ts +++ b/src/tools/index.ts @@ -16,13 +16,14 @@ export * from "./stake_with_jup"; export * from "./fetch_price"; export * from "./send_compressed_airdrop"; export * from "./create_orca_single_sided_whirlpool"; +export * from "./get_all_active_tlds"; +export * from "./get_all_registered_all_domains"; +export * from "./get_domains_on_tld"; +export * from "./get_main_domain"; +export * from "./lookup_owner"; +export * from "./resolve_domain"; -export * from "../tools/get_all_active_tlds"; -export * from "../tools/get_all_registered_all_domains"; -export * from "../tools/get_domains_on_tld"; -export * from "../tools/get_main_domain"; -export * from "../tools/lookup_owner"; -export * from "../tools/resolve_domain";export * from "./raydium_create_ammV4"; +export * from "./raydium_create_ammV4"; export * from "./raydium_create_clmm"; export * from "./raydium_create_cpmm"; export * from "./openbook_create_market"; From cfda7151a28a7fb2446315094df8e80f5269a386 Mon Sep 17 00:00:00 2001 From: adpthegreat Date: Sat, 21 Dec 2024 20:53:00 +0100 Subject: [PATCH 17/17] feat: added langchain class, refactored methods to use tlb parser, wrote and ran tests --- package-lock.json | 0 package.json | 5 +- pnpm-lock.yaml | 428 ++++++++++++++++++ src/agent/index.ts | 32 +- src/langchain/index.ts | 6 + src/tools/get_all_active_tlds.ts | 65 --- src/tools/get_all_domains_tlds.ts | 21 + src/tools/get_all_registered_all_domains.ts | 4 +- ...main.ts => get_main_all_domains_domain.ts} | 13 +- src/tools/get_owned_all_domains.ts | 20 + ...on_tld.ts => get_owned_domains_for_tld.ts} | 18 +- src/tools/index.ts | 8 +- src/tools/lookup_owner.ts | 21 - src/tools/resolve_domain.ts | 36 +- test/domain_methods.test.ts | 146 ++++++ 15 files changed, 676 insertions(+), 147 deletions(-) delete mode 100644 package-lock.json delete mode 100644 src/tools/get_all_active_tlds.ts create mode 100644 src/tools/get_all_domains_tlds.ts rename src/tools/{get_main_domain.ts => get_main_all_domains_domain.ts} (68%) create mode 100644 src/tools/get_owned_all_domains.ts rename src/tools/{get_domains_on_tld.ts => get_owned_domains_for_tld.ts} (54%) delete mode 100644 src/tools/lookup_owner.ts create mode 100644 test/domain_methods.test.ts diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index e69de29..0000000 diff --git a/package.json b/package.json index 790b80c..cd4008d 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "scripts": { "build": "tsc", "docs": "typedoc src --out docs", - "test": "ts-node test/index.ts", + "test": "ts-node test/**/*.ts", "generate": "ts-node src/utils/keypair.ts" }, "engines": { @@ -32,6 +32,7 @@ "@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/price-service-client": "^1.9.0", @@ -40,6 +41,7 @@ "@solana/web3.js": "^1.95.4", "bn.js": "^5.2.1", "bs58": "^6.0.0", + "chai": "^5.1.2", "decimal.js": "^10.4.3", "dotenv": "^16.4.5", "form-data": "^4.0.1", @@ -49,6 +51,7 @@ }, "devDependencies": { "@types/bn.js": "^5.1.5", + "@types/chai": "^5.0.1", "@types/node": "^22.9.0", "ts-node": "^10.9.2", "typescript": "^5.7.2" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 289b940..d4d7572 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -50,6 +50,9 @@ importers: '@metaplex-foundation/umi-web3js-adapters': specifier: ^0.9.2 version: 0.9.2(@metaplex-foundation/umi@0.9.2)(@solana/web3.js@1.98.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)) + '@onsol/tldparser': + specifier: ^0.6.7 + version: 0.6.7(@solana/web3.js@1.98.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bn.js@5.2.1)(borsh@2.0.0)(buffer@6.0.3)(bufferutil@4.0.8)(utf-8-validate@5.0.10) '@orca-so/common-sdk': specifier: 0.6.4 version: 0.6.4(@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))(@solana/web3.js@1.98.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(decimal.js@10.4.3) @@ -74,6 +77,9 @@ importers: bs58: specifier: ^6.0.0 version: 6.0.0 + chai: + specifier: ^5.1.2 + version: 5.1.2 decimal.js: specifier: ^10.4.3 version: 10.4.3 @@ -96,6 +102,9 @@ importers: '@types/bn.js': specifier: ^5.1.5 version: 5.1.6 + '@types/chai': + specifier: ^5.0.1 + version: 5.0.1 '@types/node': specifier: ^22.9.0 version: 22.10.2 @@ -139,6 +148,15 @@ packages: resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} + '@ethersproject/bytes@5.7.0': + resolution: {integrity: sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==} + + '@ethersproject/logger@5.7.0': + resolution: {integrity: sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==} + + '@ethersproject/sha2@5.7.0': + resolution: {integrity: sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==} + '@jridgewell/resolve-uri@3.1.2': resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} @@ -194,6 +212,12 @@ packages: '@lightprotocol/stateless.js@0.17.1': resolution: {integrity: sha512-EjId1n33A6dBwpce33Wsa/fs/CDKtMtRrkxbApH0alXrnEXmbW6QhIViXOrKYXjZ4uJQM1xsBtsKe0vqJ4nbtQ==} + '@metaplex-foundation/beet-solana@0.4.1': + resolution: {integrity: sha512-/6o32FNUtwK8tjhotrvU/vorP7umBuRFvBZrC6XCk51aKidBHe5LPVPA5AjGPbV3oftMfRuXPNd9yAGeEqeCDQ==} + + '@metaplex-foundation/beet@0.7.2': + resolution: {integrity: sha512-K+g3WhyFxKPc0xIvcIjNyV1eaTVJTiuaHZpig7Xx0MuYRMoJLLvhLTnUXhFdR5Tu2l2QSyKwfyXDgZlzhULqFg==} + '@metaplex-foundation/mpl-core@1.1.1': resolution: {integrity: sha512-h1kLw+cGaV8SiykoHDb1/G01+VYqtJXAt0uGuO5+2Towsdtc6ET4M62iqUnh4EacTVMIW1yYHsKsG/LYWBCKaA==} peerDependencies: @@ -306,6 +330,15 @@ packages: resolution: {integrity: sha512-pq5D8h10hHBjyqX+cfBm0i8JUXJ0UhczFc4r74zbuT9XgewFo2E3J1cOaGtdZynILNmQ685YWGzGE1Zv6io50w==} engines: {node: ^14.21.3 || >=16} + '@onsol/tldparser@0.6.7': + resolution: {integrity: sha512-QwkRDLyC514pxeplCCXZ2kTiRcJSeUrpp+9o2XqLbePy/qzZGGG8I0UbXUKuWVD/bUL1zAm21+D+Eu30OKwcQg==} + engines: {node: '>=14'} + peerDependencies: + '@solana/web3.js': ^1.95.3 + bn.js: ^5.2.1 + borsh: ^0.7.0 + buffer: 6.0.1 + '@orca-so/common-sdk@0.6.4': resolution: {integrity: sha512-iOiC6exTA9t2CEOaUPoWlNP3soN/1yZFjoz1mSf7NvOqo/PJZeIdWpB7BRXwU0mGGatjxU4SFgMGQ8NrSx+ONw==} peerDependencies: @@ -526,9 +559,15 @@ packages: '@types/bn.js@5.1.6': resolution: {integrity: sha512-Xh8vSwUeMKeYYrj3cX4lGQgFSF/N03r+tv4AiLl1SucqV+uTQpxRcnM8AkXKHwYP9ZPXOYXRr2KPXpVlIvqh9w==} + '@types/chai@5.0.1': + resolution: {integrity: sha512-5T8ajsg3M/FOncpLYW7sdOcD6yf4+722sze/tc4KQV0P8Z2rAr3SAuHCIkYmYpt8VbcQlnz8SxlOlPQYefe4cA==} + '@types/connect@3.4.38': resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} @@ -596,15 +635,29 @@ packages: resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} engines: {node: '>=10'} + ansicolors@0.3.2: + resolution: {integrity: sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==} + arg@4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + assert@2.1.0: + resolution: {integrity: sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==} + + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + axios-retry@3.9.1: resolution: {integrity: sha512-8PJDLJv7qTTMMwdnbMvrLYuvB47M81wRtxQmEdV5w4rgbTXTt+vtPkXwajOfOdSyv/wZICJOC+/UhXH4aQ/R+w==} @@ -674,6 +727,18 @@ packages: resolution: {integrity: sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==} engines: {node: '>=6.14.2'} + call-bind-apply-helpers@1.0.1: + resolution: {integrity: sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==} + engines: {node: '>= 0.4'} + + call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} + + call-bound@1.0.3: + resolution: {integrity: sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==} + engines: {node: '>= 0.4'} + camelcase@6.3.0: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} @@ -681,6 +746,10 @@ packages: ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + chai@5.1.2: + resolution: {integrity: sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==} + engines: {node: '>=12'} + chalk@5.4.0: resolution: {integrity: sha512-ZkD35Mx92acjB2yNJgziGqT9oKHEOxjTBTDRpOsRWtdecL/0jM3z5kM/CTzHWvHIen1GvkM85p6TuFfDGfc8/Q==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} @@ -691,6 +760,10 @@ packages: character-entities-legacy@3.0.0: resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + check-error@2.1.1: + resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} + engines: {node: '>= 16'} + combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} @@ -722,6 +795,15 @@ packages: dayjs@1.11.13: resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} + debug@4.4.0: + resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + decamelize@1.2.0: resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} engines: {node: '>=0.10.0'} @@ -732,6 +814,18 @@ packages: decimal.js@10.4.3: resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==} + deep-eql@5.0.2: + resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} + engines: {node: '>=6'} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + delay@5.0.0: resolution: {integrity: sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==} engines: {node: '>=10'} @@ -758,6 +852,10 @@ packages: resolution: {integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==} engines: {node: '>=12'} + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + emoji-regex-xs@1.0.0: resolution: {integrity: sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==} @@ -765,6 +863,18 @@ packages: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.0.0: + resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} + engines: {node: '>= 0.4'} + es6-promise@4.2.8: resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} @@ -803,6 +913,9 @@ packages: debug: optional: true + for-each@0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + form-data-encoder@1.7.2: resolution: {integrity: sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==} @@ -814,6 +927,17 @@ packages: resolution: {integrity: sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==} engines: {node: '>= 12.20'} + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + get-intrinsic@1.2.6: + resolution: {integrity: sha512-qxsEs+9A+u85HhllWJJFicJfPDhRmjzoYdl64aMWW9yRIJmSyxdn8IEkuIM530/7T+lv0TIHd8L6Q/ra0tEoeA==} + engines: {node: '>= 0.4'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} @@ -823,6 +947,24 @@ packages: groq-sdk@0.5.0: resolution: {integrity: sha512-RVmhW7qZ+XZoy5fIuSdx/LGQJONpL8MHgZEW7dFwTdgkzStub2XQx6OKv28CHogijdwH41J+Npj/z2jBPu3vmw==} + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hash.js@1.1.7: + resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + hast-util-to-html@9.0.4: resolution: {integrity: sha512-wxQzXtdbhiwGAUKrnQJXlOPmHnEehzphwkK7aluUPQ+lEc1xefC8pblMgpp2w5ldBTEfveRIrADcrhGIWrlTDA==} @@ -838,10 +980,33 @@ packages: ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + ipaddr.js@2.2.0: resolution: {integrity: sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==} engines: {node: '>= 10'} + is-arguments@1.2.0: + resolution: {integrity: sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==} + engines: {node: '>= 0.4'} + + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + + is-generator-function@1.0.10: + resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} + engines: {node: '>= 0.4'} + + is-nan@1.3.2: + resolution: {integrity: sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==} + engines: {node: '>= 0.4'} + + is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} + engines: {node: '>= 0.4'} + is-retry-allowed@2.2.0: resolution: {integrity: sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg==} engines: {node: '>=10'} @@ -945,6 +1110,9 @@ packages: lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + loupe@3.1.2: + resolution: {integrity: sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==} + lower-case@2.0.2: resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} @@ -958,6 +1126,10 @@ packages: resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==} hasBin: true + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + mdast-util-to-hast@13.2.0: resolution: {integrity: sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==} @@ -987,6 +1159,9 @@ packages: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} + minimalistic-assert@1.0.1: + resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} + minimatch@9.0.5: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} @@ -1021,6 +1196,18 @@ packages: resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} hasBin: true + object-is@1.1.6: + resolution: {integrity: sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==} + engines: {node: '>= 0.4'} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + object.assign@4.1.7: + resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} + engines: {node: '>= 0.4'} + oniguruma-to-es@0.8.0: resolution: {integrity: sha512-rY+/a6b+uCgoYIL9itjY0x99UUDHXmGaw7Jjk5ZvM/3cxDJifyxFr/Zm4tTmF6Tre18gAakJo7AzhKUeMNLgHA==} @@ -1058,6 +1245,14 @@ packages: pako@2.1.0: resolution: {integrity: sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==} + pathval@2.0.0: + resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==} + engines: {node: '>= 14.16'} + + possible-typed-array-names@1.0.0: + resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} + engines: {node: '>= 0.4'} + property-information@6.5.0: resolution: {integrity: sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==} @@ -1099,6 +1294,10 @@ packages: engines: {node: '>=10'} hasBin: true + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + shiki@1.24.3: resolution: {integrity: sha512-eMeX/ehE2IDKVs71kB4zVcDHjutNcOtm+yIRuR4sA6ThBbdFI0DffGJiyoKCodj0xRGxIoWC3pk/Anmm5mzHmA==} @@ -1220,6 +1419,9 @@ packages: resolution: {integrity: sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==} engines: {node: '>=6.14.2'} + util@0.12.5: + resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} + uuid@10.0.0: resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==} hasBin: true @@ -1255,6 +1457,10 @@ packages: whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + which-typed-array@1.1.18: + resolution: {integrity: sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA==} + engines: {node: '>= 0.4'} + ws@7.5.10: resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==} engines: {node: '>=8.3.0'} @@ -1364,6 +1570,18 @@ snapshots: dependencies: '@jridgewell/trace-mapping': 0.3.9 + '@ethersproject/bytes@5.7.0': + dependencies: + '@ethersproject/logger': 5.7.0 + + '@ethersproject/logger@5.7.0': {} + + '@ethersproject/sha2@5.7.0': + dependencies: + '@ethersproject/bytes': 5.7.0 + '@ethersproject/logger': 5.7.0 + hash.js: 1.1.7 + '@jridgewell/resolve-uri@3.1.2': {} '@jridgewell/sourcemap-codec@1.5.0': {} @@ -1463,6 +1681,27 @@ snapshots: - encoding - utf-8-validate + '@metaplex-foundation/beet-solana@0.4.1(bufferutil@4.0.8)(utf-8-validate@5.0.10)': + dependencies: + '@metaplex-foundation/beet': 0.7.2 + '@solana/web3.js': 1.98.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) + bs58: 5.0.0 + debug: 4.4.0 + transitivePeerDependencies: + - bufferutil + - encoding + - supports-color + - utf-8-validate + + '@metaplex-foundation/beet@0.7.2': + dependencies: + ansicolors: 0.3.2 + assert: 2.1.0 + bn.js: 5.2.1 + debug: 4.4.0 + transitivePeerDependencies: + - supports-color + '@metaplex-foundation/mpl-core@1.1.1(@metaplex-foundation/umi@0.9.2)(@noble/hashes@1.6.1)': dependencies: '@metaplex-foundation/umi': 0.9.2 @@ -1583,6 +1822,20 @@ snapshots: '@noble/hashes@1.6.1': {} + '@onsol/tldparser@0.6.7(@solana/web3.js@1.98.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bn.js@5.2.1)(borsh@2.0.0)(buffer@6.0.3)(bufferutil@4.0.8)(utf-8-validate@5.0.10)': + dependencies: + '@ethersproject/sha2': 5.7.0 + '@metaplex-foundation/beet-solana': 0.4.1(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.js: 5.2.1 + borsh: 2.0.0 + buffer: 6.0.3 + transitivePeerDependencies: + - bufferutil + - encoding + - supports-color + - utf-8-validate + '@orca-so/common-sdk@0.6.4(@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))(@solana/web3.js@1.98.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(decimal.js@10.4.3)': dependencies: '@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) @@ -1983,10 +2236,16 @@ snapshots: dependencies: '@types/node': 22.10.2 + '@types/chai@5.0.1': + dependencies: + '@types/deep-eql': 4.0.2 + '@types/connect@3.4.38': dependencies: '@types/node': 22.10.2 + '@types/deep-eql@4.0.2': {} + '@types/hast@3.0.4': dependencies: '@types/unist': 3.0.3 @@ -2051,12 +2310,28 @@ snapshots: ansi-styles@5.2.0: {} + ansicolors@0.3.2: {} + arg@4.1.3: {} argparse@2.0.1: {} + assert@2.1.0: + dependencies: + call-bind: 1.0.8 + is-nan: 1.3.2 + object-is: 1.1.6 + object.assign: 4.1.7 + util: 0.12.5 + + assertion-error@2.0.1: {} + asynckit@0.4.0: {} + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.0.0 + axios-retry@3.9.1: dependencies: '@babel/runtime': 7.26.0 @@ -2134,16 +2409,43 @@ snapshots: node-gyp-build: 4.8.4 optional: true + call-bind-apply-helpers@1.0.1: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bind@1.0.8: + dependencies: + call-bind-apply-helpers: 1.0.1 + es-define-property: 1.0.1 + get-intrinsic: 1.2.6 + set-function-length: 1.2.2 + + call-bound@1.0.3: + dependencies: + call-bind-apply-helpers: 1.0.1 + get-intrinsic: 1.2.6 + camelcase@6.3.0: {} ccount@2.0.1: {} + chai@5.1.2: + dependencies: + assertion-error: 2.0.1 + check-error: 2.1.1 + deep-eql: 5.0.2 + loupe: 3.1.2 + pathval: 2.0.0 + chalk@5.4.0: {} character-entities-html4@2.1.0: {} character-entities-legacy@3.0.0: {} + check-error@2.1.1: {} + combined-stream@1.0.8: dependencies: delayed-stream: 1.0.0 @@ -2168,12 +2470,30 @@ snapshots: dayjs@1.11.13: {} + debug@4.4.0: + dependencies: + ms: 2.1.3 + decamelize@1.2.0: {} decimal.js-light@2.5.1: {} decimal.js@10.4.3: {} + deep-eql@5.0.2: {} + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + delay@5.0.0: {} delayed-stream@1.0.0: {} @@ -2193,10 +2513,24 @@ snapshots: dotenv@16.4.7: {} + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + emoji-regex-xs@1.0.0: {} entities@4.5.0: {} + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-object-atoms@1.0.0: + dependencies: + es-errors: 1.3.0 + es6-promise@4.2.8: {} es6-promisify@5.0.0: @@ -2219,6 +2553,10 @@ snapshots: follow-redirects@1.15.9: {} + for-each@0.3.3: + dependencies: + is-callable: 1.2.7 + form-data-encoder@1.7.2: {} form-data@4.0.1: @@ -2232,6 +2570,23 @@ snapshots: node-domexception: 1.0.0 web-streams-polyfill: 4.0.0-beta.3 + function-bind@1.1.2: {} + + get-intrinsic@1.2.6: + dependencies: + call-bind-apply-helpers: 1.0.1 + dunder-proto: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + function-bind: 1.1.2 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + gopd@1.2.0: {} + graceful-fs@4.2.11: optional: true @@ -2253,6 +2608,25 @@ snapshots: transitivePeerDependencies: - encoding + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hash.js@1.1.7: + dependencies: + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + hast-util-to-html@9.0.4: dependencies: '@types/hast': 3.0.4 @@ -2279,6 +2653,8 @@ snapshots: ieee754@1.2.1: {} + inherits@2.0.4: {} + ipaddr.js@2.2.0: {} is-retry-allowed@2.2.0: {} @@ -2372,6 +2748,8 @@ snapshots: lodash@4.17.21: {} + loupe@3.1.2: {} + lower-case@2.0.2: dependencies: tslib: 2.8.1 @@ -2389,6 +2767,8 @@ snapshots: punycode.js: 2.3.1 uc.micro: 2.1.0 + math-intrinsics@1.1.0: {} + mdast-util-to-hast@13.2.0: dependencies: '@types/hast': 3.0.4 @@ -2426,6 +2806,8 @@ snapshots: dependencies: mime-db: 1.52.0 + minimalistic-assert@1.0.1: {} + minimatch@9.0.5: dependencies: brace-expansion: 2.0.1 @@ -2450,6 +2832,22 @@ snapshots: node-gyp-build@4.8.4: optional: true + object-is@1.1.6: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + + object-keys@1.1.1: {} + + object.assign@4.1.7: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.3 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + has-symbols: 1.1.0 + object-keys: 1.1.1 + oniguruma-to-es@0.8.0: dependencies: emoji-regex-xs: 1.0.0 @@ -2492,6 +2890,10 @@ snapshots: pako@2.1.0: {} + pathval@2.0.0: {} + + possible-typed-array-names@1.0.0: {} + property-information@6.5.0: {} proxy-from-env@1.1.0: {} @@ -2531,6 +2933,15 @@ snapshots: semver@7.6.3: {} + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.6 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + shiki@1.24.3: dependencies: '@shikijs/core': 1.24.3 @@ -2656,6 +3067,14 @@ snapshots: node-gyp-build: 4.8.4 optional: true + util@0.12.5: + dependencies: + inherits: 2.0.4 + is-arguments: 1.2.0 + is-generator-function: 1.0.10 + is-typed-array: 1.1.15 + which-typed-array: 1.1.18 + uuid@10.0.0: {} uuid@8.3.2: {} @@ -2685,6 +3104,15 @@ snapshots: tr46: 0.0.3 webidl-conversions: 3.0.1 + which-typed-array@1.1.18: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.3 + for-each: 0.3.3 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + ws@7.5.10(bufferutil@4.0.8)(utf-8-validate@5.0.10): optionalDependencies: bufferutil: 4.0.8 diff --git a/src/agent/index.ts b/src/agent/index.ts index 344c47a..9ecf699 100644 --- a/src/agent/index.ts +++ b/src/agent/index.ts @@ -43,6 +43,7 @@ import { PumpFunTokenOptions, } from "../types"; import { BN } from "@coral-xyz/anchor"; +import { NameAccountAndDomain } from "@onsol/tldparser"; /** * Main class for interacting with Solana blockchain @@ -211,22 +212,26 @@ export class SolanaAgentKit { ); } - async resolveAllDomains(domain: string): Promise { + async resolveAllDomains(domain: string): Promise { return resolveAllDomains(this, domain); } - async getOwnedAllDomains(owner: PublicKey): Promise { + async getOwnedAllDomains( + owner: PublicKey + ): Promise { return getOwnedAllDomains(this, owner); } async getOwnedDomainsForTLD( - owner: PublicKey, tld: string - ): Promise { - return getOwnedDomainsForTLD(this, owner, tld); + ):Promise { + return getOwnedDomainsForTLD(this, tld); } - async getAllDomainsTLDs(): Promise { + async getAllDomainsTLDs(): Promise> { return getAllDomainsTLDs(this); } @@ -242,7 +247,7 @@ export class SolanaAgentKit { marketId: PublicKey, baseAmount: BN, quoteAmount: BN, - startTime: BN, + startTime: BN ): Promise { return raydiumCreateAmmV4( this, @@ -251,8 +256,8 @@ export class SolanaAgentKit { baseAmount, quoteAmount, - startTime, - ); + startTime + );; } async raydiumCreateClmm( @@ -260,7 +265,7 @@ export class SolanaAgentKit { mint2: PublicKey, configId: PublicKey, initialPrice: Decimal, - startTime: BN, + startTime: BN ): Promise { return raydiumCreateClmm( this, @@ -278,7 +283,7 @@ export class SolanaAgentKit { configId: PublicKey, mintAAmount: BN, mintBAmount: BN, - startTime: BN, + startTime: BN ): Promise { return raydiumCreateCpmm( this, @@ -287,7 +292,8 @@ export class SolanaAgentKit { configId, mintAAmount, mintBAmount, - startTime, + + startTime ); } @@ -295,7 +301,7 @@ export class SolanaAgentKit { baseMint: PublicKey, quoteMint: PublicKey, lotSize: number = 1, - tickSize: number = 0.01, + tickSize: number = 0.01 ): Promise { return openbookCreateMarket( this, diff --git a/src/langchain/index.ts b/src/langchain/index.ts index afb214f..f8c76f7 100644 --- a/src/langchain/index.ts +++ b/src/langchain/index.ts @@ -1040,6 +1040,12 @@ export function createSolanaTools(solanaKit: SolanaAgentKit) { new SolanaOpenbookCreateMarket(solanaKit), new SolanaCreateSingleSidedWhirlpoolTool(solanaKit), new SolanaPythFetchPrice(solanaKit), + new SolanaResolveDomain(solanaKit), + new SolanaGetOwnedDomains(solanaKit), + new SolanaGetOwnedTldDomains(solanaKit), + new SolanaGetAllTlds(solanaKit), + new SolanaGetAllRegisteredDomains(solanaKit), + new SolanaGetMainDomain(solanaKit), ]; } diff --git a/src/tools/get_all_active_tlds.ts b/src/tools/get_all_active_tlds.ts deleted file mode 100644 index 929fbfc..0000000 --- a/src/tools/get_all_active_tlds.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { - NameRegistryState, - getAllDomains, - ROOT_DOMAIN_ACCOUNT, -} from "@bonfida/spl-name-service"; -import { Connection, PublicKey } from "@solana/web3.js"; -import { SolanaAgentKit } from "../index"; - -/** - * Get all active top-level domains (TLDs) in the Solana name service - * @param agent SolanaAgentKit instance - * @returns Array of active TLD strings - */ -export async function getAllDomainsTLDs( - agent: SolanaAgentKit -): Promise { - try { - // Get the root domain record - const rootAccount = await NameRegistryState.retrieve( - agent.connection, - ROOT_DOMAIN_ACCOUNT - ); - - if (!rootAccount) { - throw new Error("Root domain account not found"); - } - - // Fetch all TLD records under the root domain - const tldAccounts = await agent.connection.getProgramAccounts( - new PublicKey("namesLPneVptA9Z5rqUDD9tMTWEJwofgaYwp8cawRkX"), - { - filters: [ - { - memcmp: { - offset: 0, - bytes: rootAccount.registry.owner.toBase58(), - }, - }, - ], - } - ); - - // Parse the TLD names from the accounts - const tlds: string[] = []; - for (const account of tldAccounts) { - const registry = await NameRegistryState.retrieve( - agent.connection, - account.pubkey - ); - - if (registry && registry.registry.data) { - const tldName = Buffer.from(registry.registry.data) - .toString() - .replace(/\0/g, ""); - if (tldName) { - tlds.push(tldName); - } - } - } - - return tlds; - } catch (error: any) { - throw new Error(`Failed to fetch TLDs: ${error.message}`); - } -} diff --git a/src/tools/get_all_domains_tlds.ts b/src/tools/get_all_domains_tlds.ts new file mode 100644 index 0000000..d46fdba --- /dev/null +++ b/src/tools/get_all_domains_tlds.ts @@ -0,0 +1,21 @@ +import { Connection, PublicKey } from "@solana/web3.js"; +import { SolanaAgentKit } from "../index"; +import { getAllTld } from "@onsol/tldparser"; + +/** + * Get all active top-level domains (TLDs) in the Solana name service + * @param agent SolanaAgentKit instance + * @returns Array of active TLD strings + */ +export async function getAllDomainsTLDs( + agent: SolanaAgentKit +): Promise> { + try { + return getAllTld(agent.connection) + } catch (error: any) { + throw new Error(`Failed to fetch TLDs: ${error.message}`); + } +} \ No newline at end of file diff --git a/src/tools/get_all_registered_all_domains.ts b/src/tools/get_all_registered_all_domains.ts index dc0f0a4..5520a48 100644 --- a/src/tools/get_all_registered_all_domains.ts +++ b/src/tools/get_all_registered_all_domains.ts @@ -1,7 +1,7 @@ import { getAllDomains } from "@bonfida/spl-name-service"; import { SolanaAgentKit } from "../agent"; import { PublicKey } from "@solana/web3.js"; -import { getAllDomainsTLDs } from "./get_all_active_tlds"; +import { getAllDomainsTLDs } from "./get_all_domains_tlds"; /** * Get all registered domains across all TLDs @@ -20,7 +20,7 @@ export async function getAllRegisteredAllDomains( for (const tld of tlds) { const domains = await getAllDomains( agent.connection, - new PublicKey("namesLPneVptA9Z5rqUDD9tMTWEJwofgaYwp8cawRkX"), + new PublicKey("namesLPneVptA9Z5rqUDD9tMTWEJwofgaYwp8cawRkX") ); // Add domains with TLD suffix diff --git a/src/tools/get_main_domain.ts b/src/tools/get_main_all_domains_domain.ts similarity index 68% rename from src/tools/get_main_domain.ts rename to src/tools/get_main_all_domains_domain.ts index 775c343..98f0dcd 100644 --- a/src/tools/get_main_domain.ts +++ b/src/tools/get_main_all_domains_domain.ts @@ -6,16 +6,19 @@ import { PublicKey } from "@solana/web3.js"; * Get the user's main/favorite domain for a SolanaAgentKit instance * @param agent SolanaAgentKit instance * @param owner Owner's public key - * @returns Promise resolving to the main domain name or null if not set + * @returns Promise resolving to the main domain name or null if not found */ export async function getMainAllDomainsDomain( agent: any, owner: PublicKey ): Promise { + let mainDomain = null; try { - const favDomain = await _getFavoriteDomain(agent.connection, owner); - return favDomain.stale ? null : favDomain.reverse; + mainDomain = await _getFavoriteDomain(agent.connection, owner); + return mainDomain.stale ? null : mainDomain.reverse; } catch (error: any) { - throw new Error(`Failed to fetch main domain: ${error.message}`); + console.log("No main/favorite domain found"); } -} \ No newline at end of file + return null +} + diff --git a/src/tools/get_owned_all_domains.ts b/src/tools/get_owned_all_domains.ts new file mode 100644 index 0000000..c626658 --- /dev/null +++ b/src/tools/get_owned_all_domains.ts @@ -0,0 +1,20 @@ +import { SolanaAgentKit } from "../agent"; +import { PublicKey } from "@solana/web3.js"; +import { NameAccountAndDomain, TldParser } from "@onsol/tldparser"; + +/** + * Get all domains owned domains for a specific TLD for the agent's wallet + * @param agent SolanaAgentKit instance + * @param owner - PublicKey of the owner + * @returns Promise resolving to an array of owned domains or an empty array if none are found + */ +export async function getOwnedAllDomains( + agent: SolanaAgentKit, + owner:PublicKey +): Promise { + try { + return new TldParser(agent.connection).getParsedAllUserDomains(owner); + } catch (error: any) { + throw new Error(`Failed to fetch owned domains: ${error.message}`); + } +} diff --git a/src/tools/get_domains_on_tld.ts b/src/tools/get_owned_domains_for_tld.ts similarity index 54% rename from src/tools/get_domains_on_tld.ts rename to src/tools/get_owned_domains_for_tld.ts index 045f44a..16c3cb9 100644 --- a/src/tools/get_domains_on_tld.ts +++ b/src/tools/get_owned_domains_for_tld.ts @@ -1,23 +1,25 @@ +import { NameAccountAndDomain, TldParser } from "@onsol/tldparser"; import { SolanaAgentKit } from "../agent"; -import { getOwnedAllDomains } from "./lookup_owner"; import { PublicKey } from "@solana/web3.js"; - /** * Get all domains owned by an address for a specific TLD * @param agent SolanaAgentKit instance - * @param owner Owner's public key * @param tld Top-level domain (e.g., "sol") - * @returns Array of owned domain names for the specified TLD + * @returns Promise resolving to an array of owned domain names for the specified TLD or an empty array if none are found */ export async function getOwnedDomainsForTLD( agent: SolanaAgentKit, - owner: PublicKey, tld: string -): Promise { +): Promise { try { - const allDomains = await getOwnedAllDomains(agent, owner); - return allDomains.filter(domain => domain.endsWith(`.${tld}`)); + return new TldParser(agent.connection) + .getParsedAllUserDomainsFromTld( + agent.wallet_address, + tld + ) } catch (error: any) { throw new Error(`Failed to fetch domains for TLD: ${error.message}`); } } + + diff --git a/src/tools/index.ts b/src/tools/index.ts index 85e338a..38fcdb5 100644 --- a/src/tools/index.ts +++ b/src/tools/index.ts @@ -16,11 +16,11 @@ export * from "./stake_with_jup"; export * from "./fetch_price"; export * from "./send_compressed_airdrop"; export * from "./create_orca_single_sided_whirlpool"; -export * from "./get_all_active_tlds"; +export * from "./get_all_domains_tlds"; export * from "./get_all_registered_all_domains"; -export * from "./get_domains_on_tld"; -export * from "./get_main_domain"; -export * from "./lookup_owner"; +export * from "./get_owned_domains_for_tld"; +export * from "./get_main_all_domains_domain"; +export * from "./get_owned_all_domains"; export * from "./resolve_domain"; export * from "./raydium_create_ammV4"; diff --git a/src/tools/lookup_owner.ts b/src/tools/lookup_owner.ts deleted file mode 100644 index cffd264..0000000 --- a/src/tools/lookup_owner.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { getAllDomains } from "@bonfida/spl-name-service"; -import { SolanaAgentKit } from "../agent"; -import { PublicKey } from "@solana/web3.js"; - -/** - * Get all domains owned by a specific address - * @param agent SolanaAgentKit instance - * @param owner Owner's public key - * @returns Array of owned domain names - */ -export async function getOwnedAllDomains( - agent: SolanaAgentKit, - owner: PublicKey -): Promise { - try { - const domains = await getAllDomains(agent.connection, owner); - return domains.map(domain => domain.toString()); - } catch (error: any) { - throw new Error(`Failed to fetch owned domains: ${error.message}`); - } -} diff --git a/src/tools/resolve_domain.ts b/src/tools/resolve_domain.ts index 3ea5e41..2ba5f4d 100644 --- a/src/tools/resolve_domain.ts +++ b/src/tools/resolve_domain.ts @@ -1,42 +1,22 @@ -import { Buffer } from "buffer"; -import { PublicKey } from "@solana/web3.js"; -import { - getNameAccountKeySync, - NAME_PROGRAM_ID, -} from "@bonfida/spl-name-service"; +import { TldParser } from "@onsol/tldparser"; import { SolanaAgentKit } from "../index"; +import { PublicKey } from "@solana/web3.js"; /** - * Resolve a domain to its public key + * Resolve all domains for a given agent and domain * @param agent SolanaAgentKit instance * @param domain Domain name to resolve - * @returns Associated public key or null if not found + * @returns Promise resolving to the domain or undefined if not found */ export async function resolveAllDomains( agent: SolanaAgentKit, domain: string -): Promise { +): Promise { try { - // Convert domain name to buffer for hashing - const hashedDomain = Buffer.from(domain); - - // Get the name account key using the new sync method - const nameAccountKey = getNameAccountKeySync( - hashedDomain, - undefined, // nameClass - undefined // nameParent - ); - - // Get the account info to retrieve the owner - const owner = await agent.connection.getAccountInfo(nameAccountKey); - - if (!owner) { - return null; - } - - // The owner's public key is stored in the data buffer starting at offset 32 - return new PublicKey(owner.data.slice(32, 64)); + let tld = new TldParser(agent.connection).getOwnerFromDomainTld(domain) + return tld; } catch (error: any) { throw new Error(`Domain resolution failed: ${error.message}`); } } + diff --git a/test/domain_methods.test.ts b/test/domain_methods.test.ts new file mode 100644 index 0000000..2485ed7 --- /dev/null +++ b/test/domain_methods.test.ts @@ -0,0 +1,146 @@ + +import { SolanaAgentKit } from "../src"; +import { PublicKey } from "@solana/web3.js"; +import * as dotenv from "dotenv"; +import { expect } from "chai"; +import { before, describe, it } from "node:test"; +import { TldParser } from "@onsol/tldparser"; + +dotenv.config(); + +describe("Solana Domain Methods Tests", () => { + let agent: SolanaAgentKit; + + before(() => { + // Initialize the agent before running tests + if ( + !process.env.SOLANA_PRIVATE_KEY || + !process.env.RPC_URL || + !process.env.OPENAI_API_KEY + ) { + throw new Error("Required environment variables are not set"); + } + + agent = new SolanaAgentKit( + process.env.SOLANA_PRIVATE_KEY, + process.env.RPC_URL, + process.env.OPENAI_API_KEY + ); + }); + + describe("resolveAllDomains", () => { + it("should resolve a valid domain to a public key", async () => { + const testDomain = "hero.sol"; + const result = await agent.resolveAllDomains(testDomain); + expect(result).to.be.instanceof(PublicKey); + }); + it("should perform fetching of an owner an nft domain", async () => { + const parser = new TldParser(agent.connection); + const domanTld = "miester.sol"; + const ownerReceived = await parser.getOwnerFromDomainTld(domanTld); + const owner = new PublicKey( + "2EGGxj2qbNAJNgLCPKca8sxZYetyTjnoRspTPjzN2D67" + ); + expect(ownerReceived).to.be(owner.toString()); + }); + it("should return null for non-existent domain", async () => { + const nonExistentDomain = "nonexistent123456789.sol"; + const result = await agent.resolveAllDomains(nonExistentDomain); + expect(result).to.be.null; + }); + + it("should handle invalid domain format", async () => { + const invalidDomain = ""; + try { + await agent.resolveAllDomains(invalidDomain); + expect.fail("Should have thrown an error"); + } catch (error) { + expect(error).to.be.instanceof(Error); + } + }); + }); + + describe("getOwnedAllDomains", () => { + it("should return array of domains for an owner", async () => { + const owner = new PublicKey( + "2EGGxj2qbNAJNgLCPKca8sxZYetyTjnoRspTPjzN2D67" + ); + const domains = await agent.getOwnedAllDomains(owner); + expect(domains).to.be.an("array").that.includes("miester.sol"); + domains.forEach((domain) => { + expect(domain).to.be.a("string"); + }); + }); + it("should return array of domains for an owner", async () => { + const owner = new PublicKey(agent.wallet_address); + const domains = await agent.getOwnedAllDomains(owner); + expect(domains).to.be.an("array"); + domains.forEach((domain) => { + expect(domain).to.be.a("string"); + }); + }); + + it("should handle owner with no domains", async () => { + // Create a new random public key that likely owns no domains + const emptyOwner = PublicKey.unique(); + const domains = await agent.getOwnedAllDomains(emptyOwner); + expect(domains).to.be.an("array"); + expect(domains).to.have.lengthOf(0); + }); + }); + + describe("getOwnedDomainsForTLD", () => { + it("should return domains for specific TLD", async () => { + const tld = "sol"; + const domains = await agent.getOwnedDomainsForTLD(tld); + expect(domains).to.be.an("array"); + domains.forEach((domain) => { + console.log(`these are the domains ${domain.domain}`) + }); + }); + + it("should return empty array for non-existent TLD", async () => { + const nonExistentTLD = "nonexistent"; + const domains = await agent.getOwnedDomainsForTLD(nonExistentTLD); + expect(domains).to.be.an("array"); + expect(domains).to.have.lengthOf(0); + }); + }); + + describe("getAllDomainsTLDs", () => { + it("should return array of TLDs", async () => { + const tlds = await agent.getAllDomainsTLDs(); + expect(tlds).to.be.an("array"); + }); + }); + + describe("getAllRegisteredAllDomains", () => { + it("should return array of all registered domains", async () => { + const domains = await agent.getAllRegisteredAllDomains(); + expect(domains).to.be.an("array"); + domains.forEach((domain) => { + expect(domain).to.be.a("string"); + expect(domain).to.include("."); + }); + }); + }); + + describe("getMainAllDomainsDomain", () => { + it("should return main domain or null for an owner", async () => { + const owner = new PublicKey( + "2EGGxj2qbNAJNgLCPKca8sxZYetyTjnoRspTPjzN2D67" + ); + const mainDomain = await agent.getMainAllDomainsDomain(owner); + expect(mainDomain).to.satisfy((domain: string | null) => { + return domain === null || typeof domain === "string"; + }); + }); + + it("should return null for address without main domain", async () => { + const emptyOwner = PublicKey.unique(); + const mainDomain = await agent.getMainAllDomainsDomain(emptyOwner); + expect(mainDomain).to.be.null; + }); + }); +}); +