Merge branch 'main' into feature/vercel-ai-sdk

This commit is contained in:
Michael Essiet
2025-01-01 04:11:57 +01:00
committed by GitHub
114 changed files with 15714 additions and 1519 deletions

62
src/actions/balance.ts Normal file
View File

@@ -0,0 +1,62 @@
import { PublicKey } from "@solana/web3.js";
import { Action } from "../types/action";
import { SolanaAgentKit } from "../agent";
import { z } from "zod";
import { get_balance } from "../tools";
const balanceAction: Action = {
name: "BALANCE_ACTION",
similes: [
"check balance",
"get wallet balance",
"view balance",
"show balance",
"check token balance",
],
description: `Get the balance of a Solana wallet or token account.
If you want to get the balance of your wallet, you don't need to provide the tokenAddress.
If no tokenAddress is provided, the balance will be in SOL.`,
examples: [
[
{
input: {},
output: {
status: "success",
balance: "100",
token: "SOL",
},
explanation: "Get SOL balance of the wallet",
},
],
[
{
input: {
tokenAddress: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
},
output: {
status: "success",
balance: "1000",
token: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
},
explanation: "Get USDC token balance",
},
],
],
schema: z.object({
tokenAddress: z.string().optional(),
}),
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
const balance = await get_balance(
agent,
input.tokenAddress && new PublicKey(input.tokenAddress),
);
return {
status: "success",
balance: balance,
token: input.tokenAddress || "SOL",
};
},
};
export default balanceAction;

View File

@@ -0,0 +1,104 @@
import { Action } from "../types/action";
import { SolanaAgentKit } from "../agent";
import { z } from "zod";
import { sendCompressedAirdrop } from "../tools";
const compressedAirdropAction: Action = {
name: "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<string, any>) => {
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;

View File

@@ -0,0 +1,86 @@
import { Action } from "../types/action";
import { SolanaAgentKit } from "../agent";
import { z } from "zod";
import { PublicKey } from "@solana/web3.js";
import { create_gibwork_task } from "../tools";
const createGibworkTaskAction: Action = {
name: "CREATE_GIBWORK_TASK",
similes: [
"create task",
"post job",
"create gig",
"post task",
"create work",
"new task on gibwork",
],
description:
"Create a new task on the Gibwork platform with payment in SPL tokens",
examples: [
[
{
input: {
title: "Build a Solana dApp",
content: "Create a simple Solana dApp with React frontend",
requirements: "Experience with Rust and React",
tags: ["solana", "rust", "react"],
tokenMintAddress: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
tokenAmount: 100,
},
output: {
status: "success",
taskId: "task_123",
signature: "3YKpM1...",
message: "Successfully created task: Build a Solana dApp",
},
explanation: "Create a new task on Gibwork with 100 USDC payment",
},
],
],
schema: z.object({
title: z.string().min(1).describe("Title of the task"),
content: z.string().min(1).describe("Description of the task"),
requirements: z
.string()
.min(1)
.describe("Requirements to complete the task"),
tags: z
.array(z.string())
.min(1)
.describe("List of tags associated with the task"),
tokenMintAddress: z.string().describe("Token mint address for payment"),
tokenAmount: z.number().positive().describe("Payment amount for the task"),
payer: z
.string()
.optional()
.describe("Optional payer address (defaults to wallet address)"),
}),
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
try {
const responseData = await create_gibwork_task(
agent,
input.title,
input.content,
input.requirements,
input.tags,
new PublicKey(input.tokenMintAddress),
input.tokenAmount,
input.payer ? new PublicKey(input.payer) : undefined,
);
return {
status: "success",
taskId: responseData.taskId,
signature: responseData.signature,
message: `Successfully created task: ${input.title}`,
};
} catch (error: any) {
return {
status: "error",
message: `Failed to create task: ${error.message}`,
};
}
},
};
export default createGibworkTaskAction;

101
src/actions/createImage.ts Normal file
View File

@@ -0,0 +1,101 @@
import { Action } from "../types/action";
import { SolanaAgentKit } from "../agent";
import { z } from "zod";
import { create_image } from "../tools/create_image";
const createImageAction: Action = {
name: "CREATE_IMAGE",
similes: [
"generate image",
"create artwork",
"make image",
"generate artwork",
"create picture",
"generate picture",
],
description:
"Create an AI-generated image based on a text prompt using OpenAI's DALL-E models",
examples: [
[
{
input: {
prompt: "A beautiful sunset over a mountain landscape",
model: "dall-e-3",
size: "1024x1024",
quality: "standard",
style: "natural",
},
output: {
status: "success",
imageUrl: "https://example.com/image.png",
message: "Successfully generated image",
},
explanation: "Generate an image of a sunset landscape using DALL-E 3",
},
],
],
schema: z.object({
prompt: z
.string()
.min(1)
.max(1000)
.describe("The text description of the image to generate"),
model: z
.enum(["dall-e-3"])
.default("dall-e-3")
.describe("The AI model to use for generation"),
size: z
.enum(["256x256", "512x512", "1024x1024", "1792x1024", "1024x1792"])
.default("1024x1024")
.describe("The size of the generated image"),
quality: z
.enum(["standard", "hd"])
.default("standard")
.describe("The quality level of the generated image"),
style: z
.enum(["natural", "vivid"])
.default("natural")
.describe("The style of the generated image"),
}),
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
try {
if (!agent.config.OPENAI_API_KEY) {
return {
status: "error",
message: "OpenAI API key not found in agent configuration",
};
}
const { prompt, model, size } = input;
const response = await create_image(agent, prompt, model, size);
return {
status: "success",
imageUrl: response.images[0].url,
message: "Successfully generated image",
};
} catch (error: any) {
// Handle specific OpenAI error types
if (error.response) {
const { status, data } = error.response;
if (status === 429) {
return {
status: "error",
message: "Rate limit exceeded. Please try again later.",
};
}
return {
status: "error",
message: `OpenAI API error: ${data.error?.message || error.message}`,
};
}
return {
status: "error",
message: `Failed to generate image: ${error.message}`,
};
}
},
};
export default createImageAction;

View File

@@ -0,0 +1,80 @@
import { Action } from "../types/action";
import { SolanaAgentKit } from "../agent";
import { z } from "zod";
import { PublicKey } from "@solana/web3.js";
import { openbookCreateMarket } from "../tools";
const createOpenbookMarketAction: Action = {
name: "CREATE_OPENBOOK_MARKET",
similes: [
"create openbook market",
"setup trading market",
"new openbook market",
"create trading pair",
"setup dex market",
"new trading market",
],
description: "Create a new trading market on Openbook DEX",
examples: [
[
{
input: {
baseMint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", // USDC
quoteMint: "So11111111111111111111111111111111111111112", // SOL
lotSize: 1,
tickSize: 0.01,
},
output: {
status: "success",
signatures: ["2ZE7Rz...", "3YKpM1..."],
message: "Successfully created Openbook market",
},
explanation:
"Create a new USDC/SOL market on Openbook with default lot and tick sizes",
},
],
],
schema: z.object({
baseMint: z.string().min(1).describe("The base token's mint address"),
quoteMint: z.string().min(1).describe("The quote token's mint address"),
lotSize: z
.number()
.positive()
.default(1)
.describe("The minimum order size (lot size)"),
tickSize: z
.number()
.positive()
.default(0.01)
.describe("The minimum price increment (tick size)"),
}),
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
try {
const baseMint = new PublicKey(input.baseMint);
const quoteMint = new PublicKey(input.quoteMint);
const lotSize = input.lotSize || 1;
const tickSize = input.tickSize || 0.01;
const signatures = await openbookCreateMarket(
agent,
baseMint,
quoteMint,
lotSize,
tickSize,
);
return {
status: "success",
signatures,
message: "Successfully created Openbook market",
};
} catch (error: any) {
return {
status: "error",
message: `Failed to create Openbook market: ${error.message}`,
};
}
},
};
export default createOpenbookMarketAction;

View File

@@ -0,0 +1,117 @@
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 { orcaCreateSingleSidedLiquidityPool } from "../tools";
// Fee tiers mapping from the original tool
const FEE_TIERS = {
0.01: 1,
0.02: 2,
0.04: 4,
0.05: 8,
0.16: 16,
0.3: 64,
0.65: 96,
1.0: 128,
2.0: 256,
} as const;
const createOrcaSingleSidedWhirlpoolAction: Action = {
name: "CREATE_ORCA_SINGLE_SIDED_WHIRLPOOL",
similes: [
"create orca whirlpool",
"setup orca single sided pool",
"initialize orca whirlpool",
"create orca concentrated pool",
"setup orca concentrated liquidity",
"create orca trading pair",
],
description:
"Create a new single-sided whirlpool on Orca with concentrated liquidity",
examples: [
[
{
input: {
depositTokenAmount: "1000000000000", // 1 million tokens with 6 decimals
depositTokenMint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", // USDC
otherTokenMint: "So11111111111111111111111111111111111111112", // SOL
initialPrice: "0.001",
maxPrice: "5.0",
feeTier: 0.3,
},
output: {
status: "success",
signature: "2ZE7Rz...",
message: "Successfully created Orca single-sided whirlpool",
},
explanation:
"Create a USDC/SOL whirlpool with 1M USDC initial liquidity",
},
],
],
schema: z.object({
depositTokenAmount: z
.string()
.min(1)
.describe(
"The amount of deposit token to provide as liquidity (including decimals)",
),
depositTokenMint: z
.string()
.min(1)
.describe("The mint address of the token being deposited"),
otherTokenMint: z
.string()
.min(1)
.describe("The mint address of the other token in the pool"),
initialPrice: z
.string()
.min(1)
.describe("Initial price of deposit token in terms of the other token"),
maxPrice: z
.string()
.min(1)
.describe("Maximum price at which liquidity is added"),
feeTier: z
.number()
.refine((val) => val in FEE_TIERS, "Invalid fee tier")
.describe("Fee tier percentage for the pool (e.g., 0.3 for 0.3%)"),
}),
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
try {
const depositTokenAmount = Number(input.depositTokenAmount);
const depositTokenMint = new PublicKey(input.depositTokenMint);
const otherTokenMint = new PublicKey(input.otherTokenMint);
const initialPrice = new Decimal(input.initialPrice);
const maxPrice = new Decimal(input.maxPrice);
const feeTier = input.feeTier
// Create the whirlpool
const signature = await orcaCreateSingleSidedLiquidityPool(
agent,
depositTokenAmount,
depositTokenMint,
otherTokenMint,
initialPrice,
maxPrice,
feeTier,
);
return {
status: "success",
signature,
message: "Successfully created Orca single-sided whirlpool",
};
} catch (error: any) {
return {
status: "error",
message: `Failed to create whirlpool: ${error.message}`,
};
}
},
};
export default createOrcaSingleSidedWhirlpoolAction;

