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) => { 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;