spl data fetch fixed

This commit is contained in:
Sewmina (server) 2025-08-14 16:49:57 +08:00
parent 7f8a87cfa2
commit 3d31c1efaa
2 changed files with 94 additions and 17 deletions

View File

@ -3,13 +3,14 @@ import { config } from './config';
import { logger } from './utils/logger';
import transactionRoutes from './routes/transactionRoutes';
import { getConnection } from './utils/database';
import { getTransaction } from './utils/explorer';
import { getTransaction, getTransactionRaw } from './utils/explorer';
import { TransactionValidationService } from './services/transactionValidationService';
import { CLUSTER_API } from './data';
logger.info("Starting server...");
const app = express();
const PORT = config.port;
logger.info(`port: ${PORT}`);
logger.info(`nodeEnv: ${config.nodeEnv}`);
logger.info(`nodeEnv: ${config.nodeEnv} : ${CLUSTER_API}`);
logger.info(`logLevel: ${config.logLevel}`);
getConnection().then(() => {
@ -42,9 +43,19 @@ app.get('/health', (_req: Request, res: Response) => {
});
app.get('/solana/tx/:txHash', async (req: Request, res: Response) => {
const txHash = req.params.txHash;
const transaction = await getTransaction(txHash);
res.json(transaction);
const {raw} = req.query;
if(raw=="true"){
const tx = await getTransactionRaw(req.params.txHash);
res.json(tx);
}else{
const txHash = req.params.txHash;
const transaction = await getTransaction(txHash);
res.json(transaction);
}
});
// Validation service control endpoints

View File

@ -1,15 +1,27 @@
import { CLUSTER_API } from "../data";
import { Connection } from "@solana/web3.js";
import { Connection, ParsedTransactionWithMeta, PublicKey } from "@solana/web3.js";
import { TransferData } from "../types";
import { logger } from "./logger";
export async function getTransaction(txHash: string) {
const connection = new Connection(CLUSTER_API, { commitment: 'finalized' });
export async function getTransactionRaw(txHash: string) {
const connection = new Connection(CLUSTER_API, { commitment: 'confirmed' });
const transaction = await connection.getParsedTransaction(txHash, {
maxSupportedTransactionVersion: 0,
});
const transaction_formatted = extractTokenTransferData(transaction);
return transaction;
}
export async function getTransaction(txHash: string) {
const transaction = await getTransactionRaw(txHash);
if (!transaction) {
logger.error(`Blockchain couldn't find transaction: ${txHash}`);
return null;
}
const transaction_formatted = await extractTokenTransferData(transaction);
return transaction_formatted;
}
@ -41,12 +53,38 @@ export function extractNativeSolTransferData(transaction: any): TransferData | n
}
}
export function extractSplTokenTransferData(transaction: any): TransferData | null {
async function getAtaOwner(ataAddress: string): Promise<string> {
try {
const connection = new Connection(CLUSTER_API, { commitment: 'confirmed' });
const ataPublicKey = new PublicKey(ataAddress);
const accountInfo = await connection.getAccountInfo(ataPublicKey);
if (!accountInfo) {
logger.warn(`Could not find account info for ATA: ${ataAddress}`);
return ataAddress; // Fallback to ATA address if we can't get owner
}
// The owner is stored in the account data at a specific offset
// For token accounts, the owner is at offset 32
const ownerBytes = accountInfo.data.slice(32, 64);
const owner = new PublicKey(ownerBytes);
return owner.toString();
} catch (error) {
logger.error(`Error getting ATA owner: ${error}`);
return ataAddress; // Fallback to ATA address if there's an error
}
}
export async function extractSplTokenTransferData(transaction: any): Promise<TransferData | null> {
try {
// Check if this is an SPL token transfer
const instructions = transaction.transaction.message.instructions;
// Try to find either transferChecked or transfer instruction
const tokenTransferInstruction = instructions.find((instruction: any) =>
instruction.program === "spl-token" && instruction.parsed?.type === "transferChecked"
instruction.program === "spl-token" &&
(instruction.parsed?.type === "transferChecked" || instruction.parsed?.type === "transfer")
);
if (!tokenTransferInstruction) {
@ -55,11 +93,37 @@ export function extractSplTokenTransferData(transaction: any): TransferData | nu
const transferInfo = tokenTransferInstruction.parsed.info;
// For transferChecked type
if (tokenTransferInstruction.parsed.type === "transferChecked") {
const receiverOwner = await getAtaOwner(transferInfo.destination);
return {
sender: transferInfo.authority,
receiver: receiverOwner,
amount: parseInt(transferInfo.tokenAmount.amount),
mint: transferInfo.mint,
time: transaction.blockTime,
blockhash: transaction.transaction.message.recentBlockhash
};
}
logger.debug(`It's not a transferChecked`);
// For transfer type
const tokenBalances = transaction.meta.preTokenBalances;
const mint = tokenBalances[0]?.mint;
if (!mint) {
return null;
}
const receiverOwner = await getAtaOwner(transferInfo.destination);
return {
sender: transferInfo.source,
receiver: transferInfo.destination,
amount: parseInt(transferInfo.tokenAmount.amount),
mint: transferInfo.mint,
sender: transferInfo.authority,
receiver: receiverOwner,
amount: parseInt(transferInfo.amount),
mint: mint,
time: transaction.blockTime,
blockhash: transaction.transaction.message.recentBlockhash
};
@ -69,7 +133,7 @@ export function extractSplTokenTransferData(transaction: any): TransferData | nu
}
}
export function extractTokenTransferData(transaction: any): TransferData | null {
export async function extractTokenTransferData(transaction: ParsedTransactionWithMeta): Promise<TransferData | null> {
// Try to extract native SOL transfer first
const nativeSolData = extractNativeSolTransferData(transaction);
if (nativeSolData) {
@ -77,10 +141,12 @@ export function extractTokenTransferData(transaction: any): TransferData | null
}
// Try to extract SPL token transfer
const splTokenData = extractSplTokenTransferData(transaction);
const splTokenData = await extractSplTokenTransferData(transaction);
if (splTokenData) {
return splTokenData;
}
logger.error(`Error extracting token transfer data: ${transaction}`);
return null; // Not a recognized token transfer
}