View File

@@ -0,0 +1,78 @@
import { Action } from "../types/action";
import { SolanaAgentKit } from "../agent";
import { z } from "zod";
import { deploy_collection } from "../tools";
interface CollectionOptions {
name: string;
uri: string;
royaltyBasisPoints?: number;
}
const deployCollectionAction: Action = {
name: "DEPLOY_COLLECTION",
similes: [
"create collection",
"launch collection",
"deploy nft collection",
"create nft collection",
"mint collection",
],
description: `Deploy a new NFT collection on Solana blockchain.`,
examples: [
[
{
input: {
name: "My Collection",
uri: "https://example.com/collection.json",
royaltyBasisPoints: 500,
},
output: {
status: "success",
message: "Collection deployed successfully",
collectionAddress: "7nE9GvcwsqzYxmJLSrYmSB1V1YoJWVK1KWzAcWAzjXkN",
name: "My Collection",
},
explanation: "Deploy an NFT collection with 5% royalty",
},
],
[
{
input: {
name: "Basic Collection",
uri: "https://example.com/basic.json",
},
output: {
status: "success",
message: "Collection deployed successfully",
collectionAddress: "8nE9GvcwsqzYxmJLSrYmSB1V1YoJWVK1KWzAcWAzjXkM",
name: "Basic Collection",
},
explanation: "Deploy a basic NFT collection without royalties",
},
],
],
schema: z.object({
name: z.string().min(1, "Name is required"),
uri: z.string().url("URI must be a valid URL"),
royaltyBasisPoints: z.number().min(0).max(10000).optional(),
}),
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
const options: CollectionOptions = {
name: input.name,
uri: input.uri,
royaltyBasisPoints: input.royaltyBasisPoints,
};
const result = await deploy_collection(agent, options);
return {
status: "success",
message: "Collection deployed successfully",
collectionAddress: result.collectionAddress.toString(),
name: input.name,
};
},
};
export default deployCollectionAction;

View File

@@ -0,0 +1,83 @@
import { Action } from "../types/action";
import { SolanaAgentKit } from "../agent";
import { z } from "zod";
import { deploy_token } from "../tools";
const deployTokenAction: Action = {
name: "DEPLOY_TOKEN",
similes: [
"create token",
"launch token",
"deploy new token",
"create new token",
"mint token",
],
description:
"Deploy a new SPL token on the Solana blockchain with specified parameters",
examples: [
[
{
input: {
name: "My Token",
uri: "https://example.com/token.json",
symbol: "MTK",
decimals: 9,
initialSupply: 1000000,
},
output: {
mint: "7nE9GvcwsqzYxmJLSrYmSB1V1YoJWVK1KWzAcWAzjXkN",
status: "success",
message: "Token deployed successfully",
},
explanation: "Deploy a token with initial supply and metadata",
},
],
[
{
input: {
name: "Basic Token",
uri: "https://example.com/basic.json",
symbol: "BASIC",
},
output: {
mint: "8nE9GvcwsqzYxmJLSrYmSB1V1YoJWVK1KWzAcWAzjXkM",
status: "success",
message: "Token deployed successfully",
},
explanation: "Deploy a basic token with minimal parameters",
},
],
],
schema: z.object({
name: z.string().min(1, "Name is required"),
uri: z.string().url("URI must be a valid URL"),
symbol: z.string().min(1, "Symbol is required"),
decimals: z.number().optional(),
initialSupply: z.number().optional(),
}),
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
try {
const result = await deploy_token(
agent,
input.name,
input.uri,
input.symbol,
input.decimals,
input.initialSupply,
);
return {
mint: result.mint.toString(),
status: "success",
message: "Token deployed successfully",
};
} catch (error: any) {
return {
status: "error",
message: `Token deployment failed: ${error.message}`,
};
}
},
};
export default deployTokenAction;

57
src/actions/fetchPrice.ts Normal file
View File

@@ -0,0 +1,57 @@
import { Action } from "../types/action";
import { SolanaAgentKit } from "../agent";
import { z } from "zod";
import { PublicKey } from "@solana/web3.js";
import { fetchPrice } from "../tools";
const fetchPriceAction: Action = {
name: "FETCH_PRICE",
similes: [
"get token price",
"check price",
"token value",
"price check",
"get price in usd",
],
description:
"Fetch the current price of a Solana token in USDC using Jupiter API",
examples: [
[
{
input: {
tokenAddress: "So11111111111111111111111111111111111111112",
},
output: {
status: "success",
price: "23.45",
message: "Current price: $23.45 USDC",
},
explanation: "Get the current price of SOL token in USDC",
},
],
],
schema: z.object({
tokenAddress: z
.string()
.describe("The mint address of the token to fetch the price for"),
}),
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
try {
const tokenId = new PublicKey(input.tokenAddress);
const price = await fetchPrice(tokenId);
return {
status: "success",
price,
message: `Current price: $${price} USDC`,
};
} catch (error: any) {
return {
status: "error",
message: `Failed to fetch price: ${error.message}`,
};
}
},
};
export default fetchPriceAction;

View File

@@ -0,0 +1,52 @@
import { Action } from "../types/action";
import { SolanaAgentKit } from "../agent";
import { z } from "zod";
import { getAllDomainsTLDs } from "../tools";
const getAllDomainsTLDsAction: Action = {
name: "GET_ALL_TLDS",
similes: [
"list domain tlds",
"get domain extensions",
"fetch domain tlds",
"get top level domains",
"list available tlds",
"get domain suffixes",
],
description:
"Get a list of all available top-level domains (TLDs) for Solana domains",
examples: [
[
{
input: {},
output: {
status: "success",
tlds: [".sol", ".abc", ".backpack", ".bonk"],
message: "Successfully retrieved all domain TLDs",
},
explanation:
"Get a list of all available TLDs that can be used for Solana domains",
},
],
],
schema: z.object({}),
handler: async (agent: SolanaAgentKit) => {
try {
// Get all domain TLDs
const tlds = await getAllDomainsTLDs(agent);
return {
status: "success",
tlds,
message: "Successfully retrieved all domain TLDs",
};
} catch (error: any) {
return {
status: "error",
message: `Failed to get domain TLDs: ${error.message}`,
};
}
},
};
export default getAllDomainsTLDsAction;

View File

@@ -0,0 +1,70 @@
import { Action } from "../types/action";
import { SolanaAgentKit } from "../agent";
import { z } from "zod";
import { getAllRegisteredAllDomains } from "../tools";
const getAllRegisteredAllDomainsAction: Action = {
name: "GET_ALL_REGISTERED_ALL_DOMAINS",
similes: [
"list registered domains",
"get all domains",
"fetch registered domains",
"get domain list",
"list active domains",
"get registered names",
],
description: "Get a list of all registered domains across all TLDs",
examples: [
[
{
input: {
limit: 100,
offset: 0,
},
output: {
status: "success",
domains: ["solana.sol", "bonk.abc", "wallet.backpack"],
total: 3,
message: "Successfully retrieved registered domains",
},
explanation: "Get the first 100 registered domains across all TLDs",
},
],
],
schema: z.object({
limit: z
.number()
.positive()
.max(1000)
.default(100)
.describe("Maximum number of domains to return"),
offset: z
.number()
.nonnegative()
.default(0)
.describe("Number of domains to skip"),
}),
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
try {
const limit = input.limit || 100;
const offset = input.offset || 0;
// Get all registered domains
const domains = await getAllRegisteredAllDomains(agent);
return {
status: "success",
domains: domains.slice(offset, offset + limit),
total: domains.length,
message: "Successfully retrieved registered domains",
};
} catch (error: any) {
return {
status: "error",
message: `Failed to get registered domains: ${error.message}`,
};
}
},
};
export default getAllRegisteredAllDomainsAction;

View File

@@ -0,0 +1,67 @@
import { Action } from "../types/action";
import { SolanaAgentKit } from "../agent";
import { z } from "zod";
import { PublicKey } from "@solana/web3.js";
import { getMainAllDomainsDomain } from "../tools";
const getMainAllDomainsDomainAction: Action = {
name: "GET_MAIN_ALL_DOMAINS_DOMAIN",
similes: [
"get main domain",
"fetch primary domain",
"get default domain",
"get main address name",
"get primary name",
"get main domain name",
],
description: "Get the main domain associated with a wallet address",
examples: [
[
{
input: {
address: "7nxQB...",
},
output: {
status: "success",
domain: "solana.sol",
message: "Successfully retrieved main domain",
},
explanation: "Get the main domain name for a given wallet address",
},
],
],
schema: z.object({
address: z
.string()
.min(1)
.describe("The wallet address to get the main domain for"),
}),
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
try {
const mainDomain = await getMainAllDomainsDomain(
agent,
new PublicKey(input.address),
);
if (!mainDomain) {
return {
status: "error",
message: "No main domain found for this address",
};
}
return {
status: "success",
domain: mainDomain,
message: "Successfully retrieved main domain",
};
} catch (error: any) {
return {
status: "error",
message: `Failed to get main domain: ${error.message}`,
};
}
},
};
export default getMainAllDomainsDomainAction;

View File

@@ -0,0 +1,63 @@
import { Action } from "../types/action";
import { SolanaAgentKit } from "../agent";
import { z } from "zod";
import { PublicKey } from "@solana/web3.js";
import { getOwnedAllDomains } from "../tools";
const getOwnedAllDomainsAction: Action = {
name: "GET_OWNED_ALL_DOMAINS",
similes: [
"list owned domains",
"get my domains",
"fetch wallet domains",
"get owned names",
"list my domains",
"get address domains",
],
description:
"Get all domains owned by a specific wallet address across all TLDs",
examples: [
[
{
input: {
address: "7nxQB...",
},
output: {
status: "success",
domains: ["solana.sol", "wallet.abc", "user.backpack"],
total: 3,
message: "Successfully retrieved owned domains",
},
explanation: "Get all domain names owned by a specific wallet address",
},
],
],
schema: z.object({
address: z
.string()
.min(1)
.describe("The wallet address to get owned domains for"),
}),
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
try {
const address = new PublicKey(input.address);
// Get owned domains
const domains = await getOwnedAllDomains(agent, address);
return {
status: "success",
domains,
total: domains.length,
message: `Successfully retrieved ${domains.length} owned domain${domains.length === 1 ? "" : "s"}`,
};
} catch (error: any) {
return {
status: "error",
message: `Failed to get owned domains: ${error.message}`,
};
}
},
};
export default getOwnedAllDomainsAction;

View File

