Enhance transaction detail extraction to identify sender, receiver, and transaction types (transfer, swap, nft_mint)
This commit is contained in:
parent
a5ebc25567
commit
774abf7bd6
155
index.html
155
index.html
@ -2578,11 +2578,111 @@
|
|||||||
status === "confirmed" ? `Included in Slot #${tx.slot}` : "";
|
status === "confirmed" ? `Included in Slot #${tx.slot}` : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill in transaction details
|
|
||||||
|
// Extract sender and receiver from transaction
|
||||||
|
let sender = "Unknown";
|
||||||
|
let receiver = "Unknown";
|
||||||
|
let transactionType = "transfer"; // transfer, swap, nft_mint, other
|
||||||
|
|
||||||
|
const accountKeys = tx.transaction?.message?.accountKeys || [];
|
||||||
|
const instructions = tx.transaction?.message?.instructions || [];
|
||||||
|
const logMessages = tx.meta?.logMessages || [];
|
||||||
|
|
||||||
|
// Check if this is an NFT mint by looking at log messages
|
||||||
|
const isNFTMint = logMessages.some(log =>
|
||||||
|
log.includes("MintToCollectionV1") ||
|
||||||
|
log.includes("MintV1") ||
|
||||||
|
log.includes("Bubblegum") ||
|
||||||
|
(log.includes("Instruction: Mint") && !log.includes("MintTo") && !log.includes("JUP"))
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isNFTMint) {
|
||||||
|
transactionType = "nft_mint";
|
||||||
|
sender = "NFT Mint";
|
||||||
|
receiver = accountKeys[0]?.toString() || "Unknown";
|
||||||
|
}
|
||||||
|
// Check if this is a token swap by looking at token balance changes
|
||||||
|
else if (tx.meta?.preTokenBalances && tx.meta?.postTokenBalances) {
|
||||||
|
const preTokens = tx.meta.preTokenBalances;
|
||||||
|
const postTokens = tx.meta.postTokenBalances;
|
||||||
|
|
||||||
|
// Find tokens that decreased (sent)
|
||||||
|
let tokenSent = null;
|
||||||
|
let tokenReceived = null;
|
||||||
|
|
||||||
|
for (const preTok of preTokens) {
|
||||||
|
const postTok = postTokens.find(p => p.accountIndex === preTok.accountIndex);
|
||||||
|
if (postTok) {
|
||||||
|
const preAmount = parseFloat(preTok.uiTokenAmount.amount);
|
||||||
|
const postAmount = parseFloat(postTok.uiTokenAmount.amount);
|
||||||
|
|
||||||
|
// Token amount decreased significantly (sent/swapped)
|
||||||
|
if (preAmount > postAmount && (preAmount - postAmount) > 0.000001) {
|
||||||
|
tokenSent = {
|
||||||
|
mint: preTok.mint,
|
||||||
|
amount: preTok.uiTokenAmount.uiAmountString,
|
||||||
|
symbol: preTok.mint === "So11111111111111111111111111111111111111112" ? "SOL" : preTok.mint
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token amount increased significantly (received)
|
||||||
|
if (postAmount > preAmount && (postAmount - preAmount) > 0.000001) {
|
||||||
|
tokenReceived = {
|
||||||
|
mint: postTok.mint,
|
||||||
|
amount: postTok.uiTokenAmount.uiAmountString,
|
||||||
|
symbol: postTok.mint === "So11111111111111111111111111111111111111112" ? "SOL" : postTok.mint
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we found a token swap, use that instead of FROM/TO
|
||||||
|
if (tokenSent && tokenReceived) {
|
||||||
|
transactionType = "swap";
|
||||||
|
sender = `${tokenSent.symbol}`;
|
||||||
|
receiver = `${tokenReceived.symbol}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not a swap or NFT mint, try to find the transfer instruction
|
||||||
|
if (transactionType === "transfer") {
|
||||||
|
for (const ix of instructions) {
|
||||||
|
if (ix.accounts && ix.accounts.length >= 2) {
|
||||||
|
if (ix.data) {
|
||||||
|
try {
|
||||||
|
const dataBytes = bs58.decode(ix.data);
|
||||||
|
if (dataBytes[0] === 2) {
|
||||||
|
sender = accountKeys[ix.accounts[0]]?.toString() || "Unknown";
|
||||||
|
receiver = accountKeys[ix.accounts[1]]?.toString() || "Unknown";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// If decode fails, continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback: use balance changes to determine sender/receiver
|
||||||
|
if (sender === "Unknown" && tx.meta?.preBalances && tx.meta?.postBalances) {
|
||||||
|
for (let i = 0; i < accountKeys.length; i++) {
|
||||||
|
const balanceChange = tx.meta.postBalances[i] - tx.meta.preBalances[i];
|
||||||
|
if (balanceChange < -100000 && sender === "Unknown") {
|
||||||
|
sender = accountKeys[i]?.toString() || "Unknown";
|
||||||
|
}
|
||||||
|
if (balanceChange > 100000 && receiver === "Unknown") {
|
||||||
|
receiver = accountKeys[i]?.toString() || "Unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Final fallback: use first account as sender
|
||||||
|
if (sender === "Unknown" && accountKeys[0]) {
|
||||||
|
sender = accountKeys[0]?.toString() || "Unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (getRef("tx_from")) {
|
if (getRef("tx_from")) {
|
||||||
const sender =
|
|
||||||
tx.transaction?.message?.accountKeys?.[0]?.toString() ||
|
|
||||||
"Unknown";
|
|
||||||
getRef("tx_from").value = sender;
|
getRef("tx_from").value = sender;
|
||||||
getRef("tx_from").addEventListener("click", function (e) {
|
getRef("tx_from").addEventListener("click", function (e) {
|
||||||
if (
|
if (
|
||||||
@ -2601,9 +2701,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (getRef("tx_to")) {
|
if (getRef("tx_to")) {
|
||||||
const receiver =
|
|
||||||
tx.transaction?.message?.accountKeys?.[1]?.toString() ||
|
|
||||||
"Unknown";
|
|
||||||
getRef("tx_to").value = receiver;
|
getRef("tx_to").value = receiver;
|
||||||
getRef("tx_to").addEventListener("click", function (e) {
|
getRef("tx_to").addEventListener("click", function (e) {
|
||||||
if (
|
if (
|
||||||
@ -2682,49 +2779,6 @@
|
|||||||
if (currentCurrency !== "sol" && !isHistoricApiAvailable) {
|
if (currentCurrency !== "sol" && !isHistoricApiAvailable) {
|
||||||
testHistoricalAPIAndRenderToggle();
|
testHistoricalAPIAndRenderToggle();
|
||||||
}
|
}
|
||||||
|
|
||||||
let sender = "Unknown";
|
|
||||||
let receiver = "Unknown";
|
|
||||||
|
|
||||||
const message = tx.transaction?.message;
|
|
||||||
const accountKeys =
|
|
||||||
message?.staticAccountKeys || message?.accountKeys || [];
|
|
||||||
const instructions =
|
|
||||||
message?.compiledInstructions || message?.instructions || [];
|
|
||||||
|
|
||||||
// Try to extract from parsed instructions (for parsed transactions)
|
|
||||||
if (instructions && instructions.length > 0) {
|
|
||||||
// Try to find a transfer instruction (SPL or System)
|
|
||||||
for (const ix of instructions) {
|
|
||||||
// For parsed transactions (if available)
|
|
||||||
if (ix.parsed && ix.parsed.info) {
|
|
||||||
if (ix.parsed.info.source && ix.parsed.info.destination) {
|
|
||||||
sender = ix.parsed.info.source;
|
|
||||||
receiver = ix.parsed.info.destination;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (ix.parsed.info.authority && ix.parsed.info.destination) {
|
|
||||||
sender = ix.parsed.info.authority;
|
|
||||||
receiver = ix.parsed.info.destination;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// For raw instructions (like in your prompt)
|
|
||||||
if (ix.accountKeyIndexes && ix.accountKeyIndexes.length >= 2) {
|
|
||||||
sender = accountKeys[ix.accountKeyIndexes[0]] || "Unknown";
|
|
||||||
receiver = accountKeys[ix.accountKeyIndexes[1]] || "Unknown";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback: just use first two account keys
|
|
||||||
if (sender === "Unknown" && accountKeys[0]) sender = accountKeys[0];
|
|
||||||
if (receiver === "Unknown" && accountKeys[1])
|
|
||||||
receiver = accountKeys[1];
|
|
||||||
|
|
||||||
if (getRef("tx_from")) getRef("tx_from").value = sender;
|
|
||||||
if (getRef("tx_to")) getRef("tx_to").value = receiver;
|
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error("Error:", error);
|
console.error("Error:", error);
|
||||||
@ -2766,7 +2820,6 @@
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchSolanaTransactionDetails(signature) {
|
async function fetchSolanaTransactionDetails(signature) {
|
||||||
try {
|
try {
|
||||||
// Check for valid signature format
|
// Check for valid signature format
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user