diff --git a/README.md b/README.md
index 0030313..42ea566 100644
--- a/README.md
+++ b/README.md
@@ -437,6 +437,10 @@ transitions.
- **When**: User tapped a transaction row from AddressDetail or AddressToken.
- **Elements**:
- "Transaction" heading, "Back" button
+ - Type: transaction classification — one of: Native ETH Transfer, ERC-20
+ Token Transfer, Swap, Token Approval, Contract Call, Contract Creation
+ - Token contract: shown for ERC-20 transfers — color dot + full contract
+ address (tap to copy) + etherscan token link
- Status: "Success" or "Failed"
- Time: ISO datetime + relative age in parentheses
- Amount: value + symbol (bold)
@@ -445,6 +449,11 @@ transitions.
- To: blockie + color dot + full address (tap to copy) + etherscan link
- ENS name if available
- Transaction hash: full hash (tap to copy) + etherscan link
+ - Block: block number (tap to copy) + etherscan block link
+ - Nonce: transaction nonce (tap to copy)
+ - Transaction fee: ETH amount (tap to copy)
+ - Gas price: value in Gwei (tap to copy)
+ - Gas used: integer (tap to copy)
- **Transitions**:
- "Back" → **AddressToken** (if `selectedToken` set) or **AddressDetail**
diff --git a/src/popup/index.html b/src/popup/index.html
index 89e36b7..336431c 100644
--- a/src/popup/index.html
+++ b/src/popup/index.html
@@ -1092,6 +1092,13 @@
Raw data
${dot}` +
+ copyableHtml(tx.contractAddress, "break-all") +
+ etherscanLinkHtml(link) +
+ `
`;
+ tokenContractSection.classList.remove("hidden");
+ } else {
+ tokenContractSection.classList.add("hidden");
+ }
+ }
+
+ // Hide calldata and raw data sections; always fetch full tx details
const calldataSection = $("tx-detail-calldata-section");
if (calldataSection) calldataSection.classList.add("hidden");
const rawDataSection = $("tx-detail-rawdata-section");
if (rawDataSection) rawDataSection.classList.add("hidden");
- if (tx.isContractCall || tx.direction === "contract") {
- loadCalldata(tx.hash, tx.to);
+ // Hide on-chain detail sections until populated
+ for (const id of [
+ "tx-detail-block-section",
+ "tx-detail-nonce-section",
+ "tx-detail-fee-section",
+ "tx-detail-gasprice-section",
+ "tx-detail-gasused-section",
+ ]) {
+ const el = $(id);
+ if (el) el.classList.add("hidden");
}
+ loadFullTxDetails(tx.hash, tx.to, tx.isContractCall);
+
const isoStr = isoDate(tx.timestamp);
$("tx-detail-time").innerHTML =
copyableHtml(isoStr) + " (" + escapeHtml(timeAgo(tx.timestamp)) + ")";
@@ -177,7 +222,90 @@ function render() {
});
}
-async function loadCalldata(txHash, toAddress) {
+function showDetailField(sectionId, contentId, value) {
+ const section = $(sectionId);
+ const el = $(contentId);
+ if (!section || !el) return;
+ el.innerHTML = copyableHtml(value, "");
+ section.classList.remove("hidden");
+}
+
+function populateOnChainDetails(txData) {
+ // Block number
+ if (txData.block_number != null) {
+ const blockLink = `https://etherscan.io/block/${txData.block_number}`;
+ const blockSection = $("tx-detail-block-section");
+ const blockEl = $("tx-detail-block");
+ if (blockSection && blockEl) {
+ blockEl.innerHTML =
+ copyableHtml(String(txData.block_number), "") +
+ etherscanLinkHtml(blockLink);
+ blockSection.classList.remove("hidden");
+ }
+ }
+
+ // Nonce
+ if (txData.nonce != null) {
+ showDetailField(
+ "tx-detail-nonce-section",
+ "tx-detail-nonce",
+ String(txData.nonce),
+ );
+ }
+
+ // Transaction fee
+ const feeWei = txData.fee?.value || txData.tx_fee;
+ if (feeWei) {
+ const feeEth = formatEther(String(feeWei));
+ showDetailField(
+ "tx-detail-fee-section",
+ "tx-detail-fee",
+ feeEth + " ETH",
+ );
+ }
+
+ // Gas price
+ const gasPrice = txData.gas_price;
+ if (gasPrice) {
+ const gwei = formatUnits(String(gasPrice), "gwei");
+ showDetailField(
+ "tx-detail-gasprice-section",
+ "tx-detail-gasprice",
+ gwei + " Gwei",
+ );
+ }
+
+ // Gas used
+ const gasUsed = txData.gas_used;
+ if (gasUsed) {
+ showDetailField(
+ "tx-detail-gasused-section",
+ "tx-detail-gasused",
+ String(gasUsed),
+ );
+ }
+
+ // Bind copy handlers for newly added elements
+ for (const id of [
+ "tx-detail-block-section",
+ "tx-detail-nonce-section",
+ "tx-detail-fee-section",
+ "tx-detail-gasprice-section",
+ "tx-detail-gasused-section",
+ ]) {
+ const section = $(id);
+ if (!section) continue;
+ section.querySelectorAll("[data-copy]").forEach((el) => {
+ el.onclick = () => {
+ navigator.clipboard.writeText(el.dataset.copy);
+ showFlash("Copied!");
+ flashCopyFeedback(el);
+ };
+ });
+ }
+}
+
+async function loadFullTxDetails(txHash, toAddress, isContractCall) {
const section = $("tx-detail-calldata-section");
const actionEl = $("tx-detail-calldata-action");
const detailsEl = $("tx-detail-calldata-details");
@@ -192,6 +320,10 @@ async function loadCalldata(txHash, toAddress) {
);
if (!resp.ok) return;
const txData = await resp.json();
+
+ // Populate on-chain detail fields (block, nonce, gas, fee)
+ populateOnChainDetails(txData);
+
const inputData = txData.raw_input || txData.input || null;
if (!inputData || inputData === "0x") return;