UNPKG

transfer-token

Version:

Plugin for transferring tokens to different wallets in API City

202 lines (173 loc) 6.66 kB
import { Connection, PublicKey, Transaction } from '@solana/web3.js'; import { TOKEN_PROGRAM_ID, getAccount, createTransferInstruction, getAssociatedTokenAddress } from '@solana/spl-token'; import { BasePlugin, PluginContext } from 'api-city-sdk'; export class TransferTokenPlugin extends BasePlugin { protected context!: PluginContext; private connection: Connection; private readonly BASE_COMMAND = 'transfer'; constructor() { super({ name: "Token Transfer Manager", description: "Transfer tokens to different wallets on Solana", version: "1.0.0", author: "API City", permissions: [], entryPoints: { main: "transfer" } }); // Initialize connection this.connection = new Connection( process.env.NEXT_PUBLIC_SOLANA_RPC || 'https://api.mainnet-beta.solana.com', { commitment: 'confirmed' } ); } async initialize(context: PluginContext): Promise<void> { this.context = context; } render(): React.ReactNode { return null; } private async getTokenAccounts(publicKey: PublicKey): Promise<{ pubkey: PublicKey; account: any }[]> { const accounts = await this.connection.getParsedTokenAccountsByOwner(publicKey, { programId: TOKEN_PROGRAM_ID, }); return accounts.value.filter(({ account }) => { const info = account.data.parsed.info; return Number(info.tokenAmount.amount) > 0; }); } private async transferTokens( fromPublicKey: PublicKey, toPublicKey: PublicKey, sourceTokenAccount: PublicKey, amount: number ): Promise<void> { try { const destinationTokenAccount = await getAssociatedTokenAddress( new PublicKey(sourceTokenAccount.toString()), toPublicKey ); const latestBlockhash = await this.connection.getLatestBlockhash(); const transaction = new Transaction(latestBlockhash); transaction.feePayer = fromPublicKey; transaction.add( createTransferInstruction( sourceTokenAccount, destinationTokenAccount, fromPublicKey, amount, [], TOKEN_PROGRAM_ID ) ); if (!this.context.wallet.signTransaction) { throw new Error("Wallet does not support transaction signing"); } this.emit('message', { content: "Sending transaction for approval..." }); const signedTransaction = await this.context.wallet.signTransaction(transaction); const signature = await this.connection.sendRawTransaction( signedTransaction.serialize(), { preflightCommitment: 'confirmed', maxRetries: 10 } ); await this.connection.confirmTransaction({ signature, ...latestBlockhash }); this.emit('message', { content: `Successfully transferred tokens.\nTransaction: https://solscan.io/tx/${signature}` }); } catch (error: any) { throw new Error(`Transfer failed: ${error.message}`); } } async handleCommand(command: string, args: string[]): Promise<void> { if (!command.startsWith(this.BASE_COMMAND)) { this.emit('message', { content: "Unknown command" }); return; } try { const publicKey = this.context.wallet.publicKey; if (!publicKey) { this.emit('message', { content: "Wallet not connected" }); return; } const subCommand = args[0] || 'help'; switch (subCommand) { case 'help': this.emit('message', { content: `Available commands: - /transfer help: Show this help message - /transfer list: Show list of token accounts with balances - /transfer [token_account] [recipient_address] [amount]: Transfer tokens to another wallet` }); break; case 'list': const tokenAccounts = await this.getTokenAccounts(publicKey); if (tokenAccounts.length === 0) { this.emit('message', { content: "No token accounts with balance found" }); } else { const accountList = tokenAccounts.map(({ pubkey, account }, index) => { const info = account.data.parsed.info; return `${index + 1}. ${pubkey.toString()} - Balance: ${info.tokenAmount.uiAmount} ${info.mint}`; }).join('\n'); this.emit('message', { content: `Found ${tokenAccounts.length} token accounts with balance:\n${accountList}` }); } break; default: // Handle transfer if (args.length !== 3) { this.emit('message', { content: "Please provide: token_account recipient_address amount" }); return; } const [tokenAccount, recipientAddress, amountStr] = args; try { const sourceAccount = new PublicKey(tokenAccount); const recipientPublicKey = new PublicKey(recipientAddress); const amount = parseFloat(amountStr); if (isNaN(amount) || amount <= 0) { throw new Error("Invalid amount"); } await this.transferTokens( publicKey, recipientPublicKey, sourceAccount, amount ); } catch (err: any) { this.emit('message', { content: `Invalid parameters: ${err.message}` }); return; } break; } } catch (err: any) { console.error("Error in command execution:", err); this.emit('message', { content: `Error: ${err.message}` }); } } getCommands(): { command: string; description: string; usage: string; }[] { return [ { command: this.BASE_COMMAND, description: "Transfer tokens to different wallets", usage: `${this.BASE_COMMAND} <help|list|token_account recipient_address amount>` }, { command: `${this.BASE_COMMAND} help`, description: "Show available commands for token transfers", usage: `${this.BASE_COMMAND} help` }, { command: `${this.BASE_COMMAND} list`, description: "List all token accounts with balances", usage: `${this.BASE_COMMAND} list` }, { command: `${this.BASE_COMMAND} transfer`, description: "Transfer tokens to another wallet", usage: `${this.BASE_COMMAND} <token_account> <recipient_address> <amount>` } ]; } } export default TransferTokenPlugin;