import assert from 'assert'; import { Connection, PublicKey, Transaction } from '@solana/web3.js' import { TOKEN_PROGRAM_ID, createTransferInstruction, createAssociatedTokenAccountInstruction, ASSOCIATED_TOKEN_PROGRAM_ID } from '@solana/spl-token' import { WalletType } from './types' assert(process.env.NEXT_PUBLIC_SOLANA_RPC_URL, 'SOLANA_RPC_URL is required'); assert(process.env.NEXT_PUBLIC_MTM_TOKEN_MINT, 'MTM_TOKEN_MINT is required'); assert(process.env.NEXT_PUBLIC_PAYMENT_RECEIVER_ADDRESS, 'PAYMENT_RECEIVER_ADDRESS is required'); const MTM_TOKEN_MINT = process.env.NEXT_PUBLIC_MTM_TOKEN_MINT; const PAYMENT_RECEIVER_ADDRESS = process.env.NEXT_PUBLIC_PAYMENT_RECEIVER_ADDRESS; const SOLANA_RPC_URL = process.env.NEXT_PUBLIC_SOLANA_RPC_URL; const SOLANA_WEBSOCKET_URL = process.env.NEXT_PUBLIC_SOLANA_WEBSOCKET_URL; const USDC_MINT = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'; // USDC mint address const connection = new Connection( SOLANA_RPC_URL, { commitment: 'confirmed', wsEndpoint: SOLANA_WEBSOCKET_URL, confirmTransactionInitialTimeout: 60000, } ) export interface PaymentResult { success: boolean transactionSignature?: string error?: string } async function findAssociatedTokenAddress( walletAddress: PublicKey, tokenMintAddress: PublicKey ): Promise { return PublicKey.findProgramAddressSync( [ walletAddress.toBuffer(), TOKEN_PROGRAM_ID.toBuffer(), tokenMintAddress.toBuffer(), ], ASSOCIATED_TOKEN_PROGRAM_ID )[0] } export async function getUSDCToMTMQuote() { const url = `https://api.jup.ag/price/v2?ids=${USDC_MINT}&vsToken=${MTM_TOKEN_MINT}`; const response = await fetch(url); if (!response.ok) { throw new Error(`Failed to fetch quote: ${response.statusText}`); } const quoteResponse = await response.json(); const price = quoteResponse['data'][USDC_MINT]['price'] return price; } interface WalletAdapter { signAndSendTransaction(transaction: Transaction): Promise<{ signature: string }> } export async function processMTMPayment( walletPublicKey: string, tokenAmount: number, walletType: WalletType ): Promise { try { let wallet: WalletAdapter | null = null; if (walletType === 'phantom') { wallet = window.phantom?.solana || null; } else if (walletType === 'solflare') { wallet = window.solflare || null; } if (!wallet) { throw new Error(`${walletType} wallet not found`) } const senderPublicKey = new PublicKey(walletPublicKey) const mintPublicKey = new PublicKey(MTM_TOKEN_MINT) const receiverPublicKey = new PublicKey(PAYMENT_RECEIVER_ADDRESS) console.log('Processing payment with keys:', { sender: senderPublicKey.toBase58(), mint: mintPublicKey.toBase58(), receiver: receiverPublicKey.toBase58(), }) const senderATA = await findAssociatedTokenAddress( senderPublicKey, mintPublicKey ) const receiverATA = await findAssociatedTokenAddress( receiverPublicKey, mintPublicKey ) console.log('Token accounts:', { senderATA: senderATA.toBase58(), receiverATA: receiverATA.toBase58(), }) const transaction = new Transaction() const [senderATAInfo, receiverATAInfo] = await Promise.all([ connection.getAccountInfo(senderATA), connection.getAccountInfo(receiverATA), ]) if (!receiverATAInfo) { console.log('Creating receiver token account') transaction.add( createAssociatedTokenAccountInstruction( senderPublicKey, receiverATA, receiverPublicKey, mintPublicKey ) ) } if (!senderATAInfo) { console.log('Creating sender token account') transaction.add( createAssociatedTokenAccountInstruction( senderPublicKey, senderATA, senderPublicKey, mintPublicKey ) ) } transaction.add( createTransferInstruction( senderATA, receiverATA, senderPublicKey, BigInt(tokenAmount * (10 ** 6)) ) ) const latestBlockhash = await connection.getLatestBlockhash('confirmed') transaction.recentBlockhash = latestBlockhash.blockhash transaction.feePayer = senderPublicKey console.log('Sending transaction...') const { signature } = await wallet.signAndSendTransaction(transaction) console.log('Transaction sent:', signature) const confirmation = await connection.confirmTransaction({ signature, blockhash: latestBlockhash.blockhash, lastValidBlockHeight: latestBlockhash.lastValidBlockHeight, }, 'confirmed') if (confirmation.value.err) { console.error('Transaction error:', confirmation.value.err) throw new Error(`Transaction failed: ${JSON.stringify(confirmation.value.err)}`) } return { success: true, transactionSignature: signature }; } catch (error) { console.error('Payment error:', error) return { success: false, error: error instanceof Error ? error.message : 'Payment failed' } } }