diff --git a/agent.ts b/agent.ts index 36d4d8c3..0b2d635b 100644 --- a/agent.ts +++ b/agent.ts @@ -15,6 +15,7 @@ import { type SwapBestRouteResult, } from "./lib/dex"; import { bridgeTokenTool } from "./tools/bridge"; +import { stellarGetBalanceTool, stellarGetAccountInfoTool } from "./tools/stellar"; import { Horizon, Keypair, @@ -157,6 +158,51 @@ export class AgentClient { }); } + /** + * Get the balance of a Stellar account. + * @param publicKey Optional Stellar public key (defaults to client's publicKey) + */ + async getBalance(publicKey?: string) { + const targetPublicKey = publicKey || this.publicKey; + if (!targetPublicKey) { + throw new Error("Public key is required to fetch balance."); + } + + const result = await stellarGetBalanceTool.func({ + publicKey: targetPublicKey, + network: this.network, + }); + + try { + return JSON.parse(result); + } catch (e) { + // If it's not JSON (e.g. error message), return as is + return result; + } + } + + /** + * Get full details of a Stellar account. + * @param publicKey Optional Stellar public key (defaults to client's publicKey) + */ + async getAccountInfo(publicKey?: string) { + const targetPublicKey = publicKey || this.publicKey; + if (!targetPublicKey) { + throw new Error("Public key is required to fetch account info."); + } + + const result = await stellarGetAccountInfoTool.func({ + publicKey: targetPublicKey, + network: this.network, + }); + + try { + return JSON.parse(result); + } catch (e) { + return result; + } + } + /** * Liquidity Pool operations. */ diff --git a/index.ts b/index.ts index 42c43091..2e299911 100644 --- a/index.ts +++ b/index.ts @@ -2,7 +2,7 @@ import { bridgeTokenTool } from "./tools/bridge"; import { StellarLiquidityContractTool } from "./tools/contract"; import { StellarDexTool } from "./tools/dex"; import { StellarContractTool } from "./tools/stake"; -import { stellarSendPaymentTool } from "./tools/stellar"; +import { stellarSendPaymentTool, stellarGetBalanceTool, stellarGetAccountInfoTool } from "./tools/stellar"; import { AgentClient, AgentConfig, @@ -36,5 +36,7 @@ export const stellarTools = [ StellarDexTool, StellarLiquidityContractTool, StellarContractTool, - stellarSendPaymentTool + stellarSendPaymentTool, + stellarGetBalanceTool, + stellarGetAccountInfoTool ]; diff --git a/tools/stellar.ts b/tools/stellar.ts index dfc4eb95..7a13c64b 100644 --- a/tools/stellar.ts +++ b/tools/stellar.ts @@ -64,4 +64,82 @@ export const stellarSendPaymentTool = new DynamicStructuredTool({ return `Transaction failed: ${errorMessage}`; } }, +}); + +export const stellarGetBalanceTool = new DynamicStructuredTool({ + name: "stellar_get_balance", + description: "Get the balance of a Stellar account. Returns balances for XLM and all other assets.", + schema: z.object({ + publicKey: z.string().describe("The Stellar public key to check the balance for"), + network: z.enum(["testnet", "mainnet"]).optional().describe("The Stellar network to use (defaults to testnet)"), + }), + func: async ({ publicKey, network = "testnet" }: { publicKey: string; network?: string }) => { + try { + if (!StellarSdk.StrKey.isValidEd25519PublicKey(publicKey)) { + throw new Error("Invalid Stellar public key."); + } + + const horizonUrl = network === "mainnet" + ? "https://horizon.stellar.org" + : "https://horizon-testnet.stellar.org"; + + const server = new StellarSdk.Horizon.Server(horizonUrl); + const account = await server.loadAccount(publicKey); + + const balances = account.balances.map((balance: any) => { + if (balance.asset_type === "native") { + return { + asset: "XLM", + balance: balance.balance, + }; + } else { + return { + asset: `${balance.asset_code}:${balance.asset_issuer}`, + balance: balance.balance, + }; + } + }); + + return JSON.stringify(balances, null, 2); + } catch (error) { + const errorMessage = + (error as { response?: { data?: { title?: string } }; message?: string }) + .response?.data?.title || + (error as Error).message || + "Unknown error occurred"; + return `Failed to fetch balance: ${errorMessage}`; + } + }, +}); + +export const stellarGetAccountInfoTool = new DynamicStructuredTool({ + name: "stellar_get_account_info", + description: "Get full details of a Stellar account, including sequence number, signers, and thresholds.", + schema: z.object({ + publicKey: z.string().describe("The Stellar public key to get info for"), + network: z.enum(["testnet", "mainnet"]).optional().describe("The Stellar network to use (defaults to testnet)"), + }), + func: async ({ publicKey, network = "testnet" }: { publicKey: string; network?: string }) => { + try { + if (!StellarSdk.StrKey.isValidEd25519PublicKey(publicKey)) { + throw new Error("Invalid Stellar public key."); + } + + const horizonUrl = network === "mainnet" + ? "https://horizon.stellar.org" + : "https://horizon-testnet.stellar.org"; + + const server = new StellarSdk.Horizon.Server(horizonUrl); + const account = await server.loadAccount(publicKey); + + return JSON.stringify(account, (key, value) => (key === "_links" || key === "balances" ? undefined : value), 2); + } catch (error) { + const errorMessage = + (error as { response?: { data?: { title?: string } }; message?: string }) + .response?.data?.title || + (error as Error).message || + "Unknown error occurred"; + return `Failed to fetch account info: ${errorMessage}`; + } + }, }); \ No newline at end of file