diff --git a/README.md b/README.md index 418bba9..7f6847b 100644 --- a/README.md +++ b/README.md @@ -2395,6 +2395,8 @@ view would leave a wallet one click from deletion. - Raw data: full calldata displayed inline (shown if present) - Password input and an error line - "Confirm" / "Reject" buttons +- **Behavior**: Every etherscan link on the screen opens the explorer of the + network the transaction was populated on, whichever network is active. - **Transitions**: - "Confirm" (correct password) → decrypts and signs the transaction it was shown, exactly as shown, hands the signed transaction to the background to diff --git a/src/popup/views/approval.js b/src/popup/views/approval.js index 6911927..6003fdd 100644 --- a/src/popup/views/approval.js +++ b/src/popup/views/approval.js @@ -58,9 +58,11 @@ const { notify, runtimeApi, sendMessage } = require("../../shared/browserApi"); const erc20Iface = new Interface(ERC20_ABI); -function approvalAddressHtml(address) { +// The link opens the explorer of the network with `chainId`, or of the active +// network when none is given. +function approvalAddressHtml(address, chainId) { const title = addressTitle(address, state.wallets); - return renderAddressHtml(address, { title }); + return renderAddressHtml(address, { title, chainId }); } // The amount line for a decoded ERC-20 call. With a known scale it is the @@ -338,8 +340,14 @@ function showTxApproval(details) { }; } + // Every address link on this screen opens the explorer of the network the + // transaction is for, which the Network line names, whichever network is + // active. $("approve-tx-origin").textContent = details.origin; - $("approve-tx-from").innerHTML = approvalAddressHtml(details.approvedFrom); + $("approve-tx-from").innerHTML = approvalAddressHtml( + details.approvedFrom, + approvedTx.chainId, + ); // Show token symbol next to contract address if known on the network the // transaction is for @@ -349,7 +357,7 @@ function showTxApproval(details) { if (symbol) { toHtml += `
${escapeHtml(symbol)}
`; } - toHtml += approvalAddressHtml(toAddr); + toHtml += approvalAddressHtml(toAddr, approvedTx.chainId); $("approve-tx-to").innerHTML = toHtml; } else { $("approve-tx-to").innerHTML = escapeHtml(CONTRACT_CREATION_TEXT); @@ -388,7 +396,10 @@ function showTxApproval(details) { if (d.isToken) { detailsHtml += `
${escapeHtml(tokenLabel(d.address, approvedTx.chainId) || "Unknown token")}
`; } - detailsHtml += approvalAddressHtml(d.address); + detailsHtml += approvalAddressHtml( + d.address, + approvedTx.chainId, + ); } else { detailsHtml += `
${escapeHtml(d.value)}
`; } diff --git a/tests/approvalTokenNetwork.test.js b/tests/approvalTokenNetwork.test.js index 20ed1dc..62bbf51 100644 --- a/tests/approvalTokenNetwork.test.js +++ b/tests/approvalTokenNetwork.test.js @@ -1,11 +1,16 @@ // The approval screen for a site's Sepolia token transfer while Ethereum -// Mainnet is active (https://git.eeqj.de/sneak/AutistMask/issues/629). +// Mainnet is active. // // The screen named the token, and scaled its amount, from the active network's // tracked tokens and balances, so a token the wallet tracks on Sepolia read as // an unknown token with its amount in base units, and the screens after it -// labelled the amount `?`. It now uses what the wallet knows of the tokens on -// the network the transaction is for. +// labelled the amount `?` (https://git.eeqj.de/sneak/AutistMask/issues/629). +// It now uses what the wallet knows of the tokens on the network the +// transaction is for. +// +// Its address links opened the active network's explorer +// (https://git.eeqj.de/sneak/AutistMask/issues/631). They now open the +// explorer of the network the transaction is for. // // Driven through the real approval screen, password and Confirm included, // against a minimal DOM stub in the shape tests/swapStatusAmount.test.js uses. @@ -218,3 +223,28 @@ test("a token tracked and held on mainnet only is not named, and its amount is i '
1234500000 base units (decimals unknown)
', ); }); + +// The From and Contract lines, and the decoded Token and Recipient lines. +test("every address links to the Sepolia explorer", async () => { + await showSepoliaTransfer(); + const sepolia = NETWORKS.sepolia.explorerUrl; + expect(node("approve-tx-from").innerHTML).toContain( + `href="${sepolia}/address/${FROM}"`, + ); + expect(node("approve-tx-to").innerHTML).toContain( + `href="${sepolia}/address/${TOKEN}"`, + ); + expect(decodedLine("Token")).toContain( + `href="${sepolia}/address/${TOKEN}"`, + ); + expect(decodedLine("Recipient")).toContain( + `href="${sepolia}/address/${RECIPIENT}"`, + ); + for (const id of [ + "approve-tx-from", + "approve-tx-to", + "approve-tx-decoded-details", + ]) { + expect(node(id).innerHTML).not.toContain(NETWORKS.mainnet.explorerUrl); + } +}); diff --git a/tests/walletDefects.test.js b/tests/walletDefects.test.js index d5e9ea5..fe1c389 100644 --- a/tests/walletDefects.test.js +++ b/tests/walletDefects.test.js @@ -475,7 +475,7 @@ describe("every way to a signature or the private key refuses a defective wallet to: RECIPIENT, value: "0x0", data: "0x", - chainId: 1, + chainId: "0x1", nonce: 0, gasLimit: "21000", maxFeePerGas: "1000000000",