Show decoded calldata in transaction detail view
All checks were successful
check / check (push) Successful in 22s

Add decoded transaction summary (matching the approval screen
format) to the transaction detail view. For unknown contract
calls, show 'Unknown Contract Call' label with full raw
calldata hex (not truncated).
This commit is contained in:
2026-02-27 12:05:21 -08:00
parent 497d011b3c
commit efc5404d6d
2 changed files with 73 additions and 0 deletions

View File

@@ -943,6 +943,23 @@
<div class="text-xs text-muted mb-1">Transaction hash</div>
<div id="tx-detail-hash" class="text-xs break-all"></div>
</div>
<div
id="tx-detail-decoded"
class="mb-3 border border-border border-dashed p-2 hidden"
>
<div
id="tx-detail-action"
class="font-bold mb-1 text-xs"
></div>
<div id="tx-detail-decoded-details" class="text-xs"></div>
</div>
<div id="tx-detail-rawdata-section" class="mb-4 hidden">
<div class="text-xs text-muted mb-1">Raw calldata</div>
<div
id="tx-detail-rawdata"
class="text-xs break-all font-mono"
></div>
</div>
</div>
<!-- ============ TRANSACTION APPROVAL ============ -->

View File

@@ -12,6 +12,8 @@ const {
timeAgo,
} = require("./helpers");
const { state } = require("../../shared/state");
const { TOKEN_BY_ADDRESS } = require("../../shared/tokenList");
const { decodeCalldata } = require("../../shared/decodeCalldata");
const makeBlockie = require("ethereum-blockies-base64");
const EXT_ICON =
@@ -85,6 +87,8 @@ function show(tx) {
fromEns: tx.fromEns || null,
toEns: tx.toEns || null,
directionLabel: tx.directionLabel || null,
rawInput: tx.rawInput || null,
decoded: tx.decoded || null,
},
};
render();
@@ -124,6 +128,58 @@ function render() {
$("tx-detail-time").textContent =
isoDate(tx.timestamp) + " (" + timeAgo(tx.timestamp) + ")";
$("tx-detail-status").textContent = tx.isError ? "Failed" : "Success";
// Decoded calldata section — matches approval screen format
const decodedEl = $("tx-detail-decoded");
const rawDataEl = $("tx-detail-rawdata-section");
const decoded = tx.decoded;
if (decoded) {
$("tx-detail-action").textContent = decoded.name;
let detailsHtml = "";
if (decoded.description) {
detailsHtml += `<div class="mb-2">${escapeHtml(decoded.description)}</div>`;
}
for (const d of decoded.details) {
detailsHtml += `<div class="mb-2">`;
detailsHtml += `<div class="text-muted">${escapeHtml(d.label)}</div>`;
if (d.address) {
if (d.isToken) {
const t = TOKEN_BY_ADDRESS.get(d.address.toLowerCase());
const label = t ? t.symbol : "Unknown token";
detailsHtml += `<div class="font-bold">${escapeHtml(label)}</div>`;
}
const dot = addressDotHtml(d.address);
const link = `https://etherscan.io/address/${d.address}`;
detailsHtml +=
`<div class="flex items-center">${dot}` +
`<span class="break-all underline decoration-dashed cursor-pointer" data-copy="${escapeHtml(d.address)}">${escapeHtml(d.address)}</span>` +
`<a href="${link}" target="_blank" rel="noopener" class="inline-flex items-center">${EXT_ICON}</a></div>`;
} else {
detailsHtml += `<div class="font-bold">${escapeHtml(d.value)}</div>`;
}
detailsHtml += `</div>`;
}
$("tx-detail-decoded-details").innerHTML = detailsHtml;
decodedEl.classList.remove("hidden");
} else {
decodedEl.classList.add("hidden");
}
// Raw calldata section — shown for unknown contract calls (full, not truncated)
if (tx.rawInput && tx.rawInput !== "0x" && !decoded) {
$("tx-detail-rawdata").textContent = tx.rawInput;
rawDataEl.classList.remove("hidden");
// Label as unknown contract call
$("tx-detail-action").textContent = "Unknown Contract Call";
$("tx-detail-decoded-details").innerHTML = "";
decodedEl.classList.remove("hidden");
} else if (!decoded) {
rawDataEl.classList.add("hidden");
} else {
rawDataEl.classList.add("hidden");
}
showView("transaction");
document