chore: the native token's label follows the network (closes #372)
check / check (push) Failing after 2s
e2e / e2e-chrome (push) Failing after 1s
e2e / e2e-firefox (push) Failing after 1s

networks.js gives each network a nativeCurrency (ETH, SepoliaETH) and nothing
read it: every screen wrote ETH. The wallet's balances and the Send and
confirmation screens now use the active network's. A transaction's figures use
the network its chain id names, through nativeCurrencyByChainId(): the
approval value and fee, the wait, success and error screens, history entries,
the detail screen and the fee-limit refusal, so a site switching networks
cannot make one read as another network's coin. The "ETH" that selectedToken
and txInfo.token hold is the native token's id and is unchanged. A token
reporting any network's nativeCurrency is a spoof, and the detail screen calls
an entry a token transfer when it has a token contract.

Model: opus-5-5
This commit was merged in pull request #442.
This commit is contained in:
2026-10-05 01:26:04 +02:00
parent 2b97aae04a
commit e3790c5da4
20 changed files with 769 additions and 83 deletions
+15 -7
View File
@@ -21,6 +21,7 @@ const {
goBack,
} = require("./helpers");
const { state } = require("../../shared/state");
const { nativeCurrencyByChainId } = require("../../shared/networks");
const { formatEther, formatUnits } = require("ethers");
const makeBlockie = require("ethereum-blockies-base64");
const { log, debugFetch } = require("../../shared/log");
@@ -41,8 +42,10 @@ function getTransactionType(tx) {
return "Token Approval";
return "Contract Call";
}
if (tx.symbol && tx.symbol !== "ETH") return "ERC-20 Token Transfer";
return "Native ETH Transfer";
// By the token contract, not the symbol: a token chooses its own symbol
// and can report the native token's, but only a token transfer has one.
if (tx.contractAddress) return "ERC-20 Token Transfer";
return "Native " + nativeCurrencyByChainId(tx.chainId) + " Transfer";
}
function blockieHtml(address) {
@@ -84,6 +87,11 @@ function show(tx) {
isContractCall: tx.isContractCall || false,
method: tx.method || null,
contractAddress: tx.contractAddress || null,
// The network the history entry was read from. The type line and
// the fee are in its native currency, not the active network's:
// a site can switch the active network before a later popup
// shows this screen again.
chainId: tx.chainId,
},
};
render();
@@ -179,7 +187,7 @@ function render() {
if (el) el.classList.add("hidden");
}
loadFullTxDetails(tx.hash, tx.to);
loadFullTxDetails(tx.hash, tx.to, tx.chainId);
const isoStr = isoDate(tx.timestamp);
$("tx-detail-time").innerHTML =
@@ -197,7 +205,7 @@ function showDetailField(sectionId, contentId, value) {
section.classList.remove("hidden");
}
function populateOnChainDetails(txData) {
function populateOnChainDetails(txData, chainId) {
// Block number
if (txData.block_number != null) {
const blockLink = explorerUrl("block", String(txData.block_number));
@@ -227,7 +235,7 @@ function populateOnChainDetails(txData) {
showDetailField(
"tx-detail-fee-section",
"tx-detail-fee",
feeEth + " ETH",
feeEth + " " + nativeCurrencyByChainId(chainId),
);
}
@@ -287,7 +295,7 @@ function populateOnChainDetails(txData) {
}
}
async function loadFullTxDetails(txHash, toAddress) {
async function loadFullTxDetails(txHash, toAddress, chainId) {
const section = $("tx-detail-calldata-section");
const actionEl = $("tx-detail-calldata-action");
const detailsEl = $("tx-detail-calldata-details");
@@ -304,7 +312,7 @@ async function loadFullTxDetails(txHash, toAddress) {
const txData = await resp.json();
// Populate on-chain detail fields (block, nonce, gas, fee)
populateOnChainDetails(txData);
populateOnChainDetails(txData, chainId);
const inputData = txData.raw_input || txData.input || null;
if (!inputData || inputData === "0x") return;