import assert from 'assert'; import BN from 'bn.js'; import { Connection } from '@solana/web3.js'; import { TOKEN_PROGRAM_ID } from '@solana/spl-token'; import { AppDataSource } from '../data-source'; import { Payment } from '../entity/Payment'; assert(process.env.NEXT_PUBLIC_SOLANA_RPC_URL, 'SOLANA_RPC_URL is required'); const SOLANA_RPC_URL = process.env.NEXT_PUBLIC_SOLANA_RPC_URL; const SOLANA_WEBSOCKET_URL = process.env.NEXT_PUBLIC_SOLANA_WEBSOCKET_URL; const connection = new Connection( SOLANA_RPC_URL, { commitment: 'confirmed', wsEndpoint: SOLANA_WEBSOCKET_URL, confirmTransactionInitialTimeout: 60000, } ); export async function isSignatureUsed(transactionSignature: string): Promise { const paymentRepository = AppDataSource.getRepository(Payment); const payment = await paymentRepository.findOneBy({ transactionSignature }); if (payment) { return true; } return false; } export async function markSignatureAsUsed(transactionSignature: string): Promise { await AppDataSource.transaction(async (transactionalEntityManager) => { const paymentRepository = transactionalEntityManager.getRepository(Payment); // Check if the payment with the given signature already exists const exists = await paymentRepository.exists({ where: { transactionSignature } }); // If not, create a new payment entry if (!exists) { const newPayment = paymentRepository.create({ transactionSignature }); await paymentRepository.save(newPayment); } }); } export async function verifyPayment( transactionSignature: string, tokenAmount: BN, ): Promise { try { // Check if the signature is already used if (await isSignatureUsed(transactionSignature)) { return false; } const transaction = await connection.getParsedTransaction(transactionSignature, 'confirmed'); if (!transaction) { throw new Error('Transaction not found'); } const transferInstruction = transaction.transaction.message.instructions.find( (instr) => 'parsed' in instr && instr.programId.equals(TOKEN_PROGRAM_ID) ); if (!transferInstruction || !('parsed' in transferInstruction)) { throw new Error('Transfer instruction not found'); } const { parsed } = transferInstruction; const { info } = parsed; const { amount } = info; const transactionAmount = new BN(amount); if (transactionAmount.gte(tokenAmount)) { return true; } console.log('Transaction amount is less than minimum amount. Rejecting request'); return false; } catch (error) { console.error('Verification error:', error); return false; } }