@@ -0,0 +1,63 @@
import { Action } from "../types/action";
import { SolanaAgentKit } from "../agent";
import { z } from "zod";
import { getOwnedDomainsForTLD } from "../tools";
const getOwnedDomainsForTLDAction: Action = {
name: "GET_OWNED_DOMAINS_FOR_TLD",
similes: [
"list owned domains for tld",
"get my domains for extension",
"fetch wallet domains by tld",
"get owned names by extension",
"list my domains by tld",
"get address domains for tld",
],
description:
"Get all domains owned by a specific wallet address for a given top-level domain (TLD)",
examples: [
[
{
input: {
tld: "sol",
},
output: {
status: "success",
domains: ["solana.sol", "wallet.sol", "user.sol"],
total: 3,
message: "Successfully retrieved owned domains for .sol",
},
explanation:
"Get all .sol domain names owned by a specific wallet address",
},
],
],
schema: z.object({
tld: z
.string()
.min(1)
.describe("The top-level domain to filter by (e.g., 'sol', 'abc')"),
}),
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
try {
const tld = input.tld.toLowerCase();
// Get owned domains for TLD
const domains = await getOwnedDomainsForTLD(agent, tld);
return {
status: "success",
domains,
total: domains.length,
message: `Successfully retrieved ${domains.length} owned domain${domains.length === 1 ? "" : "s"} for .${tld}`,
};
} catch (error: any) {
return {
status: "error",
message: `Failed to get owned domains: ${error.message}`,
};
}
},
};
export default getOwnedDomainsForTLDAction;

View File

@@ -0,0 +1,57 @@
import { Action } from "../types/action";
import { SolanaAgentKit } from "../agent";
import { z } from "zod";
import { PublicKey } from "@solana/web3.js";
import { getPrimaryDomain } from "../tools";
const getPrimaryDomainAction: Action = {
name: "GET_PRIMARY_DOMAIN",
similes: [
"get primary domain",
"lookup primary domain",
"check primary domain",
"find primary domain",
"get main domain",
"primary sol domain",
],
description:
"Get the primary .sol domain associated with a Solana wallet address",
examples: [
[
{
input: {
account: "7nxQB...",
},
output: {
status: "success",
domain: "vitalik.sol",
message: "Primary domain: vitalik.sol",
},
explanation: "Get the primary .sol domain for a wallet address",
},
],
],
schema: z.object({
account: z.string().min(1).describe("The Solana wallet address to lookup"),
}),
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
try {
const account = new PublicKey(input.account);
const response = await getPrimaryDomain(agent, account);
return {
status: "success",
domain: response,
message: `Primary domain: ${response}`,
};
} catch (error: any) {
return {
status: "error",
message: `Failed to get primary domain: ${error.message}`,
};
}
},
};
export default getPrimaryDomainAction;

48
src/actions/getTPS.ts Normal file
View File

@@ -0,0 +1,48 @@
import { Action } from "../types/action";
import { SolanaAgentKit } from "../agent";
import { z } from "zod";
import { getTPS } from "../tools";
const getTPSAction: Action = {
name: "GET_TPS",
similes: [
"get transactions per second",
"check network speed",
"network performance",
"transaction throughput",
"network tps",
],
description:
"Get the current transactions per second (TPS) of the Solana network",
examples: [
[
{
input: {},
output: {
status: "success",
tps: 3500,
message: "Current network TPS: 3500",
},
explanation: "Get the current TPS of the Solana network",
},
],
],
schema: z.object({}), // No input parameters required
handler: async (agent: SolanaAgentKit, _input: Record<string, any>) => {
try {
const response = await getTPS(agent);
return {
status: "success",
response,
message: `Current network TPS: ${response}`,
};
} catch (error: any) {
return {
status: "error",
message: `Failed to get TPS: ${error.message}`,
};
}
},
};
export default getTPSAction;

View File

@@ -0,0 +1,98 @@
import { Action } from "../types/action";
import { SolanaAgentKit } from "../agent";
import { z } from "zod";
import { PublicKey } from "@solana/web3.js";
import { JupiterTokenData } from "../types";
import { getTokenAddressFromTicker, getTokenDataByAddress } from "../tools";
const getTokenDataAction: Action = {
name: "GET_TOKEN_DATA",
similes: [
"get token info",
"token details",
"lookup token",
"find token",
"token data",
],
description: "Get token data from either a token address or ticker symbol",
examples: [
[
{
input: {
address: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
},
output: {
status: "success",
token: {
name: "USD Coin",
symbol: "USDC",
address: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
decimals: 6,
},
},
explanation: "Get token data using the token's address",
},
],
[
{
input: {
ticker: "SOL",
},
output: {
status: "success",
token: {
name: "Wrapped SOL",
symbol: "SOL",
address: "So11111111111111111111111111111111111111112",
decimals: 9,
},
},
explanation: "Get token data using the token's ticker symbol",
},
],
],
schema: z
.object({
address: z.string().optional().describe("The token's mint address"),
ticker: z.string().optional().describe("The token's ticker symbol"),
})
.refine((data) => data.address || data.ticker, {
message: "Either address or ticker must be provided",
}),
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
try {
let tokenData: JupiterTokenData | undefined;
if (input.address) {
tokenData = await getTokenDataByAddress(new PublicKey(input.address));
} else if (input.ticker) {
const address = await getTokenAddressFromTicker(input.ticker);
if (address) {
tokenData = await getTokenDataByAddress(new PublicKey(address));
}
}
if (!tokenData) {
return {
status: "error",
message: "Token not found or not verified",
};
}
return {
status: "success",
token: {
name: tokenData.name,
symbol: tokenData.symbol,
address: tokenData.address,
decimals: tokenData.decimals,
logoURI: tokenData.logoURI,
},
};
} catch (error: any) {
return {
status: "error",
message: `Failed to get token data: ${error.message}`,
};
}
},
};
export default getTokenDataAction;

61
src/actions/index.ts Normal file
View File

@@ -0,0 +1,61 @@
import deployTokenAction from "./deployToken";
import balanceAction from "./balance";
import transferAction from "./transfer";
import deployCollectionAction from "./deployCollection";
import mintNFTAction from "./mintNFT";
import tradeAction from "./trade";
import requestFundsAction from "./requestFunds";
import resolveDomainAction from "./resolveDomain";
import getTokenDataAction from "./getTokenData";
import getTPSAction from "./getTPS";
import fetchPriceAction from "./fetchPrice";
import stakeWithJupAction from "./stakeWithJup";
import registerDomainAction from "./registerDomain";
import lendAssetAction from "./lendAsset";
import createGibworkTaskAction from "./createGibworkTask";
import resolveSolDomainAction from "./resolveSolDomain";
import pythFetchPriceAction from "./pythFetchPrice";
import getOwnedDomainsForTLDAction from "./getOwnedDomainsForTLD";
import getPrimaryDomainAction from "./getPrimaryDomain";
import getAllDomainsTLDsAction from "./getAllDomainsTLDs";
import getOwnedAllDomainsAction from "./getOwnedAllDomains";
import createImageAction from "./createImage";
import getMainAllDomainsDomainAction from "./getMainAllDomainsDomain";
import getAllRegisteredAllDomainsAction from "./getAllRegisteredAllDomains";
import raydiumCreateCpmmAction from "./raydiumCreateCpmm";
import raydiumCreateAmmV4Action from "./raydiumCreateAmmV4";
import createOrcaSingleSidedWhirlpoolAction from "./createOrcaSingleSidedWhirlpool";
import launchPumpfunTokenAction from "./launchPumpfunToken";
export const ACTIONS = {
"DEPLOY_TOKEN_ACTION" : deployTokenAction,
"BALANCE_ACTION" : balanceAction,
"TRANSFER_ACTION" : transferAction,
"DEPLOY_COLLECTION_ACTION" : deployCollectionAction,
"MINT_NFT_ACTION" : mintNFTAction,
"TRADE_ACTION" : tradeAction,
"REQUEST_FUNDS_ACTION" : requestFundsAction,
"RESOLVE_DOMAIN_ACTION" : resolveDomainAction,
"GET_TOKEN_DATA_ACTION" : getTokenDataAction,
"GET_TPS_ACTION" : getTPSAction,
"FETCH_PRICE_ACTION" : fetchPriceAction,
"STAKE_WITH_JUP_ACTION" : stakeWithJupAction,
"REGISTER_DOMAIN_ACTION" : registerDomainAction,
"LEND_ASSET_ACTION" : lendAssetAction,
"CREATE_GIBWORK_TASK_ACTION" : createGibworkTaskAction,
"RESOLVE_SOL_DOMAIN_ACTION" : resolveSolDomainAction,
"PYTH_FETCH_PRICE_ACTION" : pythFetchPriceAction,
"GET_OWNED_DOMAINS_FOR_TLD_ACTION" : getOwnedDomainsForTLDAction,
"GET_PRIMARY_DOMAIN_ACTION" : getPrimaryDomainAction,
"GET_ALL_DOMAINS_TLDS_ACTION" : getAllDomainsTLDsAction,
"GET_OWNED_ALL_DOMAINS_ACTION" : getOwnedAllDomainsAction,
"CREATE_IMAGE_ACTION" : createImageAction,
"GET_MAIN_ALL_DOMAINS_DOMAIN_ACTION" : getMainAllDomainsDomainAction,
"GET_ALL_REGISTERED_ALL_DOMAINS_ACTION" : getAllRegisteredAllDomainsAction,
"RAYDIUM_CREATE_CPMM_ACTION" : raydiumCreateCpmmAction,
"RAYDIUM_CREATE_AMM_V4_ACTION" : raydiumCreateAmmV4Action,
"CREATE_ORCA_SINGLE_SIDED_WHIRLPOOL_ACTION" : createOrcaSingleSidedWhirlpoolAction,
"LAUNCH_PUMPFUN_TOKEN_ACTION" : launchPumpfunTokenAction,
};
export type { Action, ActionExample, Handler } from "../types/action";

View File

