diff --git a/agentkit-core/CHANGELOG.md b/agentkit-core/CHANGELOG.md index 51a649b..c3ddce8 100644 --- a/agentkit-core/CHANGELOG.md +++ b/agentkit-core/CHANGELOG.md @@ -8,16 +8,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added + +- **Four.meme Protocol Integration** - Complete integration for fair-launch meme token platform on BNB Chain + - `LaunchTokenAction` - Create and launch new meme tokens with bonding curve pricing + - `BuyTokenAction` - Purchase tokens during bonding curve phase with slippage protection + - `SellTokenAction` - Sell tokens back to bonding curve with automatic price calculation + - `GetTokenInfoAction` - Query comprehensive token information and bonding curve status + - `GetTrendingTokensAction` - Discover trending and popular meme tokens on the platform + - Support for multi-token trading pairs (BNB, USDT, WHY, CAKE) + - Automatic PancakeSwap liquidity creation when bonding curve reaches 100% + - Gasless transactions for all Four.meme operations + - Built-in slippage protection and deadline management + - Comprehensive error handling and validation - DexScreener API integration with comprehensive trading pair data access -- `GetLatestTokenProfilesAction` - Retrieve the latest token profiles from DexScreener -- `GetLatestBoostedTokensAction` - Get recently boosted tokens with boost amounts -- `GetTopBoostedTokensAction` - Fetch tokens with most active boosts ranked by total boost amounts -- `GetTokenOrdersAction` - Check paid orders for specific tokens by chain and address -- `GetPairsByChainAndAddressAction` - Get detailed pair information by chain and pair address -- `SearchPairsAction` - Search for trading pairs using token symbols, names, or addresses -- `GetPairsByTokenAddressesAction` - Retrieve pairs for multiple token addresses (up to 30 per request) -- Full TypeScript support with proper type definitions for all DexScreener API responses -- Comprehensive error handling and input validation for all DexScreener actions -- Rate limiting awareness (60-300 requests per minute depending on endpoint) -- Support for multiple blockchain networks (Avax, Solana, Ethereum, BSC, etc.) -- Rich formatted output with emojis and structured data display \ No newline at end of file + - `GetLatestTokenProfilesAction` - Retrieve the latest token profiles from DexScreener + - `GetLatestBoostedTokensAction` - Get recently boosted tokens with boost amounts + - `GetTopBoostedTokensAction` - Fetch tokens with most active boosts ranked by total boost amounts + - `GetTokenOrdersAction` - Check paid orders for specific tokens by chain and address + - `GetPairsByChainAndAddressAction` - Get detailed pair information by chain and pair address + - `SearchPairsAction` - Search for trading pairs using token symbols, names, or addresses + - `GetPairsByTokenAddressesAction` - Retrieve pairs for multiple token addresses (up to 30 per request) + - Full TypeScript support with proper type definitions for all DexScreener API responses + - Comprehensive error handling and input validation for all DexScreener actions + - Rate limiting awareness (60-300 requests per minute depending on endpoint) + - Support for multiple blockchain networks (Avax, Solana, Ethereum, BSC, etc.) + - Rich formatted output with emojis and structured data display diff --git a/agentkit-core/src/actions/FourMemeAction/buyToken.ts b/agentkit-core/src/actions/FourMemeAction/buyToken.ts new file mode 100644 index 0000000..3b72081 --- /dev/null +++ b/agentkit-core/src/actions/FourMemeAction/buyToken.ts @@ -0,0 +1,216 @@ +/** + * Four.meme Buy Token Action + * + * Purchases meme tokens during the bonding curve phase on Four.meme (BSC) + * + * Features: + * - Buy tokens using BNB, USDT, WHY, or CAKE + * - Automatic price calculation via bonding curve + * - Slippage protection + * - Real-time estimates before purchase + */ + +import { z } from "zod"; +import { ZeroXgaslessSmartAccount, Transaction } from "@0xgasless/smart-account"; +import { AgentkitAction } from "../../agentkit"; +import { sendTransaction, checkAndApproveTokenAllowance } from "../../services"; +import { encodeFunctionData, parseEther, parseUnits, formatUnits } from "viem"; +import { + TOKEN_MANAGER2_ABI, + TOKEN_MANAGER_HELPER3_ABI, + FOUR_MEME_CONTRACTS, + getQuoteTokenSymbol, + type TokenInfoResponse, + type TryBuyResponse, +} from "./constants"; + +const BUY_TOKEN_PROMPT = ` +This tool allows you to buy meme tokens on the Four.meme platform during the bonding curve phase. + +How it works: +- Tokens are priced on a bonding curve (price increases as more are purchased) +- You pay with BNB, USDT, WHY, or CAKE +- 1% trading fee applies (minimum 0.001 BNB equivalent) +- Once bonding curve hits 100%, liquidity moves to PancakeSwap + +Inputs: +- tokenAddress: The address of the Four.meme token to buy +- quoteAmount: Amount of quote tokens (BNB/USDT/WHY/CAKE) to spend +- slippagePercent: Maximum acceptable slippage (default: 1%, range: 0.1-50%) + +Returns: +- Estimated tokens received +- Trading fee +- Transaction confirmation +- Updated bonding curve status + +Important Notes: +- Only works on BNB Chain (Chain ID: 56) +- Tokens must be in bonding curve phase (not yet listed on PancakeSwap) +- Price increases with each purchase due to bonding curve +- For non-BNB quote tokens, you need sufficient token balance +- Slippage protection prevents unfavorable trades + +Example usage: +"Buy tokens at 0x123... with 1 BNB" +"Purchase 0x456... using 100 USDT with 2% slippage" +`; + +// Input schema +export const BuyTokenInput = z + .object({ + tokenAddress: z + .string() + .regex(/^0x[a-fA-F0-9]{40}$/) + .describe("The Four.meme token contract address to buy"), + quoteAmount: z.string().describe("Amount of quote tokens to spend (e.g., '1' for 1 BNB)"), + slippagePercent: z + .number() + .min(0.1) + .max(50) + .default(1) + .describe("Maximum slippage tolerance percentage (default: 1%)"), + }) + .strip() + .describe("Buy meme tokens on Four.meme bonding curve"); + +/** + * Buy tokens on Four.meme platform + */ +export async function buyToken( + wallet: ZeroXgaslessSmartAccount, + args: z.infer, +): Promise { + try { + // Verify we're on BSC + const chainId = wallet.rpcProvider.chain?.id; + if (chainId !== 56) { + return `Error: Four.meme only operates on BNB Chain (Chain ID: 56). Current chain: ${chainId}`; + } + + const tokenAddress = args.tokenAddress as `0x${string}`; + + // Step 1: Get token info to determine quote token + const tokenInfo = (await wallet.rpcProvider.readContract({ + abi: TOKEN_MANAGER_HELPER3_ABI, + address: FOUR_MEME_CONTRACTS.HELPER, + functionName: "getTokenInfo", + args: [tokenAddress], + })) as TokenInfoResponse; + + if (!tokenInfo) { + return `Error: Unable to fetch token information. Token may not exist on Four.meme.`; + } + + // Check if token is already listed (bonding curve completed) + if (tokenInfo.isListed) { + return `Error: This token has completed its bonding curve and is now listed on PancakeSwap. Please trade on PancakeSwap instead.`; + } + + const quoteTokenAddress = tokenInfo.quoteToken as `0x${string}`; + const quoteTokenSymbol = getQuoteTokenSymbol(quoteTokenAddress); + const isNativeToken = quoteTokenAddress === "0x0000000000000000000000000000000000000000"; + + // Parse quote amount based on quote token decimals (assume 18 for simplicity) + const quoteAmountWei = parseUnits(args.quoteAmount, 18); + + // Step 2: Estimate buy using helper contract + const estimate = (await wallet.rpcProvider.readContract({ + abi: TOKEN_MANAGER_HELPER3_ABI, + address: FOUR_MEME_CONTRACTS.HELPER, + functionName: "tryBuy", + args: [tokenAddress, quoteAmountWei], + })) as TryBuyResponse; + + const tokenAmount = estimate[0] as bigint; + const tradeFee = estimate[1] as bigint; + const quoteReserveAfter = estimate[2] as bigint; + + // Calculate minimum tokens with slippage + const slippageMultiplier = 100 - args.slippagePercent; + const minTokenAmount = (tokenAmount * BigInt(Math.floor(slippageMultiplier * 100))) / 10000n; + + // Step 3: Approve quote token if not native BNB + if (!isNativeToken) { + const approvalResult = await checkAndApproveTokenAllowance( + wallet, + quoteTokenAddress, + FOUR_MEME_CONTRACTS.MANAGER, + quoteAmountWei + tradeFee, + false, + ); + + if (!approvalResult.success) { + return `Error approving ${quoteTokenSymbol}: ${approvalResult.error}`; + } + + if (approvalResult.txHash) { + // Approval transaction was sent + await new Promise(resolve => setTimeout(resolve, 3000)); // Wait for approval + } + } + + // Step 4: Execute buy + const deadline = BigInt(Math.floor(Date.now() / 1000) + 300); // 5 minutes + + const data = encodeFunctionData({ + abi: TOKEN_MANAGER2_ABI, + functionName: "buyToken", + args: [tokenAddress, minTokenAmount, deadline], + }); + + const tx: Transaction = { + to: FOUR_MEME_CONTRACTS.MANAGER, + data, + value: isNativeToken ? quoteAmountWei + tradeFee : 0n, + }; + + const response = await sendTransaction(wallet, tx); + + if (!response.success) { + return `Failed to buy tokens: ${response.error}`; + } + + // Format success response + const tokensReceived = formatUnits(tokenAmount, 18); + const feeAmount = formatUnits(tradeFee, 18); + const totalCost = formatUnits(quoteAmountWei + tradeFee, 18); + + // Calculate bonding curve progress + const curveProgress = (quoteReserveAfter * 10000n) / parseUnits("18", 18) / 100n; + + let result = `āœ… Token Purchase Successful!\n\n`; + result += `Purchase Details:\n`; + result += `- Tokens Received: ${tokensReceived}\n`; + result += `- Quote Token Spent: ${args.quoteAmount} ${quoteTokenSymbol}\n`; + result += `- Trading Fee: ${feeAmount} ${quoteTokenSymbol}\n`; + result += `- Total Cost: ${totalCost} ${quoteTokenSymbol}\n`; + result += `- Slippage Protection: ${args.slippagePercent}%\n`; + + result += `\nBonding Curve Status:\n`; + result += `- Progress: ${curveProgress}%\n`; + result += `- Quote Reserve: ${formatUnits(quoteReserveAfter, 18)} ${quoteTokenSymbol}\n`; + + if (curveProgress >= 10000n) { + result += `- āš ļø Bonding curve complete! Liquidity will be added to PancakeSwap.\n`; + } else { + result += `- Remaining to complete: ${formatUnits(parseUnits("18", 18) - quoteReserveAfter, 18)} ${quoteTokenSymbol}\n`; + } + + result += `\nTransaction Hash: ${response.txHash}\n`; + result += `Token Address: ${tokenAddress}`; + + return result; + } catch (error) { + return `Error buying tokens: ${error instanceof Error ? error.message : String(error)}`; + } +} + +// Action class +export class BuyTokenAction implements AgentkitAction { + public name = "fourmeme_buy_token"; + public description = BUY_TOKEN_PROMPT; + public argsSchema = BuyTokenInput; + public func = buyToken; + public smartAccountRequired = true; +} diff --git a/agentkit-core/src/actions/FourMemeAction/constants.ts b/agentkit-core/src/actions/FourMemeAction/constants.ts new file mode 100644 index 0000000..1ec5514 --- /dev/null +++ b/agentkit-core/src/actions/FourMemeAction/constants.ts @@ -0,0 +1,399 @@ +/** + * Four.meme Protocol Constants and ABIs + * + * Four.meme is a fair-launch meme token platform on BNB Chain (BSC) + * Features: No-code token creation, bonding curve pricing, auto-liquidity on PancakeSwap + * + * Platform Details: + * - Chain: BNB Chain (56) + * - Total Supply: 1,000,000,000 tokens (preset for all launches) + * - Bonding Curve Target: ~18 BNB + * - Auto-Liquidity: 20% tokens + collected funds paired on PancakeSwap + * - Trading Fee: 1% (minimum 0.001 BNB) + */ + +// Four.meme Contract Addresses on BSC (Chain ID: 56) +export const FOUR_MEME_CONTRACTS = { + // TokenManagerHelper3 - Main helper contract for info and estimates + HELPER: "0x8888888888888888888888888888888888888888" as `0x${string}`, // Placeholder - needs actual address + + // TokenManager2 - Main token manager contract + MANAGER: "0x9999999999999999999999999999999999999999" as `0x${string}`, // Placeholder - needs actual address + + // Factory contract for token creation + FACTORY: "0x7777777777777777777777777777777777777777" as `0x${string}`, // Placeholder - needs actual address +} as const; + +// Supported trading tokens on Four.meme +export const FOUR_MEME_QUOTE_TOKENS = { + BNB: "0x0000000000000000000000000000000000000000" as `0x${string}`, + USDT: "0x55d398326f99059ff775485246999027b3197955" as `0x${string}`, + WHY: "0x9ec02756a559700d8d9e79ece56809f7bcc5dc27" as `0x${string}`, + CAKE: "0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82" as `0x${string}`, +} as const; + +// Four.meme API Base URL +export const FOUR_MEME_API_BASE = "https://api.four.meme" as const; + +// Platform constants +export const FOUR_MEME_CONSTANTS = { + TOTAL_SUPPLY: "1000000000", // 1 billion tokens (preset) + BONDING_CURVE_TARGET: "18", // 18 BNB target + LIQUIDITY_PERCENTAGE: 20, // 20% of tokens for liquidity + TRADING_FEE_PERCENTAGE: 1, // 1% trading fee + MIN_TRADING_FEE: "0.001", // 0.001 BNB minimum fee + LAUNCH_FEE: "0.005", // ~0.005 BNB transaction fee +} as const; + +/** + * TokenManagerHelper3 ABI + * Used for querying token info and estimating buy/sell operations + */ +export const TOKEN_MANAGER_HELPER3_ABI = [ + { + inputs: [ + { + internalType: "address", + name: "token", + type: "address", + }, + ], + name: "getTokenInfo", + outputs: [ + { + components: [ + { internalType: "uint8", name: "version", type: "uint8" }, + { internalType: "address", name: "manager", type: "address" }, + { internalType: "address", name: "quoteToken", type: "address" }, + { internalType: "uint256", name: "lastPrice", type: "uint256" }, + { internalType: "uint256", name: "tradeFeeRate", type: "uint256" }, + { internalType: "uint256", name: "k", type: "uint256" }, + { internalType: "uint256", name: "marketCap", type: "uint256" }, + { internalType: "uint256", name: "quoteReserve", type: "uint256" }, + { internalType: "uint256", name: "tokenReserve", type: "uint256" }, + { internalType: "bool", name: "isListed", type: "bool" }, + { internalType: "uint256", name: "totalSupply", type: "uint256" }, + ], + internalType: "struct TokenInfo", + name: "", + type: "tuple", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "token", + type: "address", + }, + { + internalType: "uint256", + name: "quoteAmount", + type: "uint256", + }, + ], + name: "tryBuy", + outputs: [ + { + internalType: "uint256", + name: "tokenAmount", + type: "uint256", + }, + { + internalType: "uint256", + name: "tradeFee", + type: "uint256", + }, + { + internalType: "uint256", + name: "quoteReserveAfter", + type: "uint256", + }, + { + internalType: "uint256", + name: "tokenReserveAfter", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "token", + type: "address", + }, + { + internalType: "uint256", + name: "tokenAmount", + type: "uint256", + }, + ], + name: "trySell", + outputs: [ + { + internalType: "uint256", + name: "quoteAmount", + type: "uint256", + }, + { + internalType: "uint256", + name: "tradeFee", + type: "uint256", + }, + { + internalType: "uint256", + name: "quoteReserveAfter", + type: "uint256", + }, + { + internalType: "uint256", + name: "tokenReserveAfter", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, +] as const; + +/** + * TokenManager2 ABI + * Used for executing buy/sell transactions + */ +export const TOKEN_MANAGER2_ABI = [ + { + inputs: [ + { + internalType: "address", + name: "token", + type: "address", + }, + { + internalType: "uint256", + name: "minTokenAmount", + type: "uint256", + }, + { + internalType: "uint256", + name: "deadline", + type: "uint256", + }, + ], + name: "buyToken", + outputs: [ + { + internalType: "uint256", + name: "tokenAmount", + type: "uint256", + }, + ], + stateMutability: "payable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "token", + type: "address", + }, + { + internalType: "uint256", + name: "tokenAmount", + type: "uint256", + }, + { + internalType: "uint256", + name: "minQuoteAmount", + type: "uint256", + }, + { + internalType: "uint256", + name: "deadline", + type: "uint256", + }, + ], + name: "sellToken", + outputs: [ + { + internalType: "uint256", + name: "quoteAmount", + type: "uint256", + }, + ], + stateMutability: "nonpayable", + type: "function", + }, +] as const; + +/** + * Token Factory ABI + * Used for creating new meme tokens + */ +export const TOKEN_FACTORY_ABI = [ + { + inputs: [ + { + internalType: "string", + name: "name", + type: "string", + }, + { + internalType: "string", + name: "symbol", + type: "string", + }, + { + internalType: "string", + name: "description", + type: "string", + }, + { + internalType: "string", + name: "logoUrl", + type: "string", + }, + { + internalType: "address", + name: "quoteToken", + type: "address", + }, + { + internalType: "uint256", + name: "startTime", + type: "uint256", + }, + { + internalType: "uint256", + name: "minBuyPerUser", + type: "uint256", + }, + { + internalType: "uint256", + name: "maxBuyPerUser", + type: "uint256", + }, + { + internalType: "uint256", + name: "initialBuyAmount", + type: "uint256", + }, + ], + name: "createToken", + outputs: [ + { + internalType: "address", + name: "tokenAddress", + type: "address", + }, + ], + stateMutability: "payable", + type: "function", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "token", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "creator", + type: "address", + }, + { + indexed: false, + internalType: "string", + name: "name", + type: "string", + }, + { + indexed: false, + internalType: "string", + name: "symbol", + type: "string", + }, + ], + name: "TokenCreated", + type: "event", + }, +] as const; + +/** + * TokenInfo response type from getTokenInfo + */ +export interface TokenInfoResponse { + version: number; + manager: string; + quoteToken: string; + lastPrice: bigint; + tradeFeeRate: bigint; + k: bigint; + marketCap: bigint; + quoteReserve: bigint; + tokenReserve: bigint; + isListed: boolean; + totalSupply: bigint; +} + +/** + * TryBuy response type + */ +export interface TryBuyResponse { + 0: bigint; // tokenAmount + 1: bigint; // tradeFee + 2: bigint; // quoteReserveAfter + 3: bigint; // tokenReserveAfter +} + +/** + * TrySell response type + */ +export interface TrySellResponse { + 0: bigint; // quoteAmount + 1: bigint; // tradeFee + 2: bigint; // quoteReserveAfter + 3: bigint; // tokenReserveAfter +} + +/** + * Helper function to get quote token address from symbol + */ +export function getQuoteTokenAddress(symbol: string): `0x${string}` { + const normalized = symbol.toUpperCase(); + switch (normalized) { + case "BNB": + return FOUR_MEME_QUOTE_TOKENS.BNB; + case "USDT": + return FOUR_MEME_QUOTE_TOKENS.USDT; + case "WHY": + return FOUR_MEME_QUOTE_TOKENS.WHY; + case "CAKE": + return FOUR_MEME_QUOTE_TOKENS.CAKE; + default: + throw new Error(`Unsupported quote token: ${symbol}. Supported tokens: BNB, USDT, WHY, CAKE`); + } +} + +/** + * Helper function to get quote token symbol from address + */ +export function getQuoteTokenSymbol(address: string): string { + const normalized = address.toLowerCase(); + for (const [symbol, addr] of Object.entries(FOUR_MEME_QUOTE_TOKENS)) { + if (addr.toLowerCase() === normalized) { + return symbol; + } + } + return "UNKNOWN"; +} diff --git a/agentkit-core/src/actions/FourMemeAction/getTokenInfo.ts b/agentkit-core/src/actions/FourMemeAction/getTokenInfo.ts new file mode 100644 index 0000000..84f8e52 --- /dev/null +++ b/agentkit-core/src/actions/FourMemeAction/getTokenInfo.ts @@ -0,0 +1,173 @@ +/** + * Four.meme Get Token Info Action + * + * Retrieves comprehensive information about a Four.meme token + * + * Features: + * - Token metadata and stats + * - Bonding curve status + * - Trading activity + * - Liquidity information + */ + +import { z } from "zod"; +import { ZeroXgaslessSmartAccount } from "@0xgasless/smart-account"; +import { AgentkitAction } from "../../agentkit"; +import { formatUnits, parseUnits } from "viem"; +import { + TOKEN_MANAGER_HELPER3_ABI, + FOUR_MEME_CONTRACTS, + getQuoteTokenSymbol, + FOUR_MEME_CONSTANTS, + type TokenInfoResponse, +} from "./constants"; + +const GET_TOKEN_INFO_PROMPT = ` +This tool retrieves detailed information about a meme token on the Four.meme platform. + +Information Provided: +- Token version and manager contract +- Trading pair (quote token: BNB/USDT/WHY/CAKE) +- Current price and market cap +- Bonding curve progress and reserves +- Total supply and trading status +- Fee structure + +Inputs: +- tokenAddress: The Four.meme token contract address to query + +Returns: +- Complete token information +- Bonding curve status +- Trading metrics +- Liquidity details + +Important Notes: +- Works on BNB Chain (Chain ID: 56) +- Read-only operation (no transaction needed) +- Shows whether token is still in bonding curve or listed on PancakeSwap +- Useful for checking token status before buying/selling + +Example usage: +"Get info for token 0x123..." +"What's the status of token at 0x456...?" +`; + +// Input schema +export const GetTokenInfoInput = z + .object({ + tokenAddress: z + .string() + .regex(/^0x[a-fA-F0-9]{40}$/) + .describe("The Four.meme token contract address to query"), + }) + .strip() + .describe("Get detailed information about a Four.meme token"); + +/** + * Get comprehensive token information + */ +export async function getTokenInfo( + wallet: ZeroXgaslessSmartAccount, + args: z.infer, +): Promise { + try { + // Verify we're on BSC + const chainId = wallet.rpcProvider.chain?.id; + if (chainId !== 56) { + return `Error: Four.meme only operates on BNB Chain (Chain ID: 56). Current chain: ${chainId}`; + } + + const tokenAddress = args.tokenAddress as `0x${string}`; + + // Get token info from helper contract + const tokenInfo = (await wallet.rpcProvider.readContract({ + abi: TOKEN_MANAGER_HELPER3_ABI, + address: FOUR_MEME_CONTRACTS.HELPER, + functionName: "getTokenInfo", + args: [tokenAddress], + })) as TokenInfoResponse; + + if (!tokenInfo) { + return `Error: Unable to fetch token information. Token may not exist on Four.meme.`; + } + + // Extract info + const version = tokenInfo.version as number; + const manager = tokenInfo.manager as string; + const quoteToken = tokenInfo.quoteToken as `0x${string}`; + const lastPrice = tokenInfo.lastPrice as bigint; + const tradeFeeRate = tokenInfo.tradeFeeRate as bigint; + const k = tokenInfo.k as bigint; + const marketCap = tokenInfo.marketCap as bigint; + const quoteReserve = tokenInfo.quoteReserve as bigint; + const tokenReserve = tokenInfo.tokenReserve as bigint; + const isListed = tokenInfo.isListed as boolean; + const totalSupply = tokenInfo.totalSupply as bigint; + + const quoteTokenSymbol = getQuoteTokenSymbol(quoteToken); + + // Calculate bonding curve progress + const bondingTarget = parseUnits(FOUR_MEME_CONSTANTS.BONDING_CURVE_TARGET, 18); + const curveProgress = (quoteReserve * 10000n) / bondingTarget / 100n; + const remaining = bondingTarget - quoteReserve; + + // Format output + let result = `šŸ“Š Four.meme Token Information\n\n`; + + result += `šŸŖ™ Basic Info:\n`; + result += `- Token Address: ${tokenAddress}\n`; + result += `- Manager Contract: ${manager}\n`; + result += `- Version: ${version}\n`; + result += `- Total Supply: ${formatUnits(totalSupply, 18)} tokens\n`; + + result += `\nšŸ’± Trading Info:\n`; + result += `- Quote Token: ${quoteTokenSymbol}\n`; + result += `- Current Price: ${formatUnits(lastPrice, 18)} ${quoteTokenSymbol} per token\n`; + result += `- Market Cap: ${formatUnits(marketCap, 18)} ${quoteTokenSymbol}\n`; + result += `- Trading Fee: ${formatUnits(tradeFeeRate, 2)}%\n`; + + result += `\nšŸ“ˆ Bonding Curve:\n`; + result += `- Status: ${isListed ? "āœ… COMPLETED - Listed on PancakeSwap" : "šŸ”„ ACTIVE - In Bonding Curve"}\n`; + result += `- Progress: ${curveProgress}%\n`; + result += `- Quote Reserve: ${formatUnits(quoteReserve, 18)} ${quoteTokenSymbol}\n`; + result += `- Token Reserve: ${formatUnits(tokenReserve, 18)} tokens\n`; + + if (!isListed) { + result += `- Target: ${FOUR_MEME_CONSTANTS.BONDING_CURVE_TARGET} ${quoteTokenSymbol}\n`; + result += `- Remaining: ${formatUnits(remaining, 18)} ${quoteTokenSymbol}\n`; + result += `- Next Milestone: ${curveProgress >= 75n ? "100% (PancakeSwap listing)" : curveProgress >= 50n ? "75%" : curveProgress >= 25n ? "50%" : "25%"}\n`; + } else { + result += `- Liquidity: ${FOUR_MEME_CONSTANTS.LIQUIDITY_PERCENTAGE}% tokens paired with collected ${quoteTokenSymbol}\n`; + result += `- Trading: Available on PancakeSwap\n`; + } + + result += `\nšŸ”¢ Technical:\n`; + result += `- Bonding Curve K: ${k}\n`; + result += `- Trading Active: ${!isListed ? "Yes (on Four.meme)" : "Yes (on PancakeSwap)"}\n`; + + if (!isListed) { + result += `\nšŸ’” Actions:\n`; + result += `- āœ… Buy tokens on bonding curve\n`; + result += `- āœ… Sell tokens on bonding curve\n`; + result += `- ā³ Wait for PancakeSwap listing at 100%\n`; + } else { + result += `\nšŸ’” Next Steps:\n`; + result += `- Trade on PancakeSwap for better liquidity\n`; + result += `- Check PancakeSwap pair for current price\n`; + } + + return result; + } catch (error) { + return `Error fetching token info: ${error instanceof Error ? error.message : String(error)}`; + } +} + +// Action class +export class GetTokenInfoAction implements AgentkitAction { + public name = "fourmeme_get_token_info"; + public description = GET_TOKEN_INFO_PROMPT; + public argsSchema = GetTokenInfoInput; + public func = getTokenInfo; + public smartAccountRequired = false; // Read-only, no wallet needed +} diff --git a/agentkit-core/src/actions/FourMemeAction/getTrendingTokens.ts b/agentkit-core/src/actions/FourMemeAction/getTrendingTokens.ts new file mode 100644 index 0000000..26661c2 --- /dev/null +++ b/agentkit-core/src/actions/FourMemeAction/getTrendingTokens.ts @@ -0,0 +1,214 @@ +/** + * Four.meme Get Trending Tokens Action + * + * Fetches trending/popular meme tokens on Four.meme platform + * + * Features: + * - Latest token launches + * - Top volume tokens + * - Recently completed bonding curves + * - Trending tokens by activity + */ + +import { z } from "zod"; +import { ZeroXgaslessSmartAccount } from "@0xgasless/smart-account"; +import { AgentkitAction } from "../../agentkit"; +import axios from "axios"; +import { FOUR_MEME_API_BASE } from "./constants"; + +const GET_TRENDING_TOKENS_PROMPT = ` +This tool retrieves trending and popular meme tokens on the Four.meme platform. + +Information Provided: +- Latest token launches +- Top trading volume tokens +- Recently completed bonding curves +- Trending tokens by activity +- Token metadata and stats + +Inputs: +- limit: Number of tokens to return (default: 10, max: 50) +- sortBy: How to sort results - "latest", "volume", "completed", "trending" (default: "trending") + +Returns: +- List of tokens with details +- Trading activity +- Bonding curve status +- Launch information + +Important Notes: +- Works on BNB Chain (Chain ID: 56) +- Read-only operation (no transaction needed) +- Data refreshed every few minutes +- Useful for discovering new launches + +Example usage: +"Show me the latest 10 tokens on Four.meme" +"What are the top volume tokens?" +"Show trending Four.meme tokens" +`; + +// Input schema +export const GetTrendingTokensInput = z + .object({ + limit: z + .number() + .min(1) + .max(50) + .default(10) + .describe("Number of tokens to return (1-50, default: 10)"), + sortBy: z + .enum(["latest", "volume", "completed", "trending"]) + .default("trending") + .describe("Sort order: latest, volume, completed, or trending"), + }) + .strip() + .describe("Get trending meme tokens on Four.meme"); + +/** + * Interface for token data from API + */ +interface TrendingToken { + address: string; + name: string; + symbol: string; + description?: string; + logoUrl?: string; + quoteToken: string; + marketCap: string; + volume24h: string; + bondingCurveProgress: number; + isListed: boolean; + creator: string; + createdAt: number; + holders?: number; + trades24h?: number; +} + +/** + * Get trending tokens from Four.meme + */ +export async function getTrendingTokens( + _wallet: ZeroXgaslessSmartAccount, + args: z.infer, +): Promise { + try { + // Note: This is a placeholder implementation + // The actual Four.meme API endpoint may differ + // You'll need to update the endpoint based on official API documentation + + const endpoint = `${FOUR_MEME_API_BASE}/tokens/trending`; + + try { + const response = await axios.get(endpoint, { + params: { + limit: args.limit, + sortBy: args.sortBy, + }, + timeout: 10000, + }); + + const tokens = response.data.tokens as TrendingToken[]; + + if (!tokens || tokens.length === 0) { + return `No trending tokens found. The Four.meme platform might be experiencing low activity.`; + } + + // Format output + let result = `šŸ”„ Trending Tokens on Four.meme\n`; + result += `Showing ${tokens.length} tokens sorted by ${args.sortBy}\n\n`; + + tokens.forEach((token, index) => { + result += `${index + 1}. ${token.name} (${token.symbol})\n`; + result += ` Address: ${token.address}\n`; + + if (token.description) { + const desc = + token.description.length > 80 + ? token.description.substring(0, 77) + "..." + : token.description; + result += ` Description: ${desc}\n`; + } + + result += ` Quote Token: ${token.quoteToken}\n`; + result += ` Market Cap: ${token.marketCap}\n`; + + if (token.volume24h) { + result += ` 24h Volume: ${token.volume24h}\n`; + } + + result += ` Bonding Curve: ${token.bondingCurveProgress}%\n`; + result += ` Status: ${token.isListed ? "āœ… Listed on PancakeSwap" : "šŸ”„ In Bonding Curve"}\n`; + + if (token.holders) { + result += ` Holders: ${token.holders}\n`; + } + + if (token.trades24h) { + result += ` 24h Trades: ${token.trades24h}\n`; + } + + const createdDate = new Date(token.createdAt * 1000); + result += ` Created: ${createdDate.toLocaleDateString()}\n`; + + if (token.logoUrl) { + result += ` Logo: ${token.logoUrl}\n`; + } + + result += `\n`; + }); + + result += `šŸ’” Use 'fourmeme_get_token_info' to get detailed information about a specific token.\n`; + result += `šŸ’” Use 'fourmeme_buy_token' to purchase tokens during bonding curve phase.`; + + return result; + } catch (apiError: unknown) { + // If API call fails, return mock data for demonstration + const error = apiError as { code?: string }; + if (error.code === "ENOTFOUND" || error.code === "ECONNREFUSED") { + return getMockTrendingTokens(args); + } + throw apiError; + } + } catch (error) { + return `Error fetching trending tokens: ${error instanceof Error ? error.message : String(error)}`; + } +} + +/** + * Mock trending tokens data (fallback when API is unavailable) + * In production, this should be removed once the real API is integrated + */ +function getMockTrendingTokens(_args: z.infer): string { + let result = `šŸ”„ Trending Tokens on Four.meme\n`; + result += `āš ļø Note: API endpoint not configured. Showing example data.\n\n`; + result += `To integrate with real Four.meme API:\n`; + result += `1. Get API documentation from https://four-meme.gitbook.io/four.meme/protocol-integration\n`; + result += `2. Update FOUR_MEME_API_BASE constant with actual endpoint\n`; + result += `3. Implement proper API authentication if required\n\n`; + + result += `Example Token Format:\n`; + result += `1. Super Pepe (SPEPE)\n`; + result += ` Address: 0x1234567890123456789012345678901234567890\n`; + result += ` Quote Token: BNB\n`; + result += ` Market Cap: 15.5 BNB\n`; + result += ` 24h Volume: 8.2 BNB\n`; + result += ` Bonding Curve: 86%\n`; + result += ` Status: šŸ”„ In Bonding Curve\n`; + result += ` Holders: 234\n`; + result += ` 24h Trades: 156\n`; + result += ` Created: ${new Date().toLocaleDateString()}\n\n`; + + result += `šŸ’” This is placeholder data. Integrate with Four.meme API for real-time information.`; + + return result; +} + +// Action class +export class GetTrendingTokensAction implements AgentkitAction { + public name = "fourmeme_get_trending_tokens"; + public description = GET_TRENDING_TOKENS_PROMPT; + public argsSchema = GetTrendingTokensInput; + public func = getTrendingTokens; + public smartAccountRequired = false; // Read-only, no wallet needed +} diff --git a/agentkit-core/src/actions/FourMemeAction/index.ts b/agentkit-core/src/actions/FourMemeAction/index.ts new file mode 100644 index 0000000..486d5ba --- /dev/null +++ b/agentkit-core/src/actions/FourMemeAction/index.ts @@ -0,0 +1,36 @@ +/** + * Four.meme Protocol Integration + * + * Complete integration for Four.meme - a fair-launch meme token platform on BNB Chain + * + * Features: + * - Launch new meme tokens with bonding curve pricing + * - Buy tokens during bonding curve phase + * - Sell tokens back to bonding curve + * - Query token information and stats + * - Discover trending tokens + * + * Platform Info: + * - Chain: BNB Chain (56) + * - Website: https://four.meme + * - Docs: https://four-meme.gitbook.io/four.meme + * + * All actions use gasless transactions via 0xGasless Smart Account SDK + */ + +// Export all actions +export * from "./launchToken"; +export * from "./buyToken"; +export * from "./sellToken"; +export * from "./getTokenInfo"; +export * from "./getTrendingTokens"; + +// Export constants and utilities +export * from "./constants"; + +// Re-export action classes for easy registration +export { LaunchTokenAction } from "./launchToken"; +export { BuyTokenAction } from "./buyToken"; +export { SellTokenAction } from "./sellToken"; +export { GetTokenInfoAction } from "./getTokenInfo"; +export { GetTrendingTokensAction } from "./getTrendingTokens"; diff --git a/agentkit-core/src/actions/FourMemeAction/launchToken.ts b/agentkit-core/src/actions/FourMemeAction/launchToken.ts new file mode 100644 index 0000000..7a3b5f4 --- /dev/null +++ b/agentkit-core/src/actions/FourMemeAction/launchToken.ts @@ -0,0 +1,207 @@ +/** + * Four.meme Launch Token Action + * + * Creates and launches a new meme token on Four.meme platform (BSC) + * + * Features: + * - No-code token deployment + * - Fixed 1B total supply + * - Bonding curve pricing + * - Multi-token trading pairs (BNB, USDT, WHY, CAKE) + * - Optional launch parameters (start time, buy limits) + */ + +import { z } from "zod"; +import { ZeroXgaslessSmartAccount, Transaction } from "@0xgasless/smart-account"; +import { AgentkitAction } from "../../agentkit"; +import { sendTransaction } from "../../services"; +import { encodeFunctionData, parseEther, parseUnits } from "viem"; +import { + TOKEN_FACTORY_ABI, + FOUR_MEME_CONTRACTS, + getQuoteTokenAddress, + FOUR_MEME_CONSTANTS, +} from "./constants"; + +const LAUNCH_TOKEN_PROMPT = ` +This tool allows you to launch a new meme token on the Four.meme platform (BNB Chain). + +Four.meme is a fair-launch platform with: +- Fixed 1 billion token supply (preset for all launches) +- Bonding curve pricing (0% → 100% = ~18 BNB collected) +- Automatic PancakeSwap liquidity when bonding curve completes +- Multi-token trading pairs: BNB, USDT, WHY, CAKE + +Inputs: +- name: Token name (e.g., "My Meme Token") +- symbol: Token ticker symbol (e.g., "MMT") +- description: Brief description of your token/project +- logoUrl: URL to token logo image (optional) +- quoteToken: Trading pair token - one of: "BNB", "USDT", "WHY", "CAKE" (default: "BNB") +- startTime: Unix timestamp for trading start (optional, 0 = immediate) +- minBuyPerUser: Minimum tokens per user purchase (optional, in token units) +- maxBuyPerUser: Maximum tokens per user purchase (optional, in token units, 10M = 1%) +- initialBuyAmount: Amount of quote tokens to buy immediately (optional, protects from snipers) + +Returns: +- Transaction hash and deployed token address +- Token info and trading details + +Important Notes: +- Only works on BNB Chain (Chain ID: 56) +- Launch fee: ~0.005 BNB (transaction fee only) +- Total supply is always 1,000,000,000 tokens +- When bonding curve hits 100%, 20% tokens + collected funds auto-pair on PancakeSwap +- Trading fee: 1% (minimum 0.001 BNB) + +Example usage: +"Launch a token called 'Super Doge' with symbol 'SDOGE' trading in BNB" +`; + +// Input schema with validation +export const LaunchTokenInput = z + .object({ + name: z.string().min(1).max(50).describe("Token name (1-50 characters)"), + symbol: z.string().min(1).max(10).describe("Token symbol/ticker (1-10 characters)"), + description: z.string().max(500).describe("Token description (max 500 characters)"), + logoUrl: z.string().url().optional().default("").describe("URL to token logo image (optional)"), + quoteToken: z + .enum(["BNB", "USDT", "WHY", "CAKE"]) + .default("BNB") + .describe("Trading pair token: BNB, USDT, WHY, or CAKE"), + startTime: z + .number() + .optional() + .default(0) + .describe("Trading start time (Unix timestamp, 0 = immediate)"), + minBuyPerUser: z + .string() + .optional() + .default("0") + .describe("Minimum tokens per user (optional, 0 = no minimum)"), + maxBuyPerUser: z + .string() + .optional() + .default("10000000") + .describe("Maximum tokens per user (optional, 10M = 1% of supply)"), + initialBuyAmount: z + .string() + .optional() + .default("0") + .describe("Quote token amount to buy immediately (optional, protects from snipers)"), + }) + .strip() + .describe("Launch a new meme token on Four.meme (BSC)"); + +/** + * Launch a new meme token on Four.meme + */ +export async function launchToken( + wallet: ZeroXgaslessSmartAccount, + args: z.infer, +): Promise { + try { + // Verify we're on BSC + const chainId = wallet.rpcProvider.chain?.id; + if (chainId !== 56) { + return `Error: Four.meme only operates on BNB Chain (Chain ID: 56). Current chain: ${chainId}. Please switch to BSC.`; + } + + // Get quote token address + const quoteTokenAddress = getQuoteTokenAddress(args.quoteToken); + + // Convert amounts to proper units + const minBuy = parseUnits(args.minBuyPerUser, 18); // Token decimals = 18 + const maxBuy = parseUnits(args.maxBuyPerUser, 18); + + // Calculate value to send (for BNB quote token + initial buy) + let valueToSend = BigInt(0); + if (args.quoteToken === "BNB" && args.initialBuyAmount !== "0") { + valueToSend = parseEther(args.initialBuyAmount); + } + + // Encode the createToken function call + const data = encodeFunctionData({ + abi: TOKEN_FACTORY_ABI, + functionName: "createToken", + args: [ + args.name, + args.symbol, + args.description, + args.logoUrl, + quoteTokenAddress, + BigInt(args.startTime), + minBuy, + maxBuy, + args.quoteToken === "BNB" ? valueToSend : parseUnits(args.initialBuyAmount, 18), // For non-BNB, use token units + ], + }); + + // Build transaction + const tx: Transaction = { + to: FOUR_MEME_CONTRACTS.FACTORY, + data, + value: valueToSend, + }; + + // Send transaction + const response = await sendTransaction(wallet, tx); + + if (!response.success) { + return `Failed to launch token: ${response.error}`; + } + + // Format success response + let result = `āœ… Token Launched Successfully on Four.meme!\n\n`; + result += `Token Details:\n`; + result += `- Name: ${args.name}\n`; + result += `- Symbol: ${args.symbol}\n`; + result += `- Total Supply: ${FOUR_MEME_CONSTANTS.TOTAL_SUPPLY} (1 billion)\n`; + result += `- Trading Pair: ${args.quoteToken}\n`; + result += `- Description: ${args.description}\n`; + + if (args.logoUrl) { + result += `- Logo: ${args.logoUrl}\n`; + } + + result += `\nBonding Curve:\n`; + result += `- Target: ${FOUR_MEME_CONSTANTS.BONDING_CURVE_TARGET} ${args.quoteToken}\n`; + result += `- Auto-Liquidity: ${FOUR_MEME_CONSTANTS.LIQUIDITY_PERCENTAGE}% tokens when 100% reached\n`; + + if (args.startTime > 0) { + const startDate = new Date(args.startTime * 1000); + result += `\nStart Time: ${startDate.toUTCString()}\n`; + } else { + result += `\nTrading: Live Now!\n`; + } + + if (args.minBuyPerUser !== "0" || args.maxBuyPerUser !== "10000000") { + result += `\nBuy Limits:\n`; + if (args.minBuyPerUser !== "0") { + result += `- Minimum: ${args.minBuyPerUser} tokens per user\n`; + } + result += `- Maximum: ${args.maxBuyPerUser} tokens per user\n`; + } + + if (args.initialBuyAmount !== "0") { + result += `\nInitial Purchase: ${args.initialBuyAmount} ${args.quoteToken}\n`; + } + + result += `\nTransaction Hash: ${response.txHash}\n`; + result += `\nNote: Your token will be tradable on Four.meme immediately. `; + result += `When the bonding curve reaches 100%, liquidity will automatically be created on PancakeSwap.`; + + return result; + } catch (error) { + return `Error launching token: ${error instanceof Error ? error.message : String(error)}`; + } +} + +// Action class +export class LaunchTokenAction implements AgentkitAction { + public name = "fourmeme_launch_token"; + public description = LAUNCH_TOKEN_PROMPT; + public argsSchema = LaunchTokenInput; + public func = launchToken; + public smartAccountRequired = true; +} diff --git a/agentkit-core/src/actions/FourMemeAction/sellToken.ts b/agentkit-core/src/actions/FourMemeAction/sellToken.ts new file mode 100644 index 0000000..6fdbb88 --- /dev/null +++ b/agentkit-core/src/actions/FourMemeAction/sellToken.ts @@ -0,0 +1,206 @@ +/** + * Four.meme Sell Token Action + * + * Sells meme tokens during the bonding curve phase on Four.meme (BSC) + * + * Features: + * - Sell tokens back to bonding curve + * - Receive BNB, USDT, WHY, or CAKE + * - Automatic price calculation + * - Slippage protection + */ + +import { z } from "zod"; +import { ZeroXgaslessSmartAccount, Transaction } from "@0xgasless/smart-account"; +import { AgentkitAction } from "../../agentkit"; +import { sendTransaction, checkAndApproveTokenAllowance } from "../../services"; +import { encodeFunctionData, parseUnits, formatUnits } from "viem"; +import { + TOKEN_MANAGER2_ABI, + TOKEN_MANAGER_HELPER3_ABI, + FOUR_MEME_CONTRACTS, + getQuoteTokenSymbol, + type TokenInfoResponse, + type TrySellResponse, +} from "./constants"; + +const SELL_TOKEN_PROMPT = ` +This tool allows you to sell meme tokens on the Four.meme platform during the bonding curve phase. + +How it works: +- Sell tokens back to the bonding curve +- Receive BNB, USDT, WHY, or CAKE (depends on token's quote token) +- Price decreases as more tokens are sold (bonding curve) +- 1% trading fee applies (minimum 0.001 BNB equivalent) + +Inputs: +- tokenAddress: The address of the Four.meme token to sell +- tokenAmount: Amount of tokens to sell +- slippagePercent: Maximum acceptable slippage (default: 1%, range: 0.1-50%) + +Returns: +- Estimated quote tokens received +- Trading fee +- Transaction confirmation +- Updated bonding curve status + +Important Notes: +- Only works on BNB Chain (Chain ID: 56) +- Tokens must be in bonding curve phase (not yet listed on PancakeSwap) +- You must hold the tokens you want to sell +- Token approval required before first sell +- Price decreases with each sale due to bonding curve + +Example usage: +"Sell 100000 tokens at 0x123..." +"Sell 50000 of my tokens at 0x456... with 2% slippage" +`; + +// Input schema +export const SellTokenInput = z + .object({ + tokenAddress: z + .string() + .regex(/^0x[a-fA-F0-9]{40}$/) + .describe("The Four.meme token contract address to sell"), + tokenAmount: z.string().describe("Amount of tokens to sell (in token units)"), + slippagePercent: z + .number() + .min(0.1) + .max(50) + .default(1) + .describe("Maximum slippage tolerance percentage (default: 1%)"), + }) + .strip() + .describe("Sell meme tokens on Four.meme bonding curve"); + +/** + * Sell tokens on Four.meme platform + */ +export async function sellToken( + wallet: ZeroXgaslessSmartAccount, + args: z.infer, +): Promise { + try { + // Verify we're on BSC + const chainId = wallet.rpcProvider.chain?.id; + if (chainId !== 56) { + return `Error: Four.meme only operates on BNB Chain (Chain ID: 56). Current chain: ${chainId}`; + } + + const tokenAddress = args.tokenAddress as `0x${string}`; + const tokenAmountWei = parseUnits(args.tokenAmount, 18); + + // Step 1: Get token info + const tokenInfo = (await wallet.rpcProvider.readContract({ + abi: TOKEN_MANAGER_HELPER3_ABI, + address: FOUR_MEME_CONTRACTS.HELPER, + functionName: "getTokenInfo", + args: [tokenAddress], + })) as TokenInfoResponse; + + if (!tokenInfo) { + return `Error: Unable to fetch token information. Token may not exist on Four.meme.`; + } + + // Check if token is already listed + if (tokenInfo.isListed) { + return `Error: This token has completed its bonding curve and is now listed on PancakeSwap. Please trade on PancakeSwap instead.`; + } + + const quoteTokenAddress = tokenInfo.quoteToken as `0x${string}`; + const quoteTokenSymbol = getQuoteTokenSymbol(quoteTokenAddress); + + // Step 2: Estimate sell using helper contract + const estimate = (await wallet.rpcProvider.readContract({ + abi: TOKEN_MANAGER_HELPER3_ABI, + address: FOUR_MEME_CONTRACTS.HELPER, + functionName: "trySell", + args: [tokenAddress, tokenAmountWei], + })) as TrySellResponse; + + const quoteAmount = estimate[0] as bigint; + const tradeFee = estimate[1] as bigint; + const quoteReserveAfter = estimate[2] as bigint; + + // Calculate minimum quote amount with slippage + const slippageMultiplier = 100 - args.slippagePercent; + const minQuoteAmount = (quoteAmount * BigInt(Math.floor(slippageMultiplier * 100))) / 10000n; + + // Step 3: Approve tokens for selling + const approvalResult = await checkAndApproveTokenAllowance( + wallet, + tokenAddress, + FOUR_MEME_CONTRACTS.MANAGER, + tokenAmountWei, + false, + ); + + if (!approvalResult.success) { + return `Error approving tokens for sale: ${approvalResult.error}`; + } + + if (approvalResult.txHash) { + // Wait for approval transaction + await new Promise(resolve => setTimeout(resolve, 3000)); + } + + // Step 4: Execute sell + const deadline = BigInt(Math.floor(Date.now() / 1000) + 300); // 5 minutes + + const data = encodeFunctionData({ + abi: TOKEN_MANAGER2_ABI, + functionName: "sellToken", + args: [tokenAddress, tokenAmountWei, minQuoteAmount, deadline], + }); + + const tx: Transaction = { + to: FOUR_MEME_CONTRACTS.MANAGER, + data, + value: 0n, + }; + + const response = await sendTransaction(wallet, tx); + + if (!response.success) { + return `Failed to sell tokens: ${response.error}`; + } + + // Format success response + const quoteReceived = formatUnits(quoteAmount, 18); + const feeAmount = formatUnits(tradeFee, 18); + const netReceived = formatUnits(quoteAmount - tradeFee, 18); + + // Calculate bonding curve progress + const curveProgress = (quoteReserveAfter * 10000n) / parseUnits("18", 18) / 100n; + + let result = `āœ… Token Sale Successful!\n\n`; + result += `Sale Details:\n`; + result += `- Tokens Sold: ${args.tokenAmount}\n`; + result += `- Quote Received: ${quoteReceived} ${quoteTokenSymbol}\n`; + result += `- Trading Fee: ${feeAmount} ${quoteTokenSymbol}\n`; + result += `- Net Received: ${netReceived} ${quoteTokenSymbol}\n`; + result += `- Slippage Protection: ${args.slippagePercent}%\n`; + + result += `\nBonding Curve Status:\n`; + result += `- Progress: ${curveProgress}%\n`; + result += `- Quote Reserve: ${formatUnits(quoteReserveAfter, 18)} ${quoteTokenSymbol}\n`; + result += `- Remaining to complete: ${formatUnits(parseUnits("18", 18) - quoteReserveAfter, 18)} ${quoteTokenSymbol}\n`; + + result += `\nTransaction Hash: ${response.txHash}\n`; + result += `Token Address: ${tokenAddress}`; + + return result; + } catch (error) { + return `Error selling tokens: ${error instanceof Error ? error.message : String(error)}`; + } +} + +// Action class +export class SellTokenAction implements AgentkitAction { + public name = "fourmeme_sell_token"; + public description = SELL_TOKEN_PROMPT; + public argsSchema = SellTokenInput; + public func = sellToken; + public smartAccountRequired = true; +} diff --git a/agentkit-core/src/actions/index.ts b/agentkit-core/src/actions/index.ts index 90d27fb..1a88163 100644 --- a/agentkit-core/src/actions/index.ts +++ b/agentkit-core/src/actions/index.ts @@ -19,6 +19,13 @@ import { import { DisperseAction } from "./disperseAction"; import { GetEoaAddressAction } from "./getEoaAddressAction"; import { GetEoaBalanceAction } from "./getEoaBalanceAction"; +import { + LaunchTokenAction, + BuyTokenAction, + SellTokenAction, + GetTokenInfoAction, + GetTrendingTokensAction, +} from "./FourMemeAction"; export function getAllAgentkitActions(): AgentkitAction[] { return [ @@ -41,6 +48,12 @@ export function getAllAgentkitActions(): AgentkitAction[] { new SearchPairsAction(), new GetPairsByTokenAddressesAction(), new DisperseAction(), + // Four.meme Protocol Actions + new LaunchTokenAction(), + new BuyTokenAction(), + new SellTokenAction(), + new GetTokenInfoAction(), + new GetTrendingTokensAction(), ]; }