From 2a08017dcd210c68a2a33fd20481a28b3b8788e8 Mon Sep 17 00:00:00 2001 From: Fahri Bilici <28020526+FahriBilici@users.noreply.github.com> Date: Tue, 31 Dec 2024 17:54:33 +0100 Subject: [PATCH] adding missing actions --- src/actions/compressedAirdrop.ts | 105 ++++++++++++++++++++++++++ src/actions/getOwnedDomainsForTLD.ts | 2 +- src/actions/raydiumCreateClmm.ts | 76 +++++++++++++++++++ src/actions/resolveDomain.ts | 2 +- src/actions/tokenDataByTicker.ts | 60 +++++++++++++++ src/langchain/index.ts | 106 ++++++++------------------- 6 files changed, 272 insertions(+), 79 deletions(-) create mode 100644 src/actions/compressedAirdrop.ts create mode 100644 src/actions/raydiumCreateClmm.ts create mode 100644 src/actions/tokenDataByTicker.ts diff --git a/src/actions/compressedAirdrop.ts b/src/actions/compressedAirdrop.ts new file mode 100644 index 0000000..652ae28 --- /dev/null +++ b/src/actions/compressedAirdrop.ts @@ -0,0 +1,105 @@ +import { Action } from "../types/action"; +import { SolanaAgentKit } from "../agent"; +import { z } from "zod"; +import { sendCompressedAirdrop } from "../tools"; + +const compressedAirdropAction: Action = { + name: "solana_compressed_airdrop", + similes: [ + "ZK Compressed airdrop", + "Airdrop tokens with compression", + "Send compressed SPL airdrop", + "Airdrop to multiple recipients", + ], + description: + "Airdrop SPL tokens with ZK Compression (also known as airdropping tokens) to multiple recipients", + examples: [ + [ + { + input: { + mintAddress: "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN", + amount: 42, + decimals: 6, + recipients: [ + "1nc1nerator11111111111111111111111111111111", + "BrFndAe111111111111111111111111111111111", + ], + priorityFeeInLamports: 30000, + shouldLog: true, + }, + output: { + status: "success", + message: + "Airdropped 42 tokens to 2 recipients.", + transactionHashes: ["4uyfBN...", "9XsF2N..."], + }, + explanation: + "Airdrops 42 tokens (with 6 decimals) to 2 recipients, optionally logging progress to stdout.", + }, + ], + ], + // Validate inputs with zod + schema: z.object({ + mintAddress: z + .string() + .min(1) + .describe("Mint address of the token, e.g., 'JUPy...'"), + amount: z + .number() + .positive() + .describe("Number of tokens to airdrop per recipient, e.g., 42"), + decimals: z + .number() + .nonnegative() + .int() + .describe("Decimals of the token, e.g., 6"), + recipients: z + .array(z.string()) + .nonempty() + .describe("Array of recipient addresses, e.g., ['1nc1n...']"), + priorityFeeInLamports: z + .number() + .optional() + .describe("Priority fee in lamports (default is 30_000)"), + shouldLog: z + .boolean() + .optional() + .describe("Whether to log progress to stdout (default is false)"), + }), + handler: async (agent: SolanaAgentKit, input: Record) => { + try { + const { + mintAddress, + amount, + decimals, + recipients, + priorityFeeInLamports, + shouldLog, + } = input; + + // Call your airdrop method on the SolanaAgentKit + const txs = await sendCompressedAirdrop( + mintAddress, + amount, + decimals, + recipients, + priorityFeeInLamports || 30_000, + shouldLog || false, + ); + + return { + status: "success", + message: `Airdropped ${amount} tokens to ${recipients.length} recipients.`, + transactionHashes: txs, + }; + } catch (error: any) { + return { + status: "error", + message: `Failed to airdrop tokens: ${error.message}`, + code: error.code || "UNKNOWN_ERROR", + }; + } + }, +}; + +export default compressedAirdropAction; \ No newline at end of file diff --git a/src/actions/getOwnedDomainsForTLD.ts b/src/actions/getOwnedDomainsForTLD.ts index b419e58..1c0b4be 100644 --- a/src/actions/getOwnedDomainsForTLD.ts +++ b/src/actions/getOwnedDomainsForTLD.ts @@ -4,7 +4,7 @@ import { z } from "zod"; import { getOwnedDomainsForTLD } from "../tools"; const getOwnedDomainsForTLDAction: Action = { - name: "solana_get_owned_domains_for_tld", + name: "solana_get_owned_tld_domains", similes: [ "list owned domains for tld", "get my domains for extension", diff --git a/src/actions/raydiumCreateClmm.ts b/src/actions/raydiumCreateClmm.ts new file mode 100644 index 0000000..60a24db --- /dev/null +++ b/src/actions/raydiumCreateClmm.ts @@ -0,0 +1,76 @@ +import { Action } from "../types/action"; +import { SolanaAgentKit } from "../agent"; +import { z } from "zod"; +import { PublicKey } from "@solana/web3.js"; +import { BN } from "@coral-xyz/anchor"; +import Decimal from "decimal.js"; +import { raydiumCreateClmm } from "../tools"; + +const raydiumCreateClmmAction: Action = { + name: "raydium_create_clmm", + similes: [ + "create clmm pool", + "create concentrated liquidity pool", + "raydium clmm setup", + "launch concentrated liquidity market maker", + ], + description: `Create a Raydium Concentrated Liquidity Market Maker (CLMM) pool with custom ranges, providing increased capital efficiency`, + examples: [ + [ + { + input: { + mint1: "9xU1vzz456... (PublicKey)", + mint2: "EfrsBcG98... (PublicKey)", + configId: "D6yTTr... (Config PublicKey)", + initialPrice: 123.12, + startTime: 0, // or current UNIX timestamp + }, + output: { + status: "success", + message: "Create raydium clmm pool successfully", + transaction: "3skCN8... (transaction signature)", + }, + explanation: + "Creates a CLMM pool between mint1 and mint2 at an initial price of 123.12 and start time of 0.", + }, + ], + ], + // Validate tool inputs using zod + schema: z.object({ + mint1: z.string().min(1).describe("First token mint address (public key)"), + mint2: z.string().min(1).describe("Second token mint address (public key)"), + configId: z.string().min(1).describe("Raydium configId (public key)"), + initialPrice: z.number().describe("Initial price for the CLMM pool"), + startTime: z.number().describe( + "Start time in seconds (UNIX timestamp or zero)", + ), + }), + handler: async (agent: SolanaAgentKit, input: Record) => { + try { + const { mint1, mint2, configId, initialPrice, startTime } = input; + + const tx = await raydiumCreateClmm( + agent, + new PublicKey(mint1), + new PublicKey(mint2), + new PublicKey(configId), + new Decimal(initialPrice), + new BN(startTime), + ); + + return { + status: "success", + message: "Create raydium clmm pool successfully", + transaction: tx, + }; + } catch (error: any) { + return { + status: "error", + message: `Failed to create CLMM pool: ${error.message}`, + code: error.code || "UNKNOWN_ERROR", + }; + } + }, +}; + +export default raydiumCreateClmmAction; \ No newline at end of file diff --git a/src/actions/resolveDomain.ts b/src/actions/resolveDomain.ts index aca514e..d159141 100644 --- a/src/actions/resolveDomain.ts +++ b/src/actions/resolveDomain.ts @@ -4,7 +4,7 @@ import { z } from "zod"; import { resolveAllDomains } from "../tools"; const resolveDomainAction: Action = { - name: "solana_resolve_domain", + name: "solana_resolve_all_domains", similes: [ "resolve domain", "lookup domain", diff --git a/src/actions/tokenDataByTicker.ts b/src/actions/tokenDataByTicker.ts new file mode 100644 index 0000000..6f45702 --- /dev/null +++ b/src/actions/tokenDataByTicker.ts @@ -0,0 +1,60 @@ +import { Action } from "../types/action"; +import { SolanaAgentKit } from "../agent"; +import { z } from "zod"; +import { getTokenDataByTicker } from "../tools"; + +const tokenDataByTickerAction: Action = { + name: "solana_token_data_by_ticker", + similes: [ + "token data by ticker", + "fetch token info by ticker", + "lookup token ticker info", + "get token info by ticker", + ], + description: "Get the token data for a given token ticker", + examples: [ + [ + { + input: { + ticker: "USDC", + }, + output: { + status: "success", + tokenData: { + // Some placeholder example data + symbol: "USDC", + name: "USD Coin", + decimals: 6, + mintAddress: "FhRg...", + }, + }, + explanation: "Fetches metadata for the USDC token by its ticker.", + }, + ], + ], + schema: z.object({ + ticker: z.string().min(1).describe("Ticker of the token, e.g. 'USDC'"), + }), + handler: async (agent: SolanaAgentKit, input: Record) => { + try { + const ticker = input.ticker as string; + + // Use agent’s method to get token data by ticker + const tokenData = await getTokenDataByTicker(ticker); + + return { + status: "success", + tokenData: tokenData, + message: `Successfully fetched token data for ticker: ${ticker}`, + }; + } catch (error: any) { + return { + status: "error", + message: `Failed to fetch token data for ticker: ${input.ticker || ""}. ${error.message}`, + code: error.code || "UNKNOWN_ERROR", + }; + } + }, +}; + +export default tokenDataByTickerAction; \ No newline at end of file diff --git a/src/langchain/index.ts b/src/langchain/index.ts index 75aadb8..3dad335 100644 --- a/src/langchain/index.ts +++ b/src/langchain/index.ts @@ -36,6 +36,10 @@ import resolveSolDomainAction from "../actions/resolveSolDomain"; import getAllDomainsTLDsAction from "../actions/getAllDomainsTLDs"; import getMainAllDomainsDomainAction from "../actions/getMainAllDomainsDomain"; import raydiumCreateAmmV4Action from "../actions/raydiumCreateAmmV4"; +import tokenDataByTickerAction from "../actions/tokenDataByTicker"; +import compressedAirdropAction from "../actions/compressedAirdrop"; +import raydiumCreateClmmAction from "../actions/raydiumCreateClmm"; +import createOpenbookMarketAction from "../actions/createOpenbookMarket"; export class SolanaBalanceTool extends Tool { private action = balanceAction; @@ -541,7 +545,6 @@ export class SolanaFetchPriceTool extends Tool { const parsedInput = { tokenId: input.trim() }; const price = await this.action.handler(this.solanaKit, parsedInput); - //const price = await this.solanaKit.fetchTokenPrice(input.trim()); return JSON.stringify({ status: "success", tokenId: input.trim(), @@ -587,11 +590,9 @@ export class SolanaTokenDataTool extends Tool { } export class SolanaTokenDataByTickerTool extends Tool { - name = "solana_token_data_by_ticker"; - description = `Get the token data for a given token ticker - -Inputs: ticker is required. - ticker: string, eg "USDC"(required)`; + private action = tokenDataByTickerAction; + name = this.action.name; + description = this.action.description; constructor(private solanaKit: SolanaAgentKit) { super(); @@ -600,7 +601,7 @@ Inputs: ticker is required. protected async _call(input: string): Promise { try { const ticker = input.trim(); - const tokenData = await this.solanaKit.getTokenDataByTicker(ticker); + const tokenData = await this.action.handler(this.solanaKit, { ticker }); return JSON.stringify({ status: "success", tokenData: tokenData, @@ -616,16 +617,9 @@ Inputs: ticker is required. } export class SolanaCompressedAirdropTool extends Tool { - name = "solana_compressed_airdrop"; - description = `Airdrop SPL tokens with ZK Compression(also called as airdropping tokens) - -Inputs(input is a JSON string): -mintAddress: string, the mint address of the token, e.g., "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN"(required) -amount: number, the amount of tokens to airdrop per recipient, e.g., 42(required) -decimals: number, the decimals of the token, e.g., 6(required) -recipients: string[], the recipient addresses, e.g., ["1nc1nerator11111111111111111111111111111111"](required) -priorityFeeInLamports: number, the priority fee in lamports.Default is 30_000.(optional) -shouldLog: boolean, whether to log progress to stdout.Default is false. (optional)`; + private action = compressedAirdropAction; + name = this.action.name; + description = this.action.description; constructor(private solanaKit: SolanaAgentKit) { super(); @@ -634,16 +628,7 @@ shouldLog: boolean, whether to log progress to stdout.Default is false. (optiona protected async _call(input: string): Promise { try { const parsedInput = JSON.parse(input); - - const txs = await this.solanaKit.sendCompressedAirdrop( - parsedInput.mintAddress, - parsedInput.amount, - parsedInput.decimals, - parsedInput.recipients, - parsedInput.priorityFeeInLamports || 30_000, - parsedInput.shouldLog || false, - ); - + const txs = await this.action.handler(this.solanaKit, parsedInput); return JSON.stringify({ status: "success", message: `Airdropped ${parsedInput.amount} tokens to ${parsedInput.recipients.length} recipients.`, @@ -740,16 +725,9 @@ export class SolanaRaydiumCreateAmmV4 extends Tool { } export class SolanaRaydiumCreateClmm extends Tool { - name = "raydium_create_clmm"; - description = `Concentrated liquidity market maker, custom liquidity ranges, increased capital efficiency - -Inputs(input is a json string): -mint1: string(required) -mint2: string(required) -configId: string(required) stores pool info, id, index, protocolFeeRate, tradeFeeRate, tickSpacing, fundFeeRate -initialPrice: number, eg: 123.12(required) -startTime: number(seconds), eg: now number or zero(required) - `; + private action = raydiumCreateClmmAction; + name = this.action.name; + description = this.action.description; constructor(private solanaKit: SolanaAgentKit) { super(); @@ -759,15 +737,7 @@ startTime: number(seconds), eg: now number or zero(required) try { const inputFormat = JSON.parse(input); - const tx = await this.solanaKit.raydiumCreateClmm( - new PublicKey(inputFormat.mint1), - new PublicKey(inputFormat.mint2), - - new PublicKey(inputFormat.configId), - - new Decimal(inputFormat.initialPrice), - new BN(inputFormat.startTime), - ); + const tx = await this.action.handler(this.solanaKit, inputFormat); return JSON.stringify({ status: "success", @@ -814,15 +784,9 @@ export class SolanaRaydiumCreateCpmm extends Tool { } export class SolanaOpenbookCreateMarket extends Tool { - name = "solana_openbook_create_market"; - description = `Openbook marketId, required for ammv4 - - Inputs(input is a json string): - baseMint: string(required) -quoteMint: string(required) -lotSize: number(required) -tickSize: number(required) - `; + private action = createOpenbookMarketAction; + name = this.action.name; + description = this.action.description; constructor(private solanaKit: SolanaAgentKit) { super(); @@ -831,14 +795,7 @@ tickSize: number(required) async _call(input: string): Promise { try { const inputFormat = JSON.parse(input); - - const tx = await this.solanaKit.openbookCreateMarket( - new PublicKey(inputFormat.baseMint), - new PublicKey(inputFormat.quoteMint), - - inputFormat.lotSize, - inputFormat.tickSize, - ); + const tx = await this.action.handler(this.solanaKit, inputFormat); return JSON.stringify({ status: "success", @@ -887,13 +844,9 @@ export class SolanaPythFetchPrice extends Tool { } export class SolanaResolveAllDomainsTool extends Tool { - name = "solana_resolve_all_domains"; - description = `Resolve domain names to a public key for ALL domain types EXCEPT.sol domains. - Use this for domains like.blink, .bonk, etc. - DO NOT use this for .sol domains(use solana_resolve_domain instead). - - Input: - domain: string, eg "mydomain.blink" or "mydomain.bonk"(required)`; + private action = resolveDomainAction; + name = this.action.name; + description = this.action.description; constructor(private solanaKit: SolanaAgentKit) { super(); @@ -901,7 +854,8 @@ export class SolanaResolveAllDomainsTool extends Tool { async _call(input: string): Promise { try { - const owner = await this.solanaKit.resolveAllDomains(input); + const parsedInput = JSON.parse(input); + const owner = await this.action.handler(this.solanaKit, parsedInput); if (!owner) { return JSON.stringify({ @@ -956,11 +910,9 @@ export class SolanaGetOwnedDomains extends Tool { } export class SolanaGetOwnedTldDomains extends Tool { - name = "solana_get_owned_tld_domains"; - description = `Get all domains owned by the agent's wallet for a specific TLD. - -Inputs: -tld: string, eg "bonk"(required)`; + private action = getOwnedDomainsForTLDAction; + name = this.action.name; + description = this.action.description; constructor(private solanaKit: SolanaAgentKit) { super(); @@ -968,7 +920,7 @@ tld: string, eg "bonk"(required)`; async _call(input: string): Promise { try { - const domains = await this.solanaKit.getOwnedDomainsForTLD(input); + const domains = await this.action.handler(this.solanaKit, { tld: input }); return JSON.stringify({ status: "success",