@@ -0,0 +1,106 @@
import { Action } from "../types/action";
import { SolanaAgentKit } from "../agent";
import { z } from "zod";
import { launchPumpFunToken } from "../tools";
const launchPumpfunTokenAction: Action = {
name: "LAUNCH_PUMPFUN_TOKEN",
similes: [
"create pumpfun token",
"launch token on pumpfun",
"deploy pumpfun token",
"create meme token",
"launch memecoin",
"create pump token",
],
description:
"Launch a new token on Pump.fun with customizable metadata and initial liquidity",
examples: [
[
{
input: {
tokenName: "Sample Token",
tokenTicker: "SMPL",
description: "A sample token for demonstration",
imageUrl: "https://example.com/token.png",
twitter: "@sampletoken",
telegram: "t.me/sampletoken",
website: "https://sampletoken.com",
initialLiquiditySOL: 0.1,
slippageBps: 10,
priorityFee: 0.0001,
},
output: {
status: "success",
signature: "2ZE7Rz...",
mint: "7nxQB...",
metadataUri: "https://arweave.net/...",
message: "Successfully launched token on Pump.fun",
},
explanation:
"Launch a new token with custom metadata and 0.1 SOL initial liquidity",
},
],
],
schema: z.object({
tokenName: z.string().min(1).max(32).describe("Name of the token"),
tokenTicker: z
.string()
.min(2)
.max(10)
.describe("Ticker symbol of the token"),
description: z
.string()
.min(1)
.max(1000)
.describe("Description of the token"),
imageUrl: z.string().url().describe("URL of the token image"),
twitter: z.string().optional().describe("Twitter handle (optional)"),
telegram: z.string().optional().describe("Telegram group link (optional)"),
website: z.string().url().optional().describe("Website URL (optional)"),
initialLiquiditySOL: z
.number()
.min(0.0001)
.default(0.0001)
.describe("Initial liquidity in SOL"),
slippageBps: z
.number()
.min(1)
.max(1000)
.default(5)
.describe("Slippage tolerance in basis points"),
priorityFee: z
.number()
.min(0.00001)
.default(0.00005)
.describe("Priority fee in SOL"),
}),
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
try {
const { tokenName, tokenTicker, description, imageUrl } = input;
const result = await launchPumpFunToken(
agent,
tokenName,
tokenTicker,
description,
imageUrl,
input,
);
return {
status: "success",
signature: result.signature,
mint: result.mint,
metadataUri: result.metadataUri,
message: "Successfully launched token on Pump.fun",
};
} catch (error: any) {
return {
status: "error",
message: `Failed to launch token: ${error.message}`,
};
}
},
};
export default launchPumpfunTokenAction;

55
src/actions/lendAsset.ts Normal file
View File

@@ -0,0 +1,55 @@
import { Action } from "../types/action";
import { SolanaAgentKit } from "../agent";
import { z } from "zod";
import { lendAsset } from "../tools";
const lendAssetAction: Action = {
name: "LEND_ASSET",
similes: [
"lend usdc",
"deposit for yield",
"earn yield",
"lend with lulo",
"deposit usdc",
"lending",
],
description: "Lend USDC tokens to earn yield using Lulo protocol",
examples: [
[
{
input: {
amount: 100,
},
output: {
status: "success",
signature: "4xKpN2...",
message: "Successfully lent 100 USDC",
},
explanation: "Lend 100 USDC to earn yield on Lulo",
},
],
],
schema: z.object({
amount: z.number().positive().describe("Amount of USDC to lend"),
}),
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
try {
const amount = input.amount as number;
const response = await lendAsset(agent, amount);
return {
status: "success",
signature: response,
message: `Successfully lent ${amount} USDC`,
};
} catch (error: any) {
return {
status: "error",
message: `Lending failed: ${error.message}`,
};
}
},
};
export default lendAssetAction;

90
src/actions/mintNFT.ts Normal file
View File

@@ -0,0 +1,90 @@
import { PublicKey } from "@solana/web3.js";
import { Action } from "../types/action";
import { SolanaAgentKit } from "../agent";
import { z } from "zod";
import { mintCollectionNFT } from "../tools";
const mintNFTAction: Action = {
name: "MINT_NFT",
similes: [
"mint nft",
"create nft",
"mint token",
"create token",
"add nft to collection",
],
description: `Mint a new NFT in a collection on Solana blockchain.`,
examples: [
[
{
input: {
collectionMint: "J1S9H3QjnRtBbbuD4HjPV6RpRhwuk4zKbxsnCHuTgh9w",
name: "My NFT",
uri: "https://example.com/nft.json",
},
output: {
status: "success",
message: "NFT minted successfully",
mintAddress: "7nE9GvcwsqzYxmJLSrYmSB1V1YoJWVK1KWzAcWAzjXkN",
metadata: {
name: "My NFT",
uri: "https://example.com/nft.json",
},
recipient: "7nE9GvcwsqzYxmJLSrYmSB1V1YoJWVK1KWzAcWAzjXkN",
},
explanation: "Mint an NFT to the default wallet",
},
],
[
{
input: {
collectionMint: "J1S9H3QjnRtBbbuD4HjPV6RpRhwuk4zKbxsnCHuTgh9w",
name: "Gift NFT",
uri: "https://example.com/gift.json",
recipient: "9aUn5swQzUTRanaaTwmszxiv89cvFwUCjEBv1vZCoT1u",
},
output: {
status: "success",
message: "NFT minted successfully",
mintAddress: "8nE9GvcwsqzYxmJLSrYmSB1V1YoJWVK1KWzAcWAzjXkM",
metadata: {
name: "Gift NFT",
uri: "https://example.com/gift.json",
},
recipient: "9aUn5swQzUTRanaaTwmszxiv89cvFwUCjEBv1vZCoT1u",
},
explanation: "Mint an NFT to a specific recipient",
},
],
],
schema: z.object({
collectionMint: z.string().min(32, "Invalid collection mint address"),
name: z.string().min(1, "Name is required"),
uri: z.string().url("URI must be a valid URL"),
recipient: z.string().min(32, "Invalid recipient address"),
}),
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
const result = await mintCollectionNFT(
agent,
new PublicKey(input.collectionMint),
{
name: input.name,
uri: input.uri,
},
input.recipient ? new PublicKey(input.recipient) : undefined,
);
return {
status: "success",
message: "NFT minted successfully",
mintAddress: result.mint.toString(),
metadata: {
name: input.name,
uri: input.uri,
},
recipient: input.recipient || result.mint.toString(),
};
},
};
export default mintNFTAction;

View File

@@ -0,0 +1,56 @@
import { Action } from "../types/action";
import { SolanaAgentKit } from "../agent";
import { z } from "zod";
import { pythFetchPrice } from "../tools";
const pythFetchPriceAction: Action = {
name: "PYTH_FETCH_PRICE",
similes: [
"get pyth price",
"check pyth price",
"pyth oracle price",
"fetch from pyth",
"pyth price feed",
"oracle price",
],
description: "Fetch the current price from a Pyth oracle price feed",
examples: [
[
{
input: {
priceFeedId: "Gnt27xtC473ZT2Mw5u8wZ68Z3gULkSTb5DuxJy7eJotD", // SOL/USD price feed
},
output: {
status: "success",
price: "23.45",
message: "Current price: $23.45",
},
explanation: "Get the current SOL/USD price from Pyth oracle",
},
],
],
schema: z.object({
priceFeedId: z
.string()
.min(1)
.describe("The Pyth price feed ID to fetch the price from"),
}),
handler: async (_agent: SolanaAgentKit, input: Record<string, any>) => {
try {
const priceFeedId = input.tokenId as string;
const priceStr = await pythFetchPrice(priceFeedId);
return {
status: "success",
price: priceStr,
message: `Current price: $${priceStr}`,
};
} catch (error: any) {
return {
status: "error",
message: `Failed to fetch price from Pyth: ${error.message}`,
};
}
},
};
export default pythFetchPriceAction;

View File

@@ -0,0 +1,91 @@
import { Action } from "../types/action";
import { SolanaAgentKit } from "../agent";
import { z } from "zod";
import { PublicKey } from "@solana/web3.js";
import BN from "bn.js";
import { raydiumCreateAmmV4 } from "../tools";
const raydiumCreateAmmV4Action: Action = {
name: "RAYDIUM_CREATE_AMM_V4",
similes: [
"create raydium v4 pool",
"setup raydium v4 liquidity pool",
"initialize raydium v4 amm",
"create raydium v4 market maker",
"setup raydium v4 pool",
"create raydium v4 trading pair",
],
description:
"Create a new AMM V4 pool on Raydium with advanced features and improved efficiency",
examples: [
[
{
input: {
baseMint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", // USDC
quoteMint: "So11111111111111111111111111111111111111112", // SOL
baseAmount: 1000,
quoteAmount: 10,
startPrice: 100, // 1 SOL = 100 USDC
openTime: 1672531200, // Unix timestamp
},
output: {
status: "success",
signature: "2ZE7Rz...",
poolId: "7nxQB...",
message: "Successfully created Raydium AMM V4 pool",
},
explanation:
"Create a USDC-SOL V4 pool with initial liquidity and price",
},
],
],
schema: z.object({
baseMint: z.string().min(1).describe("The base token mint address"),
quoteMint: z.string().min(1).describe("The quote token mint address"),
baseAmount: z
.number()
.positive()
.describe("Initial base token amount to provide as liquidity"),
quoteAmount: z
.number()
.positive()
.describe("Initial quote token amount to provide as liquidity"),
startPrice: z
.number()
.positive()
.describe("Initial price of quote token in base token units"),
openTime: z
.number()
.positive()
.describe("Unix timestamp when trading should start"),
}),
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
try {
const marketId = new PublicKey(input.marketId);
const baseAmount = new BN(input.baseAmount);
const quoteAmount = new BN(input.quoteAmount);
const startTime = new BN(input.startTime);
const txId = await raydiumCreateAmmV4(
agent,
marketId,
baseAmount,
quoteAmount,
startTime,
);
return {
status: "success",
signature: txId,
message: "Successfully created Raydium AMM V4 pool",
};
} catch (error: any) {
return {
status: "error",
message: `Failed to create AMM V4 pool: ${error.message}`,
};
}
},
};
export default raydiumCreateAmmV4Action;

View File

@@ -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<string, any>) => {
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;

View File

@@ -0,0 +1,90 @@
import { Action } from "../types/action";
import { SolanaAgentKit } from "../agent";
import { z } from "zod";
import { PublicKey } from "@solana/web3.js";
import BN from "bn.js";
import { raydiumCreateCpmm } from "../tools";
const raydiumCreateCpmmAction: Action = {
name: "RAYDIUM_CREATE_CPMM",
similes: [
"create raydium pool",
"setup raydium liquidity pool",
"initialize raydium amm",
"create constant product market maker",
"setup raydium cpmm",
"create raydium trading pair",
],
description:
"Create a new Constant Product Market Maker (CPMM) pool on Raydium",
examples: [
[
{
input: {
baseMint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", // USDC
quoteMint: "So11111111111111111111111111111111111111112", // SOL
baseAmount: 1000,
quoteAmount: 10,
startTime: 1672531200, // Unix timestamp
},
output: {
status: "success",
signature: "2ZE7Rz...",
poolId: "7nxQB...",
message: "Successfully created Raydium CPMM pool",
},
explanation:
"Create a USDC-SOL pool with initial liquidity of 1000 USDC and 10 SOL",
},
],
],
schema: z.object({
baseMint: z.string().min(1).describe("The base token mint address"),
quoteMint: z.string().min(1).describe("The quote token mint address"),
baseAmount: z
.number()
.positive()
.describe("Initial base token amount to provide as liquidity"),
quoteAmount: z
.number()
.positive()
.describe("Initial quote token amount to provide as liquidity"),
startTime: z
.number()
.positive()
.describe("Unix timestamp when trading should start"),
}),
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
try {
const mintA = new PublicKey(input.baseMint);
const mintB = new PublicKey(input.quoteMint);
const configId = new PublicKey(input.configId);
const mintAAmount = new BN(input.baseAmount);
const mintBAmount = new BN(input.quoteAmount);
const startTime = new BN(input.startTime);
const txId = await raydiumCreateCpmm(
agent,
mintA,
mintB,
configId,
mintAAmount,
mintBAmount,
startTime,
);
return {
status: "success",
signature: txId,
message: "Successfully created Raydium CPMM pool",
};
} catch (error: any) {
return {
status: "error",
message: `Failed to create CPMM pool: ${error.message}`,
};
}
},
};
export default raydiumCreateCpmmAction;

