Optimize getting parsed tx from tx hash

This commit is contained in:
Shreerang Kale 2025-07-28 17:55:48 +05:30
parent ed08ace0a4
commit 438acd5e29
4 changed files with 28 additions and 20 deletions

View File

@ -1,8 +1,9 @@
# Client-side environment variables must be prefixed with NEXT_PUBLIC_
# Solana Payment Configuration
# TODO: Use different RPC URL
NEXT_PUBLIC_SOLANA_RPC_URL=https://skilled-prettiest-seed.solana-mainnet.quiknode.pro/eeecfebd04e345f69f1900cc3483cbbfea02a158
# Run the solana proxy to setup RPC and WS URLs: https://git.vdb.to/LaconicNetwork/solana-proxy
NEXT_PUBLIC_SOLANA_RPC_URL=
NEXT_PUBLIC_SOLANA_WS_URL=
NEXT_PUBLIC_SOLANA_TOKEN_MINT_ADDRESS=71Jvq4Epe2FCJ7JFSF7jLXdNk1Wy4Bhqd9iL6bEFELvg
NEXT_PUBLIC_SOLANA_TOKEN_SYMBOL=GOR

View File

@ -3,7 +3,7 @@ import { NextRequest, NextResponse } from 'next/server';
import axios from 'axios';
import assert from 'assert';
import { Connection } from '@solana/web3.js';
import { Connection, ParsedTransactionWithMeta } from '@solana/web3.js';
import { verifyUnusedSolanaPayment } from '@/utils/solana-verify';
import { transferLNTTokens } from '@/services/laconic-transfer';
@ -167,6 +167,7 @@ export async function POST(request: NextRequest) {
// First check if the request body is valid JSON
let url, txHash, senderPublicKey, paymentMethod;
let connection: Connection;
let parsedTx: ParsedTransactionWithMeta | null;
try {
const body = await request.json();
@ -186,6 +187,8 @@ export async function POST(request: NextRequest) {
}, { status: 400 });
}
parsedTx = tx;
const signerKeys = tx.transaction.message.accountKeys
.filter(k => k.signer)
.map(k => k.pubkey.toBase58());
@ -243,9 +246,13 @@ export async function POST(request: NextRequest) {
const requiredAmountInBaseUnits = requiredTokenInfo.requiredAmountInBaseUnits;
const expectedTokenAmount = Math.round(requiredAmountInBaseUnits - ALLOWED_SLIPPAGE_FACTOR * requiredAmountInBaseUnits);
if (!parsedTx) {
throw new Error(`Unable to find the tx with hash: ${txHash}`)
}
const solanaPaymentResult = await verifyUnusedSolanaPayment(
connection,
txHash,
parsedTx,
new BN(expectedTokenAmount),
paymentMethod,
);
@ -516,4 +523,4 @@ export async function POST(request: NextRequest) {
message: error instanceof Error ? error.message : 'Unknown error',
}, { status: 500 });
}
}
}

View File

@ -16,7 +16,10 @@ import { PaymentMethod } from '@/types';
import '@solana/wallet-adapter-react-ui/styles.css';
assert(process.env.NEXT_PUBLIC_SOLANA_RPC_URL, 'SOLANA_RPC_URL is required');
assert(process.env.NEXT_PUBLIC_SOLANA_WS_URL, 'SOLANA_WS_URL is required');
const SOLANA_RPC_URL = process.env.NEXT_PUBLIC_SOLANA_RPC_URL;
const SOLANA_WS_URL = process.env.NEXT_PUBLIC_SOLANA_WS_URL;
interface WalletProvidersProps {
children: React.ReactNode;
@ -59,7 +62,7 @@ export default function WalletProviders({ children }: WalletProvidersProps) {
}, [allWallets, selectedPaymentMethod]);
return (
<ConnectionProvider endpoint={endpoint}>
<ConnectionProvider endpoint={endpoint} config={{wsEndpoint: SOLANA_WS_URL}}>
<WalletProvider wallets={wallets} autoConnect>
<WalletModalProvider>
{children}

View File

@ -1,6 +1,6 @@
import BN from 'bn.js';
import { Connection, ParsedInstruction, PartiallyDecodedInstruction } from '@solana/web3.js';
import { Connection, ParsedInstruction, ParsedTransactionWithMeta, PartiallyDecodedInstruction } from '@solana/web3.js';
import { TOKEN_PROGRAM_ID } from '@solana/spl-token';
import { getRecipientAddress } from '@/services/solana';
@ -9,12 +9,11 @@ import { PaymentMethod } from '../types';
// Extract transaction info for native GOR transfers
const extractTxInfo = async (
connection: Connection,
transactionSignature: string,
parsedTx: ParsedTransactionWithMeta,
paymentMethod: PaymentMethod
): Promise<{ authority: string; amount: string; destination: string }> => {
const result = await connection.getParsedTransaction(transactionSignature, 'confirmed');
if (!result) {
if (!parsedTx) {
throw new Error('Transaction not found');
}
@ -23,7 +22,7 @@ const extractTxInfo = async (
switch (paymentMethod) {
case PaymentMethod.NAT_GOR:
// Look for system program transfer instruction
transferInstruction = result.transaction.message.instructions.find(
transferInstruction = parsedTx.transaction.message.instructions.find(
(instr) => 'parsed' in instr && instr.parsed.type === 'transfer'
);
@ -36,7 +35,7 @@ const extractTxInfo = async (
case PaymentMethod.SPL_TOKEN:
// Look for token transfer instruction using TOKEN_PROGRAM_ID
transferInstruction = result.transaction.message.instructions.find(
transferInstruction = parsedTx.transaction.message.instructions.find(
(instr) => 'parsed' in instr && instr.programId.equals(TOKEN_PROGRAM_ID)
);
@ -68,7 +67,7 @@ const extractTxInfo = async (
export const verifyUnusedSolanaPayment = async (
connection: Connection,
transactionSignature: string,
parsedTx: ParsedTransactionWithMeta,
expectedAmount: BN,
paymentMethod: PaymentMethod,
): Promise<{
@ -81,9 +80,7 @@ export const verifyUnusedSolanaPayment = async (
// TODO: Check if provided signature is already used
// Fetch transaction details
const transactionResult = await connection.getParsedTransaction(transactionSignature, 'confirmed');
if (!transactionResult) {
if (!parsedTx) {
return {
valid: false,
reason: 'Transaction not found on Solana blockchain'
@ -91,15 +88,15 @@ export const verifyUnusedSolanaPayment = async (
}
// Check if transaction was successful
if (transactionResult.meta?.err) {
if (parsedTx.meta?.err) {
return {
valid: false,
reason: `Transaction failed: ${JSON.stringify(transactionResult.meta.err)}`
reason: `Transaction failed: ${JSON.stringify(parsedTx.meta.err)}`
};
}
// Check transaction timestamp (5-minute window)
const txTimestamp = transactionResult.blockTime ? new Date(transactionResult.blockTime * 1000) : null;
const txTimestamp = parsedTx.blockTime ? new Date(parsedTx.blockTime * 1000) : null;
if (!txTimestamp) {
return {
valid: false,
@ -119,7 +116,7 @@ export const verifyUnusedSolanaPayment = async (
}
// Extract transaction info based on payment method
const transferInfo = await extractTxInfo(connection, transactionSignature, paymentMethod);
const transferInfo = await extractTxInfo(connection, parsedTx, paymentMethod);
const amount = transferInfo.amount;
const authority = transferInfo.authority;
const destination = transferInfo.destination;