mirror of
https://github.com/d0zingcat/solana-agent-kit.git
synced 2026-05-18 23:26:45 +00:00
adding missing tools
This commit is contained in:
135
src/actions/createGibworkTask.ts
Normal file
135
src/actions/createGibworkTask.ts
Normal file
@@ -0,0 +1,135 @@
|
||||
import { Action } from "../types/action";
|
||||
import { SolanaAgentKit } from "../agent";
|
||||
import { z } from "zod";
|
||||
import { PublicKey, VersionedTransaction } from "@solana/web3.js";
|
||||
|
||||
const createGibworkTaskAction: Action = {
|
||||
name: "solana_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 tokenMintAddress = new PublicKey(input.tokenMintAddress);
|
||||
const payer = input.payer ? new PublicKey(input.payer) : undefined;
|
||||
|
||||
const apiResponse = await fetch(
|
||||
"https://api2.gib.work/tasks/public/transaction",
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
title: input.title,
|
||||
content: input.content,
|
||||
requirements: input.requirements,
|
||||
tags: input.tags,
|
||||
payer: payer?.toBase58() || agent.wallet.publicKey.toBase58(),
|
||||
token: {
|
||||
mintAddress: tokenMintAddress.toBase58(),
|
||||
amount: input.tokenAmount,
|
||||
},
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
if (!apiResponse.ok) {
|
||||
return {
|
||||
status: "error",
|
||||
message: `Failed to create task: ${apiResponse.statusText}`
|
||||
};
|
||||
}
|
||||
|
||||
const responseData = await apiResponse.json();
|
||||
if (!responseData.taskId || !responseData.serializedTransaction) {
|
||||
return {
|
||||
status: "error",
|
||||
message: responseData.message || "Invalid response from Gibwork API"
|
||||
};
|
||||
}
|
||||
|
||||
const serializedTransaction = Buffer.from(
|
||||
responseData.serializedTransaction,
|
||||
"base64"
|
||||
);
|
||||
const tx = VersionedTransaction.deserialize(serializedTransaction);
|
||||
|
||||
tx.sign([agent.wallet]);
|
||||
const signature = await agent.connection.sendTransaction(tx, {
|
||||
preflightCommitment: "confirmed",
|
||||
maxRetries: 3,
|
||||
});
|
||||
|
||||
const latestBlockhash = await agent.connection.getLatestBlockhash();
|
||||
await agent.connection.confirmTransaction({
|
||||
signature,
|
||||
blockhash: latestBlockhash.blockhash,
|
||||
lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
|
||||
});
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
taskId: responseData.taskId,
|
||||
signature,
|
||||
message: `Successfully created task: ${input.title}`
|
||||
};
|
||||
} catch (error: any) {
|
||||
return {
|
||||
status: "error",
|
||||
message: `Failed to create task: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default createGibworkTaskAction;
|
||||
114
src/actions/createImage.ts
Normal file
114
src/actions/createImage.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
import { Action } from "../types/action";
|
||||
import { SolanaAgentKit } from "../agent";
|
||||
import { z } from "zod";
|
||||
import OpenAI from "openai";
|
||||
|
||||
const createImageAction: Action = {
|
||||
name: "solana_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.openai_api_key) {
|
||||
return {
|
||||
status: "error",
|
||||
message: "OpenAI API key not found in agent configuration"
|
||||
};
|
||||
}
|
||||
|
||||
const { prompt, model, size, quality, style } = input;
|
||||
|
||||
const openai = new OpenAI({
|
||||
apiKey: agent.openai_api_key
|
||||
});
|
||||
|
||||
const response = await openai.images.generate({
|
||||
prompt,
|
||||
model,
|
||||
n: 1,
|
||||
size,
|
||||
quality,
|
||||
style
|
||||
});
|
||||
|
||||
if (!response.data || response.data.length === 0) {
|
||||
return {
|
||||
status: "error",
|
||||
message: "No image was generated"
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
imageUrl: response.data[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;
|
||||
119
src/actions/createOpenbookMarket.ts
Normal file
119
src/actions/createOpenbookMarket.ts
Normal file
@@ -0,0 +1,119 @@
|
||||
import { Action } from "../types/action";
|
||||
import { SolanaAgentKit } from "../agent";
|
||||
import { z } from "zod";
|
||||
import { OPEN_BOOK_PROGRAM, Raydium, TxVersion } from "@raydium-io/raydium-sdk-v2";
|
||||
import { MintLayout, TOKEN_PROGRAM_ID } from "@solana/spl-token";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
|
||||
const createOpenbookMarketAction: Action = {
|
||||
name: "solana_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 raydium = await Raydium.load({
|
||||
owner: agent.wallet,
|
||||
connection: agent.connection,
|
||||
});
|
||||
|
||||
// Get mint info
|
||||
const baseMintInfo = await agent.connection.getAccountInfo(baseMint);
|
||||
const quoteMintInfo = await agent.connection.getAccountInfo(quoteMint);
|
||||
|
||||
if (!baseMintInfo || !quoteMintInfo) {
|
||||
return {
|
||||
status: "error",
|
||||
message: "Failed to fetch mint information"
|
||||
};
|
||||
}
|
||||
|
||||
// Verify token program
|
||||
if (
|
||||
baseMintInfo.owner.toString() !== TOKEN_PROGRAM_ID.toBase58() ||
|
||||
quoteMintInfo.owner.toString() !== TOKEN_PROGRAM_ID.toBase58()
|
||||
) {
|
||||
return {
|
||||
status: "error",
|
||||
message: "Openbook market only supports TOKEN_PROGRAM_ID mints. For token-2022, please use Raydium CPMM pool instead."
|
||||
};
|
||||
}
|
||||
|
||||
// Create market
|
||||
const { execute } = await raydium.marketV2.create({
|
||||
baseInfo: {
|
||||
mint: baseMint,
|
||||
decimals: MintLayout.decode(baseMintInfo.data).decimals,
|
||||
},
|
||||
quoteInfo: {
|
||||
mint: quoteMint,
|
||||
decimals: MintLayout.decode(quoteMintInfo.data).decimals,
|
||||
},
|
||||
lotSize,
|
||||
tickSize,
|
||||
dexProgramId: OPEN_BOOK_PROGRAM,
|
||||
txVersion: TxVersion.V0,
|
||||
});
|
||||
|
||||
const { txIds } = await execute({ sequentially: true });
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
signatures: txIds,
|
||||
message: "Successfully created Openbook market"
|
||||
};
|
||||
} catch (error: any) {
|
||||
return {
|
||||
status: "error",
|
||||
message: `Failed to create Openbook market: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default createOpenbookMarketAction;
|
||||
105
src/actions/createOrcaSingleSidedWhirlpool.ts
Normal file
105
src/actions/createOrcaSingleSidedWhirlpool.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
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";
|
||||
|
||||
// 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: "solana_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 = new BN(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 as keyof typeof FEE_TIERS;
|
||||
|
||||
// Create the whirlpool
|
||||
const signature = await agent.createOrcaSingleSidedWhirlpool(
|
||||
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;
|
||||
70
src/actions/fetchPrice.ts
Normal file
70
src/actions/fetchPrice.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import { Action } from "../types/action";
|
||||
import { SolanaAgentKit } from "../agent";
|
||||
import { z } from "zod";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
|
||||
const fetchPriceAction: Action = {
|
||||
name: "solana_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 response = await fetch(`https://api.jup.ag/price/v2?ids=${tokenId}`);
|
||||
|
||||
if (!response.ok) {
|
||||
return {
|
||||
status: "error",
|
||||
message: `Failed to fetch price: ${response.statusText}`
|
||||
};
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
const price = data.data[tokenId.toBase58()]?.price;
|
||||
|
||||
if (!price) {
|
||||
return {
|
||||
status: "error",
|
||||
message: "Price data not available for the given token"
|
||||
};
|
||||
}
|
||||
|
||||
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;
|
||||
49
src/actions/getAllDomainsTLDs.ts
Normal file
49
src/actions/getAllDomainsTLDs.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { Action } from "../types/action";
|
||||
import { SolanaAgentKit } from "../agent";
|
||||
import { z } from "zod";
|
||||
|
||||
const getAllDomainsTLDsAction: Action = {
|
||||
name: "solana_get_all_domains_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, input: Record<string, any>) => {
|
||||
try {
|
||||
// Get all domain TLDs
|
||||
const tlds = await agent.getAllDomainsTLDs();
|
||||
|
||||
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;
|
||||
70
src/actions/getAllRegisteredAllDomains.ts
Normal file
70
src/actions/getAllRegisteredAllDomains.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import { Action } from "../types/action";
|
||||
import { SolanaAgentKit } from "../agent";
|
||||
import { z } from "zod";
|
||||
|
||||
const getAllRegisteredAllDomainsAction: Action = {
|
||||
name: "solana_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 agent.getAllRegisteredAllDomains();
|
||||
|
||||
// Apply pagination
|
||||
const paginatedDomains = domains.slice(offset, offset + limit);
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
domains: paginatedDomains,
|
||||
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;
|
||||
67
src/actions/getMainAllDomainsDomain.ts
Normal file
67
src/actions/getMainAllDomainsDomain.ts
Normal 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 { TldParser } from "@onsol/tldparser";
|
||||
|
||||
const getMainAllDomainsDomainAction: Action = {
|
||||
name: "solana_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 address = new PublicKey(input.address);
|
||||
|
||||
// Get the main domain using TldParser
|
||||
const parser = new TldParser(agent.connection);
|
||||
const mainDomain = await parser.getMainDomain(address);
|
||||
|
||||
if (!mainDomain) {
|
||||
return {
|
||||
status: "error",
|
||||
message: "No main domain found for this address"
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
domain: mainDomain.domain,
|
||||
message: "Successfully retrieved main domain"
|
||||
};
|
||||
} catch (error: any) {
|
||||
return {
|
||||
status: "error",
|
||||
message: `Failed to get main domain: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default getMainAllDomainsDomainAction;
|
||||
60
src/actions/getOwnedAllDomains.ts
Normal file
60
src/actions/getOwnedAllDomains.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import { Action } from "../types/action";
|
||||
import { SolanaAgentKit } from "../agent";
|
||||
import { z } from "zod";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
|
||||
const getOwnedAllDomainsAction: Action = {
|
||||
name: "solana_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 agent.getOwnedAllDomains(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;
|
||||
60
src/actions/getOwnedDomainsForTLD.ts
Normal file
60
src/actions/getOwnedDomainsForTLD.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import { Action } from "../types/action";
|
||||
import { SolanaAgentKit } from "../agent";
|
||||
import { z } from "zod";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
|
||||
const getOwnedDomainsForTLDAction: Action = {
|
||||
name: "solana_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 agent.getOwnedDomainsForTLD(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;
|
||||
68
src/actions/getPrimaryDomain.ts
Normal file
68
src/actions/getPrimaryDomain.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
import { Action } from "../types/action";
|
||||
import { SolanaAgentKit } from "../agent";
|
||||
import { z } from "zod";
|
||||
import { getPrimaryDomain as _getPrimaryDomain } from "@bonfida/spl-name-service";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
|
||||
const getPrimaryDomainAction: Action = {
|
||||
name: "solana_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 { reverse, stale } = await _getPrimaryDomain(
|
||||
agent.connection,
|
||||
account
|
||||
);
|
||||
|
||||
if (stale) {
|
||||
return {
|
||||
status: "error",
|
||||
message: `Primary domain is stale for account: ${account.toBase58()}`
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
domain: reverse,
|
||||
message: `Primary domain: ${reverse}`
|
||||
};
|
||||
} catch (error: any) {
|
||||
return {
|
||||
status: "error",
|
||||
message: `Failed to get primary domain: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default getPrimaryDomainAction;
|
||||
62
src/actions/getTPS.ts
Normal file
62
src/actions/getTPS.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import { Action } from "../types/action";
|
||||
import { SolanaAgentKit } from "../agent";
|
||||
import { z } from "zod";
|
||||
|
||||
const getTPSAction: Action = {
|
||||
name: "solana_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 perfSamples = await agent.connection.getRecentPerformanceSamples();
|
||||
|
||||
if (
|
||||
!perfSamples.length ||
|
||||
!perfSamples[0]?.numTransactions ||
|
||||
!perfSamples[0]?.samplePeriodSecs
|
||||
) {
|
||||
return {
|
||||
status: "error",
|
||||
message: "No performance samples available"
|
||||
};
|
||||
}
|
||||
|
||||
const tps = Math.round(
|
||||
perfSamples[0].numTransactions / perfSamples[0].samplePeriodSecs
|
||||
);
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
tps,
|
||||
message: `Current network TPS: ${tps}`
|
||||
};
|
||||
} catch (error: any) {
|
||||
return {
|
||||
status: "error",
|
||||
message: `Failed to get TPS: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default getTPSAction;
|
||||
134
src/actions/getTokenData.ts
Normal file
134
src/actions/getTokenData.ts
Normal file
@@ -0,0 +1,134 @@
|
||||
import { Action } from "../types/action";
|
||||
import { SolanaAgentKit } from "../agent";
|
||||
import { z } from "zod";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
import { JupiterTokenData } from "../types";
|
||||
|
||||
const getTokenDataAction: Action = {
|
||||
name: "solana_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) {
|
||||
const mint = new PublicKey(input.address);
|
||||
const response = await fetch("https://tokens.jup.ag/tokens?tags=verified", {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
const data = (await response.json()) as JupiterTokenData[];
|
||||
tokenData = data.find((token: JupiterTokenData) => token.address === mint.toBase58());
|
||||
} else if (input.ticker) {
|
||||
const response = await fetch(
|
||||
`https://api.dexscreener.com/latest/dex/search?q=${input.ticker}`
|
||||
);
|
||||
const data = await response.json();
|
||||
|
||||
if (!data.pairs || data.pairs.length === 0) {
|
||||
return {
|
||||
status: "error",
|
||||
message: `No token found for ticker: ${input.ticker}`
|
||||
};
|
||||
}
|
||||
|
||||
let solanaPairs = data.pairs
|
||||
.filter((pair: any) => pair.chainId === "solana")
|
||||
.sort((a: any, b: any) => (b.fdv || 0) - (a.fdv || 0))
|
||||
.filter(
|
||||
(pair: any) =>
|
||||
pair.baseToken.symbol.toLowerCase() === input.ticker.toLowerCase()
|
||||
);
|
||||
|
||||
if (solanaPairs.length === 0) {
|
||||
return {
|
||||
status: "error",
|
||||
message: `No Solana token found for ticker: ${input.ticker}`
|
||||
};
|
||||
}
|
||||
|
||||
const address = solanaPairs[0].baseToken.address;
|
||||
const jupResponse = await fetch("https://tokens.jup.ag/tokens?tags=verified");
|
||||
const jupData = (await jupResponse.json()) as JupiterTokenData[];
|
||||
tokenData = jupData.find((token: JupiterTokenData) => token.address === 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;
|
||||
@@ -5,6 +5,30 @@ 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 createRaydiumCLMMAction from "./createRaydiumCLMM";
|
||||
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 createRaydiumCPMMAction from "./createRaydiumCPMM";
|
||||
import sendCompressedAirdropAction from "./sendCompressedAirdrop";
|
||||
import raydiumCreateCpmmAction from "./raydiumCreateCpmm";
|
||||
import raydiumCreateAmmV4Action from "./raydiumCreateAmmV4";
|
||||
import createOrcaSingleSidedWhirlpoolAction from "./createOrcaSingleSidedWhirlpool";
|
||||
import launchPumpfunTokenAction from "./launchPumpfunToken";
|
||||
|
||||
export const actions = [
|
||||
deployTokenAction,
|
||||
@@ -14,7 +38,30 @@ export const actions = [
|
||||
mintNFTAction,
|
||||
tradeAction,
|
||||
requestFundsAction,
|
||||
// Add more actions here as they are implemented
|
||||
resolveDomainAction,
|
||||
getTokenDataAction,
|
||||
getTPSAction,
|
||||
fetchPriceAction,
|
||||
stakeWithJupAction,
|
||||
registerDomainAction,
|
||||
lendAssetAction,
|
||||
createGibworkTaskAction,
|
||||
resolveSolDomainAction,
|
||||
pythFetchPriceAction,
|
||||
getOwnedDomainsForTLDAction,
|
||||
createRaydiumCLMMAction,
|
||||
getPrimaryDomainAction,
|
||||
getAllDomainsTLDsAction,
|
||||
getOwnedAllDomainsAction,
|
||||
createImageAction,
|
||||
getMainAllDomainsDomainAction,
|
||||
getAllRegisteredAllDomainsAction,
|
||||
createRaydiumCPMMAction,
|
||||
sendCompressedAirdropAction,
|
||||
raydiumCreateCpmmAction,
|
||||
raydiumCreateAmmV4Action,
|
||||
createOrcaSingleSidedWhirlpoolAction,
|
||||
launchPumpfunTokenAction,
|
||||
];
|
||||
|
||||
export type { Action, ActionExample, Handler } from "../types/action";
|
||||
203
src/actions/launchPumpfunToken.ts
Normal file
203
src/actions/launchPumpfunToken.ts
Normal file
@@ -0,0 +1,203 @@
|
||||
import { Action } from "../types/action";
|
||||
import { SolanaAgentKit } from "../agent";
|
||||
import { z } from "zod";
|
||||
import { VersionedTransaction, Keypair } from "@solana/web3.js";
|
||||
|
||||
const launchPumpfunTokenAction: Action = {
|
||||
name: "solana_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 mintKeypair = Keypair.generate();
|
||||
|
||||
// Upload metadata
|
||||
const formData = new URLSearchParams();
|
||||
formData.append("name", input.tokenName);
|
||||
formData.append("symbol", input.tokenTicker);
|
||||
formData.append("description", input.description);
|
||||
formData.append("showName", "true");
|
||||
|
||||
if (input.twitter) {
|
||||
formData.append("twitter", input.twitter);
|
||||
}
|
||||
if (input.telegram) {
|
||||
formData.append("telegram", input.telegram);
|
||||
}
|
||||
if (input.website) {
|
||||
formData.append("website", input.website);
|
||||
}
|
||||
|
||||
// Fetch and process image
|
||||
const imageResponse = await fetch(input.imageUrl);
|
||||
const imageBlob = await imageResponse.blob();
|
||||
const imageFile = new File([imageBlob], "token_image.png", { type: "image/png" });
|
||||
|
||||
// Create final form data
|
||||
const finalFormData = new FormData();
|
||||
for (const [key, value] of formData.entries()) {
|
||||
finalFormData.append(key, value);
|
||||
}
|
||||
finalFormData.append("file", imageFile);
|
||||
|
||||
// Upload metadata to IPFS
|
||||
const metadataResponse = await fetch("https://pump.fun/api/ipfs", {
|
||||
method: "POST",
|
||||
body: finalFormData,
|
||||
});
|
||||
|
||||
if (!metadataResponse.ok) {
|
||||
throw new Error(`Metadata upload failed: ${metadataResponse.statusText}`);
|
||||
}
|
||||
|
||||
const metadataResult = await metadataResponse.json();
|
||||
|
||||
// Create token transaction
|
||||
const payload = {
|
||||
publicKey: agent.wallet_address.toBase58(),
|
||||
action: "create",
|
||||
tokenMetadata: {
|
||||
name: metadataResult.metadata.name,
|
||||
symbol: metadataResult.metadata.symbol,
|
||||
uri: metadataResult.metadataUri,
|
||||
},
|
||||
mint: mintKeypair.publicKey.toBase58(),
|
||||
denominatedInSol: "true",
|
||||
amount: input.initialLiquiditySOL || 0.0001,
|
||||
slippage: input.slippageBps || 5,
|
||||
priorityFee: input.priorityFee || 0.00005,
|
||||
pool: "pump",
|
||||
};
|
||||
|
||||
const txResponse = await fetch("https://pumpportal.fun/api/trade-local", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
|
||||
if (!txResponse.ok) {
|
||||
const errorText = await txResponse.text();
|
||||
throw new Error(`Transaction creation failed: ${txResponse.status} - ${errorText}`);
|
||||
}
|
||||
|
||||
// Process and sign transaction
|
||||
const transactionData = await txResponse.arrayBuffer();
|
||||
const tx = VersionedTransaction.deserialize(new Uint8Array(transactionData));
|
||||
|
||||
// Get latest blockhash
|
||||
const { blockhash, lastValidBlockHeight } = await agent.connection.getLatestBlockhash();
|
||||
tx.message.recentBlockhash = blockhash;
|
||||
|
||||
// Sign transaction
|
||||
tx.sign([mintKeypair, agent.wallet]);
|
||||
|
||||
// Send transaction
|
||||
const signature = await agent.connection.sendTransaction(tx, {
|
||||
skipPreflight: false,
|
||||
preflightCommitment: "confirmed",
|
||||
maxRetries: 5,
|
||||
});
|
||||
|
||||
// Wait for confirmation
|
||||
const confirmation = await agent.connection.confirmTransaction({
|
||||
signature,
|
||||
blockhash,
|
||||
lastValidBlockHeight,
|
||||
});
|
||||
|
||||
if (confirmation.value.err) {
|
||||
throw new Error(`Transaction failed: ${confirmation.value.err}`);
|
||||
}
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
signature,
|
||||
mint: mintKeypair.publicKey.toBase58(),
|
||||
metadataUri: metadataResult.metadataUri,
|
||||
message: "Successfully launched token on Pump.fun"
|
||||
};
|
||||
} catch (error: any) {
|
||||
return {
|
||||
status: "error",
|
||||
message: `Failed to launch token: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default launchPumpfunTokenAction;
|
||||
101
src/actions/lendAsset.ts
Normal file
101
src/actions/lendAsset.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
import { Action } from "../types/action";
|
||||
import { SolanaAgentKit } from "../agent";
|
||||
import { z } from "zod";
|
||||
import { VersionedTransaction } from "@solana/web3.js";
|
||||
|
||||
const lendAssetAction: Action = {
|
||||
name: "solana_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 fetch(
|
||||
`https://blink.lulo.fi/actions?amount=${amount}&symbol=USDC`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
account: agent.wallet.publicKey.toBase58(),
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
return {
|
||||
status: "error",
|
||||
message: `Failed to get lending transaction: ${response.statusText}`
|
||||
};
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
// Deserialize the transaction
|
||||
const luloTxn = VersionedTransaction.deserialize(
|
||||
Buffer.from(data.transaction, "base64")
|
||||
);
|
||||
|
||||
// Get a recent blockhash and set it
|
||||
const { blockhash } = await agent.connection.getLatestBlockhash();
|
||||
luloTxn.message.recentBlockhash = blockhash;
|
||||
|
||||
// Sign and send transaction
|
||||
luloTxn.sign([agent.wallet]);
|
||||
const signature = await agent.connection.sendTransaction(luloTxn, {
|
||||
preflightCommitment: "confirmed",
|
||||
maxRetries: 3,
|
||||
});
|
||||
|
||||
// Wait for confirmation
|
||||
const latestBlockhash = await agent.connection.getLatestBlockhash();
|
||||
await agent.connection.confirmTransaction({
|
||||
signature,
|
||||
blockhash: latestBlockhash.blockhash,
|
||||
lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
|
||||
});
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
signature,
|
||||
message: `Successfully lent ${amount} USDC`
|
||||
};
|
||||
} catch (error: any) {
|
||||
return {
|
||||
status: "error",
|
||||
message: `Lending failed: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default lendAssetAction;
|
||||
78
src/actions/pythFetchPrice.ts
Normal file
78
src/actions/pythFetchPrice.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import { Action } from "../types/action";
|
||||
import { SolanaAgentKit } from "../agent";
|
||||
import { z } from "zod";
|
||||
import { PriceServiceConnection } from "@pythnetwork/price-service-client";
|
||||
import BN from "bn.js";
|
||||
|
||||
const pythFetchPriceAction: Action = {
|
||||
name: "solana_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.priceFeedId as string;
|
||||
|
||||
// Connect to Hermes service
|
||||
const stableHermesServiceUrl = "https://hermes.pyth.network";
|
||||
const connection = new PriceServiceConnection(stableHermesServiceUrl);
|
||||
const feeds = [priceFeedId];
|
||||
|
||||
const currentPrice = await connection.getLatestPriceFeeds(feeds);
|
||||
|
||||
if (!currentPrice || currentPrice.length === 0) {
|
||||
return {
|
||||
status: "error",
|
||||
message: "Price data not available for the given feed ID"
|
||||
};
|
||||
}
|
||||
|
||||
// Get price and exponent from price feed
|
||||
const price = new BN(currentPrice[0].getPriceUnchecked().price);
|
||||
const exponent = new BN(currentPrice[0].getPriceUnchecked().expo);
|
||||
|
||||
// Convert to scaled price
|
||||
const scaledPrice = price.div(new BN(10).pow(exponent));
|
||||
const priceStr = scaledPrice.toString();
|
||||
|
||||
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;
|
||||
154
src/actions/raydiumCreateAmmV4.ts
Normal file
154
src/actions/raydiumCreateAmmV4.ts
Normal file
@@ -0,0 +1,154 @@
|
||||
import { Action } from "../types/action";
|
||||
import { SolanaAgentKit } from "../agent";
|
||||
import { z } from "zod";
|
||||
import {
|
||||
AMM_V4,
|
||||
FEE_DESTINATION_ID,
|
||||
MARKET_STATE_LAYOUT_V3,
|
||||
OPEN_BOOK_PROGRAM,
|
||||
Raydium,
|
||||
TxVersion,
|
||||
} from "@raydium-io/raydium-sdk-v2";
|
||||
import { MintLayout, TOKEN_PROGRAM_ID } from "@solana/spl-token";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
import BN from "bn.js";
|
||||
|
||||
const raydiumCreateAmmV4Action: Action = {
|
||||
name: "solana_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 raydium = await Raydium.load({
|
||||
owner: agent.wallet,
|
||||
connection: agent.connection,
|
||||
});
|
||||
|
||||
const marketBufferInfo = await agent.connection.getAccountInfo(
|
||||
new PublicKey(marketId),
|
||||
);
|
||||
const { baseMint, quoteMint } = MARKET_STATE_LAYOUT_V3.decode(
|
||||
marketBufferInfo!.data,
|
||||
);
|
||||
|
||||
const baseMintInfo = await agent.connection.getAccountInfo(baseMint);
|
||||
const quoteMintInfo = await agent.connection.getAccountInfo(quoteMint);
|
||||
|
||||
if (
|
||||
baseMintInfo?.owner.toString() !== TOKEN_PROGRAM_ID.toBase58() ||
|
||||
quoteMintInfo?.owner.toString() !== TOKEN_PROGRAM_ID.toBase58()
|
||||
) {
|
||||
throw new Error(
|
||||
"amm pools with openbook market only support TOKEN_PROGRAM_ID mints, if you want to create pool with token-2022, please create cpmm pool instead",
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
baseAmount
|
||||
.mul(quoteAmount)
|
||||
.lte(
|
||||
new BN(1)
|
||||
.mul(new BN(10 ** MintLayout.decode(baseMintInfo.data).decimals))
|
||||
.pow(new BN(2)),
|
||||
)
|
||||
) {
|
||||
throw new Error(
|
||||
"initial liquidity too low, try adding more baseAmount/quoteAmount",
|
||||
);
|
||||
}
|
||||
|
||||
const { execute } = await raydium.liquidity.createPoolV4({
|
||||
programId: AMM_V4,
|
||||
marketInfo: {
|
||||
marketId,
|
||||
programId: OPEN_BOOK_PROGRAM,
|
||||
},
|
||||
baseMintInfo: {
|
||||
mint: baseMint,
|
||||
decimals: MintLayout.decode(baseMintInfo.data).decimals,
|
||||
},
|
||||
quoteMintInfo: {
|
||||
mint: quoteMint,
|
||||
decimals: MintLayout.decode(quoteMintInfo.data).decimals,
|
||||
},
|
||||
baseAmount,
|
||||
quoteAmount,
|
||||
startTime,
|
||||
ownerInfo: {
|
||||
useSOLBalance: true,
|
||||
},
|
||||
associatedOnly: false,
|
||||
txVersion: TxVersion.V0,
|
||||
feeDestinationId: FEE_DESTINATION_ID,
|
||||
});
|
||||
|
||||
const { txId } = await execute({ sendAndConfirm: true });
|
||||
|
||||
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;
|
||||
142
src/actions/raydiumCreateCpmm.ts
Normal file
142
src/actions/raydiumCreateCpmm.ts
Normal file
@@ -0,0 +1,142 @@
|
||||
import { Action } from "../types/action";
|
||||
import { SolanaAgentKit } from "../agent";
|
||||
import { z } from "zod";
|
||||
import {
|
||||
CREATE_CPMM_POOL_FEE_ACC,
|
||||
CREATE_CPMM_POOL_PROGRAM,
|
||||
Raydium,
|
||||
TxVersion,
|
||||
} from "@raydium-io/raydium-sdk-v2";
|
||||
import { MintLayout } from "@solana/spl-token";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
import BN from "bn.js";
|
||||
|
||||
const raydiumCreateCpmmAction: Action = {
|
||||
name: "solana_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 raydium = await Raydium.load({
|
||||
owner: agent.wallet,
|
||||
connection: agent.connection,
|
||||
});
|
||||
|
||||
const [mintInfoA, mintInfoB] = await agent.connection.getMultipleAccountsInfo(
|
||||
[mintA, mintB],
|
||||
);
|
||||
if (mintInfoA === null || mintInfoB === null) {
|
||||
throw Error("fetch mint info error");
|
||||
}
|
||||
|
||||
const mintDecodeInfoA = MintLayout.decode(mintInfoA.data);
|
||||
const mintDecodeInfoB = MintLayout.decode(mintInfoB.data);
|
||||
|
||||
const mintFormatInfoA = {
|
||||
chainId: 101,
|
||||
address: mintA.toString(),
|
||||
programId: mintInfoA.owner.toString(),
|
||||
logoURI: "",
|
||||
symbol: "",
|
||||
name: "",
|
||||
decimals: mintDecodeInfoA.decimals,
|
||||
tags: [],
|
||||
extensions: {},
|
||||
};
|
||||
const mintFormatInfoB = {
|
||||
chainId: 101,
|
||||
address: mintB.toString(),
|
||||
programId: mintInfoB.owner.toString(),
|
||||
logoURI: "",
|
||||
symbol: "",
|
||||
name: "",
|
||||
decimals: mintDecodeInfoB.decimals,
|
||||
tags: [],
|
||||
extensions: {},
|
||||
};
|
||||
|
||||
const { execute } = await raydium.cpmm.createPool({
|
||||
programId: CREATE_CPMM_POOL_PROGRAM,
|
||||
poolFeeAccount: CREATE_CPMM_POOL_FEE_ACC,
|
||||
mintA: mintFormatInfoA,
|
||||
mintB: mintFormatInfoB,
|
||||
mintAAmount,
|
||||
mintBAmount,
|
||||
startTime,
|
||||
//@ts-expect-error sdk bug
|
||||
feeConfig: { id: configId.toString() },
|
||||
associatedOnly: false,
|
||||
ownerInfo: {
|
||||
useSOLBalance: true,
|
||||
},
|
||||
txVersion: TxVersion.V0,
|
||||
});
|
||||
|
||||
const { txId } = await execute({ sendAndConfirm: true });
|
||||
|
||||
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;
|
||||
110
src/actions/registerDomain.ts
Normal file
110
src/actions/registerDomain.ts
Normal file
@@ -0,0 +1,110 @@
|
||||
import { Action } from "../types/action";
|
||||
import { SolanaAgentKit } from "../agent";
|
||||
import { z } from "zod";
|
||||
import { Transaction } from "@solana/web3.js";
|
||||
import { registerDomainNameV2 } from "@bonfida/spl-name-service";
|
||||
import { getAssociatedTokenAddressSync } from "@solana/spl-token";
|
||||
import { TOKENS } from "../constants";
|
||||
|
||||
const registerDomainAction: Action = {
|
||||
name: "solana_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;
|
||||
|
||||
// Validate space size
|
||||
if (spaceKB > 10) {
|
||||
return {
|
||||
status: "error",
|
||||
message: "Maximum domain size is 10KB"
|
||||
};
|
||||
}
|
||||
|
||||
// Convert KB to bytes
|
||||
const space = spaceKB * 1_000;
|
||||
|
||||
const buyerTokenAccount = await getAssociatedTokenAddressSync(
|
||||
agent.wallet_address,
|
||||
TOKENS.USDC
|
||||
);
|
||||
|
||||
// Create registration instruction
|
||||
const instruction = await registerDomainNameV2(
|
||||
agent.connection,
|
||||
name,
|
||||
space,
|
||||
agent.wallet_address,
|
||||
buyerTokenAccount
|
||||
);
|
||||
|
||||
// Create and sign transaction
|
||||
const transaction = new Transaction().add(...instruction);
|
||||
transaction.recentBlockhash = (
|
||||
await agent.connection.getLatestBlockhash()
|
||||
).blockhash;
|
||||
transaction.feePayer = agent.wallet_address;
|
||||
|
||||
// Sign and send transaction
|
||||
const signature = await agent.connection.sendTransaction(transaction, [
|
||||
agent.wallet
|
||||
]);
|
||||
|
||||
// Wait for confirmation
|
||||
const latestBlockhash = await agent.connection.getLatestBlockhash();
|
||||
await agent.connection.confirmTransaction({
|
||||
signature,
|
||||
blockhash: latestBlockhash.blockhash,
|
||||
lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
|
||||
});
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
signature,
|
||||
message: `Successfully registered ${name}.sol`
|
||||
};
|
||||
} catch (error: any) {
|
||||
return {
|
||||
status: "error",
|
||||
message: `Domain registration failed: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default registerDomainAction;
|
||||
61
src/actions/resolveDomain.ts
Normal file
61
src/actions/resolveDomain.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { Action } from "../types/action";
|
||||
import { SolanaAgentKit } from "../agent";
|
||||
import { z } from "zod";
|
||||
import { TldParser } from "@onsol/tldparser";
|
||||
|
||||
const resolveDomainAction: Action = {
|
||||
name: "solana_resolve_domain",
|
||||
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 new TldParser(agent.connection).getOwnerFromDomainTld(
|
||||
domain
|
||||
);
|
||||
|
||||
if (!tld) {
|
||||
return {
|
||||
status: "error",
|
||||
message: "Domain not found"
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
owner: tld.toBase58(),
|
||||
message: `Successfully resolved domain ${domain}`
|
||||
};
|
||||
} catch (error: any) {
|
||||
return {
|
||||
status: "error",
|
||||
message: `Failed to resolve domain: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default resolveDomainAction;
|
||||
69
src/actions/resolveSolDomain.ts
Normal file
69
src/actions/resolveSolDomain.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import { Action } from "../types/action";
|
||||
import { SolanaAgentKit } from "../agent";
|
||||
import { z } from "zod";
|
||||
import { resolve } from "@bonfida/spl-name-service";
|
||||
|
||||
const resolveSolDomainAction: Action = {
|
||||
name: "solana_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;
|
||||
|
||||
if (!domain || typeof domain !== "string") {
|
||||
return {
|
||||
status: "error",
|
||||
message: "Invalid domain. Expected a non-empty string."
|
||||
};
|
||||
}
|
||||
|
||||
// Remove .sol suffix if present for consistent handling
|
||||
const cleanDomain = domain.toLowerCase().endsWith(".sol")
|
||||
? domain.slice(0, -4)
|
||||
: domain;
|
||||
|
||||
const ownerAddress = await resolve(agent.connection, cleanDomain);
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
owner: ownerAddress.toBase58(),
|
||||
message: `Successfully resolved ${cleanDomain}.sol`
|
||||
};
|
||||
} catch (error: any) {
|
||||
return {
|
||||
status: "error",
|
||||
message: `Failed to resolve domain: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default resolveSolDomainAction;
|
||||
101
src/actions/stakeWithJup.ts
Normal file
101
src/actions/stakeWithJup.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
import { Action } from "../types/action";
|
||||
import { SolanaAgentKit } from "../agent";
|
||||
import { z } from "zod";
|
||||
import { VersionedTransaction } from "@solana/web3.js";
|
||||
|
||||
const stakeWithJupAction: Action = {
|
||||
name: "solana_stake_with_jup",
|
||||
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;
|
||||
|
||||
// Get staking transaction from Jupiter
|
||||
const res = await fetch(
|
||||
`https://worker.jup.ag/blinks/swap/So11111111111111111111111111111111111111112/jupSoLaHXQiZZTSfEWMTRRgpnyFm8f6sZdosWBjx93v/${amount}`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
account: agent.wallet.publicKey.toBase58(),
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
if (!res.ok) {
|
||||
return {
|
||||
status: "error",
|
||||
message: `Failed to get staking transaction: ${res.statusText}`
|
||||
};
|
||||
}
|
||||
|
||||
const data = await res.json();
|
||||
|
||||
// Deserialize and prepare transaction
|
||||
const txn = VersionedTransaction.deserialize(
|
||||
Buffer.from(data.transaction, "base64")
|
||||
);
|
||||
|
||||
const { blockhash } = await agent.connection.getLatestBlockhash();
|
||||
txn.message.recentBlockhash = blockhash;
|
||||
|
||||
// Sign and send transaction
|
||||
txn.sign([agent.wallet]);
|
||||
const signature = await agent.connection.sendTransaction(txn, {
|
||||
preflightCommitment: "confirmed",
|
||||
maxRetries: 3,
|
||||
});
|
||||
|
||||
// Confirm transaction
|
||||
const latestBlockhash = await agent.connection.getLatestBlockhash();
|
||||
await agent.connection.confirmTransaction({
|
||||
signature,
|
||||
blockhash: latestBlockhash.blockhash,
|
||||
lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
|
||||
});
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
signature,
|
||||
message: `Successfully staked ${amount} SOL for jupSOL`
|
||||
};
|
||||
} catch (error: any) {
|
||||
return {
|
||||
status: "error",
|
||||
message: `jupSOL staking failed: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default stakeWithJupAction;
|
||||
Reference in New Issue
Block a user