View File

@@ -0,0 +1,63 @@
import { Action } from "../types/action";
import { SolanaAgentKit } from "../agent";
import { z } from "zod";
import { registerDomain } from "../tools";
const registerDomainAction: Action = {
name: "REGISTER_DOMAIN",
similes: [
"register domain",
"buy domain",
"get domain name",
"register .sol",
"purchase domain",
"domain registration",
],
description: "Register a .sol domain name using Bonfida Name Service",
examples: [
[
{
input: {
name: "mydomain",
spaceKB: 1,
},
output: {
status: "success",
signature: "2ZE7Rz...",
message: "Successfully registered mydomain.sol",
},
explanation: "Register a new .sol domain with 1KB storage space",
},
],
],
schema: z.object({
name: z.string().min(1).describe("Domain name to register (without .sol)"),
spaceKB: z
.number()
.min(1)
.max(10)
.default(1)
.describe("Space allocation in KB (max 10KB)"),
}),
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
try {
const name = input.name as string;
const spaceKB = (input.spaceKB as number) || 1;
const signature = await registerDomain(agent, name, spaceKB);
return {
status: "success",
signature,
message: `Successfully registered ${name}.sol`,
};
} catch (error: any) {
return {
status: "error",
message: `Domain registration failed: ${error.message}`,
};
}
},
};
export default registerDomainAction;

View File

@@ -0,0 +1,41 @@
import { Action } from "../types/action";
import { SolanaAgentKit } from "../agent";
import { z } from "zod";
import { request_faucet_funds } from "../tools";
const requestFundsAction: Action = {
name: "REQUEST_FUNDS",
similes: [
"request sol",
"get test sol",
"use faucet",
"request test tokens",
"get devnet sol",
],
description: "Request SOL from Solana faucet (devnet/testnet only)",
examples: [
[
{
input: {},
output: {
status: "success",
message: "Successfully requested faucet funds",
network: "devnet.solana.com",
},
explanation: "Request SOL from the devnet faucet",
},
],
],
schema: z.object({}), // No input parameters required
handler: async (agent: SolanaAgentKit, _input: Record<string, any>) => {
await request_faucet_funds(agent);
return {
status: "success",
message: "Successfully requested faucet funds",
network: agent.connection.rpcEndpoint.split("/")[2],
};
},
};
export default requestFundsAction;

View File

@@ -0,0 +1,51 @@
import { Action } from "../types/action";
import { SolanaAgentKit } from "../agent";
import { z } from "zod";
import { resolveAllDomains } from "../tools";
const resolveDomainAction: Action = {
name: "RESOLVE_ALL_DOMAINS",
similes: [
"resolve domain",
"lookup domain",
"get domain owner",
"check domain",
"find domain owner",
],
description: "Resolve a Solana domain name to get its owner's public key",
examples: [
[
{
input: {
domain: "example.sol",
},
output: {
status: "success",
owner: "7nxQB...",
},
explanation: "Resolve a .sol domain name to get the owner's public key",
},
],
],
schema: z.object({
domain: z.string().min(1).describe("The domain name to resolve"),
}),
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
try {
const domain = input.domain as string;
const tld = await resolveAllDomains(agent, domain);
return {
status: "success",
owner: tld,
message: `Successfully resolved domain ${domain}`,
};
} catch (error: any) {
return {
status: "error",
message: `Failed to resolve domain: ${error.message}`,
};
}
},
};
export default resolveDomainAction;

View File

@@ -0,0 +1,59 @@
import { Action } from "../types/action";
import { SolanaAgentKit } from "../agent";
import { z } from "zod";
import { resolveSolDomain } from "../tools";
const resolveSolDomainAction: Action = {
name: "RESOLVE_SOL_DOMAIN",
similes: [
"resolve sol domain",
"lookup sol domain",
"get sol domain owner",
"check sol domain",
"find sol domain owner",
"resolve .sol",
],
description:
"Resolve a .sol domain to its corresponding Solana wallet address using Bonfida Name Service",
examples: [
[
{
input: {
domain: "vitalik.sol",
},
output: {
status: "success",
owner: "7nxQB...",
message: "Successfully resolved vitalik.sol",
},
explanation: "Resolve a .sol domain to get the owner's wallet address",
},
],
],
schema: z.object({
domain: z
.string()
.min(1)
.describe("The .sol domain to resolve (with or without .sol suffix)"),
}),
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
try {
const domain = input.domain as string;
const res = await resolveSolDomain(agent, domain);
return {
status: "success",
owner: res.toString(),
message: `Successfully resolved ${res}`,
};
} catch (error: any) {
return {
status: "error",
message: `Failed to resolve domain: ${error.message}`,
};
}
},
};
export default resolveSolDomainAction;

View File

@@ -0,0 +1,55 @@
import { Action } from "../types/action";
import { SolanaAgentKit } from "../agent";
import { z } from "zod";
import { stakeWithJup } from "../tools";
const stakeWithJupAction: Action = {
name: "STAKE_WITH_JUPITER",
similes: [
"stake sol",
"stake with jupiter",
"jup staking",
"stake with jup",
"liquid staking",
"get jupsol",
],
description:
"Stake SOL tokens with Jupiter's liquid staking protocol to receive jupSOL",
examples: [
[
{
input: {
amount: 1.5,
},
output: {
status: "success",
signature: "5KtPn3...",
message: "Successfully staked 1.5 SOL for jupSOL",
},
explanation: "Stake 1.5 SOL to receive jupSOL tokens",
},
],
],
schema: z.object({
amount: z.number().positive().describe("Amount of SOL to stake"),
}),
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
try {
const amount = input.amount as number;
const res = await stakeWithJup(agent, amount);
return {
status: "success",
res,
message: `Successfully staked ${amount} SOL for jupSOL`,
};
} catch (error: any) {
return {
status: "error",
message: `jupSOL staking failed: ${error.message}`,
};
}
},
};
export default stakeWithJupAction;

View File

@@ -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: "GET_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<string, any>) => {
try {
const ticker = input.ticker as string;
// Use agents 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;

85
src/actions/trade.ts Normal file
View File

@@ -0,0 +1,85 @@
import { PublicKey } from "@solana/web3.js";
import { Action } from "../types/action";
import { SolanaAgentKit } from "../agent";
import { z } from "zod";
import { trade } from "../tools";
const tradeAction: Action = {
name: "TRADE",
similes: [
"swap tokens",
"exchange tokens",
"trade tokens",
"convert tokens",
"swap sol",
],
description: `This tool can be used to swap tokens to another token (It uses Jupiter Exchange).`,
examples: [
[
{
input: {
outputMint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
inputAmount: 1,
},
output: {
status: "success",
message: "Trade executed successfully",
transaction:
"5UfgJ5vVZxUxefDGqzqkVLHzHxVTyYH9StYyHKgvHYmXJgqJKxEqy9k4Rz9LpXrHF9kUZB7",
inputAmount: 1,
inputToken: "SOL",
outputToken: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
},
explanation: "Swap 1 SOL for USDC",
},
],
[
{
input: {
outputMint: "So11111111111111111111111111111111111111112",
inputAmount: 100,
inputMint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
slippageBps: 100,
},
output: {
status: "success",
message: "Trade executed successfully",
transaction:
"4VfgJ5vVZxUxefDGqzqkVLHzHxVTyYH9StYyHKgvHYmXJgqJKxEqy9k4Rz9LpXrHF9kUZB7",
inputAmount: 100,
inputToken: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
outputToken: "So11111111111111111111111111111111111111112",
},
explanation: "Swap 100 USDC for SOL with 1% slippage",
},
],
],
schema: z.object({
outputMint: z.string().min(32, "Invalid output mint address"),
inputAmount: z.number().positive("Input amount must be positive"),
inputMint: z.string().min(32, "Invalid input mint address").optional(),
slippageBps: z.number().min(0).max(10000).optional(),
}),
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
const tx = await trade(
agent,
new PublicKey(input.outputMint),
input.inputAmount,
input.inputMint
? new PublicKey(input.inputMint)
: new PublicKey("So11111111111111111111111111111111111111112"),
input.slippageBps,
);
return {
status: "success",
message: "Trade executed successfully",
transaction: tx,
inputAmount: input.inputAmount,
inputToken: input.inputMint || "SOL",
outputToken: input.outputMint,
};
},
};
export default tradeAction;

78
src/actions/transfer.ts Normal file
View File

@@ -0,0 +1,78 @@
import { PublicKey } from "@solana/web3.js";
import { Action } from "../types/action";
import { SolanaAgentKit } from "../agent";
import { z } from "zod";
import { transfer } from "../tools";
const transferAction: Action = {
name: "TRANSFER",
similes: [
"send tokens",
"transfer funds",
"send money",
"send sol",
"transfer tokens",
],
description: `Transfer tokens or SOL to another address (also called as wallet address).`,
examples: [
[
{
input: {
to: "8x2dR8Mpzuz2YqyZyZjUbYWKSWesBo5jMx2Q9Y86udVk",
amount: 1,
},
output: {
status: "success",
message: "Transfer completed successfully",
amount: 1,
recipient: "8x2dR8Mpzuz2YqyZyZjUbYWKSWesBo5jMx2Q9Y86udVk",
token: "SOL",
transaction:
"5UfgJ5vVZxUxefDGqzqkVLHzHxVTyYH9StYyHKgvHYmXJgqJKxEqy9k4Rz9LpXrHF9kUZB7",
},
explanation: "Transfer 1 SOL to the recipient address",
},
],
[
{
input: {
to: "8x2dR8Mpzuz2YqyZyZjUbYWKSWesBo5jMx2Q9Y86udVk",
amount: 100,
mint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
},
output: {
status: "success",
message: "Transfer completed successfully",
amount: 100,
recipient: "8x2dR8Mpzuz2YqyZyZjUbYWKSWesBo5jMx2Q9Y86udVk",
token: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
transaction:
"4VfgJ5vVZxUxefDGqzqkVLHzHxVTyYH9StYyHKgvHYmXJgqJKxEqy9k4Rz9LpXrHF9kUZB7",
},
explanation: "Transfer 100 USDC tokens to the recipient address",
},
],
],
schema: z.object({
to: z.string().min(32, "Invalid Solana address"),
amount: z.number().positive("Amount must be positive"),
mint: z.string().optional(),
}),
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
const recipient = new PublicKey(input.to);
const mintAddress = input.mint ? new PublicKey(input.mint) : undefined;
const tx = await transfer(agent, recipient, input.amount, mintAddress);
return {
status: "success",
message: "Transfer completed successfully",
amount: input.amount,
recipient: input.to,
token: input.mint || "SOL",
transaction: tx,
};
},
};
export default transferAction;

View File

@@ -2,6 +2,7 @@ import { Connection, Keypair, PublicKey } from "@solana/web3.js";
import bs58 from "bs58";
import Decimal from "decimal.js";
import { DEFAULT_OPTIONS } from "../constants";
import { Config } from "../types";
import {
deploy_collection,
deploy_token,
@@ -14,12 +15,16 @@ import {
lendAsset,
mintCollectionNFT,
openbookCreateMarket,
manifestCreateMarket,
raydiumCreateAmmV4,
raydiumCreateClmm,
raydiumCreateCpmm,
registerDomain,
request_faucet_funds,
trade,
limitOrder,
cancelAllOrders,
withdrawAll,
transfer,
getTokenDataByAddress,
getTokenDataByTicker,
@@ -43,6 +48,8 @@ import {
orcaFetchPositions,
rock_paper_scissor,
create_TipLink,
listNFTForSale,
cancelListing,
} from "../tools";
import {
@@ -64,22 +71,39 @@ import { BN } from "@coral-xyz/anchor";
* @property {Connection} connection - Solana RPC connection
* @property {Keypair} wallet - Wallet keypair for signing transactions
* @property {PublicKey} wallet_address - Public key of the wallet
* @property {Config} config - Configuration object
*/
export class SolanaAgentKit {
public connection: Connection;
public wallet: Keypair;
public wallet_address: PublicKey;
public openai_api_key: string | null;
public config: Config;
/**
* @deprecated Using openai_api_key directly in constructor is deprecated.
* Please use the new constructor with Config object instead:
* @example
* const agent = new SolanaAgentKit(privateKey, rpcUrl, {
* OPENAI_API_KEY: 'your-key'
* });
*/
constructor(private_key: string, rpc_url: string, openai_api_key: string | null);
constructor(private_key: string, rpc_url: string, config: Config);
constructor(
private_key: string,
rpc_url = "https://api.mainnet-beta.solana.com",
openai_api_key: string | null = null,
rpc_url: string,
configOrKey: Config | string | null,
) {
this.connection = new Connection(rpc_url);
this.connection = new Connection(rpc_url || "https://api.mainnet-beta.solana.com");
this.wallet = Keypair.fromSecretKey(bs58.decode(private_key));
this.wallet_address = this.wallet.publicKey;
this.openai_api_key = openai_api_key;
// Handle both old and new patterns
if (typeof configOrKey === 'string' || configOrKey === null) {
this.config = { OPENAI_API_KEY: configOrKey || '' };
} else {
this.config = configOrKey;
}
}
// Tool methods
@@ -151,6 +175,23 @@ export class SolanaAgentKit {
return trade(this, outputMint, inputAmount, inputMint, slippageBps);
}
async limitOrder(
marketId: PublicKey,
quantity: number,
side: string,
price: number,
): Promise<string> {
return limitOrder(this, marketId, quantity, side, price);
}
async cancelAllOrders(marketId: PublicKey): Promise<string> {
return cancelAllOrders(this, marketId);
}
async withdrawAll(marketId: PublicKey): Promise<string> {
return withdrawAll(this, marketId);
}
async lendAssets(amount: number): Promise<string> {
return lendAsset(this, amount);
}
@@ -295,8 +336,7 @@ export class SolanaAgentKit {
return getOwnedDomainsForTLD(this, tld);
}
// eslint-disable-next-line @typescript-eslint/ban-types
async getAllDomainsTLDs(): Promise<String[]> {
async getAllDomainsTLDs(): Promise<string[]> {
return getAllDomainsTLDs(this);
}
@@ -378,6 +418,13 @@ export class SolanaAgentKit {
);
}
async manifestCreateMarket(
baseMint: PublicKey,
quoteMint: PublicKey,
): Promise<string[]> {
return manifestCreateMarket(this, baseMint, quoteMint);
}
async pythFetchPrice(priceFeedID: string): Promise<string> {
return pythFetchPrice(priceFeedID);
}
@@ -412,4 +459,12 @@ export class SolanaAgentKit {
async createTiplink(amount: number, splmintAddress?: PublicKey) {
return create_TipLink(this, amount, splmintAddress);
}
async tensorListNFT(nftMint: PublicKey, price: number): Promise<string> {
return listNFTForSale(this, nftMint, price);
}
async tensorCancelListing(nftMint: PublicKey): Promise<string> {
return cancelListing(this, nftMint);
}
}

View File

@@ -22,9 +22,12 @@ export const TOKENS = {
export const DEFAULT_OPTIONS = {
SLIPPAGE_BPS: 300,
TOKEN_DECIMALS: 9,
RERERRAL_FEE: 200,
} as const;
/**
* Jupiter API URL
*/
export const JUP_API = "https://quote-api.jup.ag/v6";
export const JUP_REFERRAL_ADDRESS =
"REFER4ZgmyYx9c6He5XfaTMiGfdLwRnkV4RPp9t9iF3";

View File

@@ -6,3 +6,7 @@ export { SolanaAgentKit, createSolanaTools, createVercelAITools };
// Optional: Export types that users might need
export * from "./types";
// Export action system
export { ACTIONS } from "./actions";
export * from "./utils/actionExecutor";

View File

@@ -46,7 +46,7 @@ export class SolanaBalanceTool extends Tool {
export class SolanaBalanceOtherTool extends Tool {
name = "solana_balance_other";
description = `Get the balance of a Solana wallet or token account different from the agent's wallet.
description = `Get the balance of a Solana wallet or token account which is different from the agent's wallet.
If no tokenAddress is provided, the SOL balance of the wallet will be returned.
@@ -306,6 +306,114 @@ export class SolanaTradeTool extends Tool {
}
}
export class SolanaLimitOrderTool extends Tool {
name = "solana_limit_order";
description = `This tool can be used to place limit orders using Manifest.
Inputs ( input is a JSON string ):
marketId: PublicKey, eg "ENhU8LsaR7vDD2G1CsWcsuSGNrih9Cv5WZEk7q9kPapQ" for SOL/USDC (required)
quantity: number, eg 1 or 0.01 (required)
side: string, eg "Buy" or "Sell" (required)
price: number, in tokens eg 200 for SOL/USDC (required)`;
constructor(private solanaKit: SolanaAgentKit) {
super();
}
protected async _call(input: string): Promise<string> {
try {
const parsedInput = JSON.parse(input);
const tx = await this.solanaKit.limitOrder(
new PublicKey(parsedInput.marketId),
parsedInput.quantity,
parsedInput.side,
parsedInput.price,
);
return JSON.stringify({
status: "success",
message: "Trade executed successfully",
transaction: tx,
marketId: parsedInput.marketId,
quantity: parsedInput.quantity,
side: parsedInput.side,
price: parsedInput.price,
});
} catch (error: any) {
return JSON.stringify({
status: "error",
message: error.message,
code: error.code || "UNKNOWN_ERROR",
});
}
}
}
export class SolanaCancelAllOrdersTool extends Tool {
name = "solana_cancel_all_orders";
description = `This tool can be used to cancel all orders from a Manifest market.
Input ( input is a JSON string ):
marketId: string, eg "ENhU8LsaR7vDD2G1CsWcsuSGNrih9Cv5WZEk7q9kPapQ" for SOL/USDC (required)`;
constructor(private solanaKit: SolanaAgentKit) {
super();
}
protected async _call(input: string): Promise<string> {
try {
const marketId = new PublicKey(input.trim());
const tx = await this.solanaKit.cancelAllOrders(marketId);
return JSON.stringify({
status: "success",
message: "Cancel orders successfully",
transaction: tx,
marketId,
});
} catch (error: any) {
return JSON.stringify({
status: "error",
message: error.message,
code: error.code || "UNKNOWN_ERROR",
});
}
}
}
export class SolanaWithdrawAllTool extends Tool {
name = "solana_withdraw_all";
description = `This tool can be used to withdraw all funds from a Manifest market.
Input ( input is a JSON string ):
marketId: string, eg "ENhU8LsaR7vDD2G1CsWcsuSGNrih9Cv5WZEk7q9kPapQ" for SOL/USDC (required)`;
constructor(private solanaKit: SolanaAgentKit) {
super();
}
protected async _call(input: string): Promise<string> {
try {
const marketId = new PublicKey(input.trim());
const tx = await this.solanaKit.withdrawAll(marketId);
return JSON.stringify({
status: "success",
message: "Withdrew successfully",
transaction: tx,
marketId,
});
} catch (error: any) {
return JSON.stringify({
status: "error",
message: error.message,
code: error.code || "UNKNOWN_ERROR",
});
}
}
}
export class SolanaRequestFundsTool extends Tool {
name = "solana_request_funds";
description = "Request SOL from Solana faucet (devnet/testnet only)";
@@ -796,7 +904,7 @@ export class SolanaCompressedAirdropTool extends Tool {
}
}
export class SolanaClosePostition extends Tool {
export class SolanaClosePosition extends Tool {
name = "orca_close_position";
description = `Closes an existing liquidity position in an Orca Whirlpool. This function fetches the position
details using the provided mint address and closes the position with a 1% slippage.
@@ -1078,7 +1186,7 @@ export class SolanaOrcaOpenSingleSidedPosition extends Tool {
export class SolanaRaydiumCreateAmmV4 extends Tool {
name = "raydium_create_ammV4";
description = `Raydium's Legacy AMM that requiers an OpenBook marketID
description = `Raydium's Legacy AMM that requires an OpenBook marketID
Inputs (input is a json string):
marketId: string (required)
@@ -1104,7 +1212,7 @@ export class SolanaRaydiumCreateAmmV4 extends Tool {
return JSON.stringify({
status: "success",
message: "Create raydium amm v4 pool successfully",
message: "Raydium amm v4 pool created successfully",
transaction: tx,
});
} catch (error: any) {
@@ -1149,7 +1257,7 @@ export class SolanaRaydiumCreateClmm extends Tool {
return JSON.stringify({
status: "success",
message: "Create raydium clmm pool successfully",
message: "Raydium clmm pool created successfully",
transaction: tx,
});
} catch (error: any) {
@@ -1197,7 +1305,7 @@ export class SolanaRaydiumCreateCpmm extends Tool {
return JSON.stringify({
status: "success",
message: "Create raydium cpmm pool successfully",
message: "Raydium cpmm pool created successfully",
transaction: tx,
});
} catch (error: any) {
@@ -1239,7 +1347,7 @@ export class SolanaOpenbookCreateMarket extends Tool {
return JSON.stringify({
status: "success",
message: "Create openbook market successfully",
message: "Openbook market created successfully",
transaction: tx,
});
} catch (error: any) {
@@ -1252,6 +1360,44 @@ export class SolanaOpenbookCreateMarket extends Tool {
}
}
export class SolanaManifestCreateMarket extends Tool {
name = "solana_manifest_create_market";
description = `Manifest market
Inputs (input is a json string):
baseMint: string (required)
quoteMint: string (required)
`;
constructor(private solanaKit: SolanaAgentKit) {
super();
}
async _call(input: string): Promise<string> {
try {
const inputFormat = JSON.parse(input);
const tx = await this.solanaKit.manifestCreateMarket(
new PublicKey(inputFormat.baseMint),
new PublicKey(inputFormat.quoteMint),
);
return JSON.stringify({
status: "success",
message: "Create manifest market successfully",
transaction: tx[0],
marketId: tx[1],
});
} catch (error: any) {
return JSON.stringify({
status: "error",
message: error.message,
code: error.code || "UNKNOWN_ERROR",
});
}
}
}
export class SolanaPythFetchPrice extends Tool {
name = "solana_pyth_fetch_price";
description = `Fetch the price of a given price feed from Pyth's Hermes service
@@ -1590,6 +1736,95 @@ export class SolanaTipLinkTool extends Tool {
}
}
export class SolanaListNFTForSaleTool extends Tool {
name = "solana_list_nft_for_sale";
description = `List an NFT for sale on Tensor Trade.
Inputs (input is a JSON string):
nftMint: string, the mint address of the NFT (required)
price: number, price in SOL (required)`;
constructor(private solanaKit: SolanaAgentKit) {
super();
}
protected async _call(input: string): Promise<string> {
try {
const parsedInput = JSON.parse(input);
// Validate NFT ownership first
const nftAccount =
await this.solanaKit.connection.getTokenAccountsByOwner(
this.solanaKit.wallet_address,
{ mint: new PublicKey(parsedInput.nftMint) },
);
if (nftAccount.value.length === 0) {
return JSON.stringify({
status: "error",
message:
"NFT not found in wallet. Please make sure you own this NFT.",
code: "NFT_NOT_FOUND",
});
}
const tx = await this.solanaKit.tensorListNFT(
new PublicKey(parsedInput.nftMint),
parsedInput.price,
);
return JSON.stringify({
status: "success",
message: "NFT listed for sale successfully",
transaction: tx,
price: parsedInput.price,
nftMint: parsedInput.nftMint,
});
} catch (error: any) {
return JSON.stringify({
status: "error",
message: error.message,
code: error.code || "UNKNOWN_ERROR",
});
}
}
}
export class SolanaCancelNFTListingTool extends Tool {
name = "solana_cancel_nft_listing";
description = `Cancel an NFT listing on Tensor Trade.
Inputs (input is a JSON string):
nftMint: string, the mint address of the NFT (required)`;
constructor(private solanaKit: SolanaAgentKit) {
super();
}
protected async _call(input: string): Promise<string> {
try {
const parsedInput = JSON.parse(input);
const tx = await this.solanaKit.tensorCancelListing(
new PublicKey(parsedInput.nftMint),
);
return JSON.stringify({
status: "success",
message: "NFT listing cancelled successfully",
transaction: tx,
nftMint: parsedInput.nftMint,
});
} catch (error: any) {
return JSON.stringify({
status: "error",
message: error.message,
code: error.code || "UNKNOWN_ERROR",
});
}
}
}
export function createSolanaTools(solanaKit: SolanaAgentKit) {
return [
new SolanaBalanceTool(solanaKit),
@@ -1616,7 +1851,11 @@ export function createSolanaTools(solanaKit: SolanaAgentKit) {
new SolanaRaydiumCreateClmm(solanaKit),
new SolanaRaydiumCreateCpmm(solanaKit),
new SolanaOpenbookCreateMarket(solanaKit),
new SolanaClosePostition(solanaKit),
new SolanaManifestCreateMarket(solanaKit),
new SolanaLimitOrderTool(solanaKit),
new SolanaCancelAllOrdersTool(solanaKit),
new SolanaWithdrawAllTool(solanaKit),
new SolanaClosePosition(solanaKit),
new SolanaOrcaCreateCLMM(solanaKit),
new SolanaOrcaCreateSingleSideLiquidityPool(solanaKit),
new SolanaOrcaFetchPositions(solanaKit),
@@ -1632,5 +1871,7 @@ export function createSolanaTools(solanaKit: SolanaAgentKit) {
new SolanaCreateGibworkTask(solanaKit),
new SolanaRockPaperScissorsTool(solanaKit),
new SolanaTipLinkTool(solanaKit),
new SolanaListNFTForSaleTool(solanaKit),
new SolanaCancelNFTListingTool(solanaKit),
];
}

View File

@@ -0,0 +1,37 @@
import {
PublicKey,
sendAndConfirmTransaction,
Transaction,
} from "@solana/web3.js";
import { SolanaAgentKit } from "../index";
import { ManifestClient } from "@cks-systems/manifest-sdk";
/**
* Cancels all orders from Manifest
* @param agent SolanaAgentKit instance
* @param marketId Public key for the manifest market
* @returns Transaction signature
*/
export async function cancelAllOrders(
agent: SolanaAgentKit,
marketId: PublicKey,
): Promise<string> {
try {
const mfxClient = await ManifestClient.getClientForMarket(
agent.connection,
marketId,
agent.wallet,
);
const cancelAllOrdersIx = await mfxClient.cancelAllIx();
const signature = await sendAndConfirmTransaction(
agent.connection,
new Transaction().add(cancelAllOrdersIx),
[agent.wallet],
);
return signature;
} catch (error: any) {
throw new Error(`Cancel all orders failed: ${error.message}`);
}
}

View File

@@ -16,12 +16,12 @@ export async function create_image(
n: number = 1,
) {
try {
if (!agent.openai_api_key) {
if (!agent.config.OPENAI_API_KEY) {
throw new Error("OpenAI API key not found in agent configuration");
}
const openai = new OpenAI({
apiKey: agent.openai_api_key,
apiKey: agent.config.OPENAI_API_KEY,
});
const response = await openai.images.generate({

View File

@@ -8,11 +8,10 @@ import { getAllTld } from "@onsol/tldparser";
*/
export async function getAllDomainsTLDs(
agent: SolanaAgentKit,
// eslint-disable-next-line @typescript-eslint/ban-types
): Promise<String[]> {
): Promise<string[]> {
try {
const tlds = await getAllTld(agent.connection);
return tlds.map((tld) => tld.tld);
return tlds.map((tld) => String(tld.tld));
} catch (error: any) {
throw new Error(`Failed to fetch TLDs: ${error.message}`);
}

View File

@@ -6,6 +6,9 @@ export * from "./get_balance_other";
export * from "./mint_nft";
export * from "./transfer";
export * from "./trade";
export * from "./limit_order";
export * from "./cancel_all_orders";
export * from "./withdraw_all";
export * from "./register_domain";
export * from "./resolve_sol_domain";
export * from "./get_primary_domain";
@@ -40,9 +43,12 @@ export * from "./raydium_create_ammV4";
export * from "./raydium_create_clmm";
export * from "./raydium_create_cpmm";
export * from "./openbook_create_market";
export * from "./manifest_create_market";
export * from "./pyth_fetch_price";
export * from "./create_gibwork_task";
export * from "./rock_paper_scissor";
export * from "./create_tiplinks";
export * from "./tensor_trade";

61
src/tools/limit_order.ts Normal file
View File

@@ -0,0 +1,61 @@
import {
PublicKey,
Transaction,
sendAndConfirmTransaction,
TransactionInstruction,
} from "@solana/web3.js";
import { SolanaAgentKit } from "../index";
import {
ManifestClient,
WrapperPlaceOrderParamsExternal,
} from "@cks-systems/manifest-sdk";
import { OrderType } from "@cks-systems/manifest-sdk/client/ts/src/wrapper/types/OrderType";
/**
* Place limit orders using Manifest
* @param agent SolanaAgentKit instance
* @param marketId Public key for the manifest market
* @param quantity Amount to trade in tokens
* @param side Buy or Sell
* @param price Price in tokens ie. SOL/USDC
* @returns Transaction signature
*/
export async function limitOrder(
agent: SolanaAgentKit,
marketId: PublicKey,
quantity: number,
side: string,
price: number,
): Promise<string> {
try {
const mfxClient = await ManifestClient.getClientForMarket(
agent.connection,
marketId,
agent.wallet,
);
const orderParams: WrapperPlaceOrderParamsExternal = {
numBaseTokens: quantity,
tokenPrice: price,
isBid: side === "Buy",
lastValidSlot: 0,
orderType: OrderType.Limit,
clientOrderId: Number(Math.random() * 1000),
};
const depositPlaceOrderIx: TransactionInstruction[] =
await mfxClient.placeOrderWithRequiredDepositIx(
agent.wallet.publicKey,
orderParams,
);
const signature = await sendAndConfirmTransaction(
agent.connection,
new Transaction().add(...depositPlaceOrderIx),
[agent.wallet],
);
return signature;
} catch (error: any) {
throw new Error(`Limit Order failed: ${error.message}`);
}
}

View File

@@ -0,0 +1,43 @@
import { ManifestClient } from "@cks-systems/manifest-sdk";
import {
Keypair,
PublicKey,
sendAndConfirmTransaction,
SystemProgram,
Transaction,
TransactionInstruction,
} from "@solana/web3.js";
import { SolanaAgentKit } from "../index";
export async function manifestCreateMarket(
agent: SolanaAgentKit,
baseMint: PublicKey,
quoteMint: PublicKey,
): Promise<string[]> {
const marketKeypair: Keypair = Keypair.generate();
const FIXED_MANIFEST_HEADER_SIZE: number = 256;
const createAccountIx: TransactionInstruction = SystemProgram.createAccount({
fromPubkey: agent.wallet.publicKey,
newAccountPubkey: marketKeypair.publicKey,
space: FIXED_MANIFEST_HEADER_SIZE,
lamports: await agent.connection.getMinimumBalanceForRentExemption(
FIXED_MANIFEST_HEADER_SIZE,
),
programId: new PublicKey("MNFSTqtC93rEfYHB6hF82sKdZpUDFWkViLByLd1k1Ms"),
});
const createMarketIx = ManifestClient["createMarketIx"](
agent.wallet.publicKey,
baseMint,
quoteMint,
marketKeypair.publicKey,
);
const tx: Transaction = new Transaction();
tx.add(createAccountIx);
tx.add(createMarketIx);
const signature = await sendAndConfirmTransaction(agent.connection, tx, [
agent.wallet,
marketKeypair,
]);
return [signature, marketKeypair.publicKey.toBase58()];
}

108
src/tools/tensor_trade.ts Normal file
View File

@@ -0,0 +1,108 @@
import { SolanaAgentKit } from "../index";
import { TensorSwapSDK } from "@tensor-oss/tensorswap-sdk";
import { PublicKey, Transaction } from "@solana/web3.js";
import { AnchorProvider, Wallet } from "@coral-xyz/anchor";
import { BN } from "bn.js";
import {
getAssociatedTokenAddress,
TOKEN_PROGRAM_ID,
getAccount,
} from "@solana/spl-token";
export async function listNFTForSale(
agent: SolanaAgentKit,
nftMint: PublicKey,
price: number,
): Promise<string> {
try {
if (!PublicKey.isOnCurve(nftMint)) {
throw new Error("Invalid NFT mint address");
}
const mintInfo = await agent.connection.getAccountInfo(nftMint);
if (!mintInfo) {
throw new Error(`NFT mint ${nftMint.toString()} does not exist`);
}
const ata = await getAssociatedTokenAddress(nftMint, agent.wallet_address);
try {
const tokenAccount = await getAccount(agent.connection, ata);
if (!tokenAccount || tokenAccount.amount <= 0) {
throw new Error(`You don't own this NFT (${nftMint.toString()})`);
}
} catch (error: any) {
throw new Error(
`No token account found for mint ${nftMint.toString()}. Make sure you own this NFT.`,
);
}
const provider = new AnchorProvider(
agent.connection,
new Wallet(agent.wallet),
AnchorProvider.defaultOptions(),
);
const tensorSwapSdk = new TensorSwapSDK({ provider });
const priceInLamports = new BN(price * 1e9);
const nftSource = await getAssociatedTokenAddress(
nftMint,
agent.wallet_address,
);
const { tx } = await tensorSwapSdk.list({
nftMint,
nftSource,
owner: agent.wallet_address,
price: priceInLamports,
tokenProgram: TOKEN_PROGRAM_ID,
payer: agent.wallet_address,
});
const transaction = new Transaction();
transaction.add(...tx.ixs);
return await agent.connection.sendTransaction(transaction, [
agent.wallet,
...tx.extraSigners,
]);
} catch (error: any) {
console.error("Full error details:", error);
throw error;
}
}
export async function cancelListing(
agent: SolanaAgentKit,
nftMint: PublicKey,
): Promise<string> {
const provider = new AnchorProvider(
agent.connection,
new Wallet(agent.wallet),
AnchorProvider.defaultOptions(),
);
const tensorSwapSdk = new TensorSwapSDK({ provider });
const nftDest = await getAssociatedTokenAddress(
nftMint,
agent.wallet_address,
false,
TOKEN_PROGRAM_ID,
);
const { tx } = await tensorSwapSdk.delist({
nftMint,
nftDest,
owner: agent.wallet_address,
tokenProgram: TOKEN_PROGRAM_ID,
payer: agent.wallet_address,
authData: null,
});
const transaction = new Transaction();
transaction.add(...tx.ixs);
return await agent.connection.sendTransaction(transaction, [
agent.wallet,
...tx.extraSigners,
]);
}

View File

@@ -1,6 +1,11 @@
import { VersionedTransaction, PublicKey } from "@solana/web3.js";
import { SolanaAgentKit } from "../index";
import { TOKENS, DEFAULT_OPTIONS, JUP_API } from "../constants";
import {
TOKENS,
DEFAULT_OPTIONS,
JUP_API,
JUP_REFERRAL_ADDRESS,
} from "../constants";
import { getMint } from "@solana/spl-token";
/**
* Swap tokens using Jupiter Exchange
@@ -11,6 +16,7 @@ import { getMint } from "@solana/spl-token";
* @param slippageBps Slippage tolerance in basis points (default: 300 = 3%)
* @returns Transaction signature
*/
export async function trade(
agent: SolanaAgentKit,
outputMint: PublicKey,
@@ -38,11 +44,24 @@ export async function trade(
`&amount=${scaledAmount}` +
`&slippageBps=${slippageBps}` +
`&onlyDirectRoutes=true` +
`&maxAccounts=20`,
`&maxAccounts=20` +
`${agent.config.JUPITER_FEE_BPS ? `&platformFeeBps=${agent.config.JUPITER_FEE_BPS}` : ""}`,
)
).json();
// Get serialized transaction
let feeAccount;
if (agent.config.JUPITER_REFERRAL_ACCOUNT) {
[feeAccount] = PublicKey.findProgramAddressSync(
[
Buffer.from("referral_ata"),
new PublicKey(agent.config.JUPITER_REFERRAL_ACCOUNT).toBuffer(),
TOKENS.SOL.toBuffer(),
],
new PublicKey(JUP_REFERRAL_ADDRESS),
);
}
const { swapTransaction } = await (
await fetch("https://quote-api.jup.ag/v6/swap", {
method: "POST",
@@ -55,6 +74,7 @@ export async function trade(
wrapAndUnwrapSol: true,
dynamicComputeUnitLimit: true,
prioritizationFeeLamports: "auto",
feeAccount: feeAccount ? feeAccount.toString() : null,
}),
})
).json();

37
src/tools/withdraw_all.ts Normal file
View File

@@ -0,0 +1,37 @@
import {
PublicKey,
sendAndConfirmTransaction,
Transaction,
} from "@solana/web3.js";
import { SolanaAgentKit } from "../index";
import { ManifestClient } from "@cks-systems/manifest-sdk";
/**
* Withdraws all funds from Manifest
* @param agent SolanaAgentKit instance
* @param marketId Public key for the manifest market
* @returns Transaction signature
*/
export async function withdrawAll(
agent: SolanaAgentKit,
marketId: PublicKey,
): Promise<string> {
try {
const mfxClient = await ManifestClient.getClientForMarket(
agent.connection,
marketId,
agent.wallet,
);
const withdrawAllIx = await mfxClient.withdrawAllIx();
const signature = await sendAndConfirmTransaction(
agent.connection,
new Transaction().add(...withdrawAllIx),
[agent.wallet],
);
return signature;
} catch (error: any) {
throw new Error(`Withdraw all failed: ${error.message}`);
}
}

56
src/types/action.ts Normal file
View File

@@ -0,0 +1,56 @@
import { SolanaAgentKit } from "../agent";
import { z } from "zod";
/**
* Example of an action with input and output
*/
export interface ActionExample {
input: Record<string, any>;
output: Record<string, any>;
explanation: string;
}
/**
* Handler function type for executing the action
*/
export type Handler = (
agent: SolanaAgentKit,
input: Record<string, any>,
) => Promise<Record<string, any>>;
/**
* Main Action interface inspired by ELIZA
* This interface makes it easier to implement actions across different frameworks
*/
export interface Action {
/**
* Unique name of the action
*/
name: string;
/**
* Alternative names/phrases that can trigger this action
*/
similes: string[];
/**
* Detailed description of what the action does
*/
description: string;
/**
* Array of example inputs and outputs for the action
* Each inner array represents a group of related examples
*/
examples: ActionExample[][];
/**
* Zod schema for input validation
*/
schema: z.ZodType<any>;
/**
* Function that executes the action
*/
handler: Handler;
}

View File

@@ -1,4 +1,12 @@
import { PublicKey } from "@solana/web3.js";
import { SolanaAgentKit } from "../agent";
import { z } from "zod";
export interface Config {
OPENAI_API_KEY?: string;
JUPITER_REFERRAL_ACCOUNT?: string;
JUPITER_FEE_BPS?: number;
}
export interface Creator {
address: string;
@@ -91,3 +99,57 @@ export interface GibworkCreateTaskReponse {
taskId?: string | undefined;
signature?: string | undefined;
}
/**
* Example of an action with input and output
*/
export interface ActionExample {
input: Record<string, any>;
output: Record<string, any>;
explanation: string;
}
/**
* Handler function type for executing the action
*/
export type Handler = (
agent: SolanaAgentKit,
input: Record<string, any>,
) => Promise<Record<string, any>>;
/**
* Main Action interface inspired by ELIZA
* This interface makes it easier to implement actions across different frameworks
*/
export interface Action {
/**
* Unique name of the action
*/
name: string;
/**
* Alternative names/phrases that can trigger this action
*/
similes: string[];
/**
* Detailed description of what the action does
*/
description: string;
/**
* Array of example inputs and outputs for the action
* Each inner array represents a group of related examples
*/
examples: ActionExample[][];
/**
* Zod schema for input validation
*/
schema: z.ZodType<any>;
/**
* Function that executes the action
*/
handler: Handler;
}

View File

@@ -0,0 +1,68 @@
import { Action } from "../types/action";
import { SolanaAgentKit } from "../agent";
import { ACTIONS } from "../actions";
/**
* Find an action by its name or one of its similes
*/
export function findAction(query: string): Action | undefined {
const normalizedQuery = query.toLowerCase().trim();
return Object.values(ACTIONS).find(
(action) =>
action.name.toLowerCase() === normalizedQuery ||
action.similes.some((simile) => simile.toLowerCase() === normalizedQuery),
);
}
/**
* Execute an action with the given input
*/
export async function executeAction(
action: Action,
agent: SolanaAgentKit,
input: Record<string, any>,
): Promise<Record<string, any>> {
try {
// Validate input using Zod schema
const validatedInput = action.schema.parse(input);
// Execute the action with validated input
const result = await action.handler(agent, validatedInput);
return {
status: "success",
...result,
};
} catch (error: any) {
// Handle Zod validation errors specially
if (error.errors) {
return {
status: "error",
message: "Validation error",
details: error.errors,
code: "VALIDATION_ERROR",
};
}
return {
status: "error",
message: error.message,
code: error.code || "EXECUTION_ERROR",
};
}
}
/**
* Get examples for an action
*/
export function getActionExamples(action: Action): string {
return action.examples
.flat()
.map((example) => {
return `Input: ${JSON.stringify(example.input, null, 2)}
Output: ${JSON.stringify(example.output, null, 2)}
Explanation: ${example.explanation}
---`;
})
.join("\n");
}