Compare commits

...

3 Commits

Author SHA1 Message Date
clawbot
bc4e78c466 fix: consistent token contract display on confirm-tx page
All checks were successful
check / check (push) Successful in 23s
The confirm-tx page displayed token contract addresses as plain text,
while addressToken used a styled container (bg-hover rounded-md) with
color dot, copy-on-click, etherscan link, and token metadata.

Changes:
- confirm-tx HTML: use bg-hover rounded-md container matching addressToken
- confirm-tx JS: render contract with addressDotHtml, copy-on-click span,
  etherscan link, and optional token name/symbol metadata
- send.js: pass tokenName to confirmTx for richer contract display
- Add click-to-copy handler for contract address on confirm-tx

Closes #70
2026-02-28 12:06:25 -08:00
e8ede7010a Merge pull request 'fix: use formatAddressHtml in receive view for display consistency' (#69) from fix/issue-58-receive-address-consistency into main
All checks were successful
check / check (push) Successful in 9s
Reviewed-on: #69
2026-02-28 20:57:08 +01:00
a2fbb0e30d fix: use formatAddressHtml in receive view for display consistency
All checks were successful
check / check (push) Successful in 22s
The receive view was using raw textContent and a manually constructed
color dot instead of the shared formatAddressHtml helper used by other
views. This violated the display consistency policy ('Same data
formatted identically across all screens').

Changes:
- Use formatAddressHtml() to render address with color dot, title
  (e.g. 'Wallet 1 — Address 1'), and ENS name — matching addressDetail
- Make the address block itself click-to-copy (matching policy:
  'Clicking any address copies the full untruncated value')
- Replace separate receive-dot/receive-address spans with a single
  receive-address-block element
- Address is still shown in full (no truncation) as appropriate for
  the receive view

Closes #58
2026-02-28 11:47:45 -08:00
4 changed files with 71 additions and 16 deletions

View File

@@ -463,12 +463,12 @@
</div> </div>
<!-- ERC-20 token contract (hidden for ETH) --> <!-- ERC-20 token contract (hidden for ETH) -->
<div id="confirm-token-section" class="mb-3 hidden"> <div
<div class="text-xs text-muted mb-1">Token contract</div> id="confirm-token-section"
<div class="bg-hover rounded-md mx-1 p-3 mb-3 text-xs hidden"
id="confirm-token-contract" >
class="text-xs break-all" <div class="font-bold mb-2">Token Contract</div>
></div> <div id="confirm-token-contract" class="break-all"></div>
</div> </div>
<div class="mb-3"> <div class="mb-3">
@@ -637,9 +637,10 @@
<div class="flex justify-center mb-3"> <div class="flex justify-center mb-3">
<canvas id="receive-qr"></canvas> <canvas id="receive-qr"></canvas>
</div> </div>
<div class="border border-border p-2 break-all mb-3 text-xs"> <div
<span id="receive-dot"></span> class="border border-border p-2 break-all mb-3 text-xs cursor-pointer"
<span id="receive-address" class="select-all"></span> >
<span id="receive-address-block" class="select-all"></span>
<span id="receive-etherscan-link"></span> <span id="receive-etherscan-link"></span>
</div> </div>
<button <button

View File

@@ -95,10 +95,22 @@ function show(txInfo) {
// Token contract section (ERC-20 only) // Token contract section (ERC-20 only)
const tokenSection = $("confirm-token-section"); const tokenSection = $("confirm-token-section");
if (isErc20) { if (isErc20) {
const dot = addressDotHtml(txInfo.token);
const link = etherscanTokenLink(txInfo.token); const link = etherscanTokenLink(txInfo.token);
$("confirm-token-contract").innerHTML = $("confirm-token-contract").innerHTML =
escapeHtml(txInfo.token) + `<div class="flex items-center">` +
` <a href="${link}" target="_blank" rel="noopener" class="inline-flex items-center">${EXT_ICON}</a>`; dot +
`<span class="break-all underline decoration-dashed cursor-pointer" id="confirm-token-contract-copy" data-copy="${escapeHtml(txInfo.token)}">${escapeHtml(txInfo.token)}</span>` +
`<a href="${link}" target="_blank" rel="noopener" class="inline-flex items-center">${EXT_ICON}</a>` +
`</div>`;
if (txInfo.tokenName) {
$("confirm-token-contract").innerHTML +=
`<div class="mt-1"><span class="text-muted">Name:</span> ${escapeHtml(txInfo.tokenName)}</div>`;
}
if (txInfo.tokenSymbol) {
$("confirm-token-contract").innerHTML +=
`<div class="mt-1"><span class="text-muted">Symbol:</span> ${escapeHtml(txInfo.tokenSymbol)}</div>`;
}
tokenSection.classList.remove("hidden"); tokenSection.classList.remove("hidden");
} else { } else {
tokenSection.classList.add("hidden"); tokenSection.classList.add("hidden");
@@ -273,6 +285,13 @@ function hidePasswordModal() {
} }
function init(ctx) { function init(ctx) {
$("confirm-token-section").addEventListener("click", (e) => {
const copyEl = e.target.closest("[data-copy]");
if (copyEl) {
navigator.clipboard.writeText(copyEl.dataset.copy);
}
});
$("btn-confirm-send").addEventListener("click", () => { $("btn-confirm-send").addEventListener("click", () => {
showPasswordModal(); showPasswordModal();
}); });

View File

@@ -1,4 +1,10 @@
const { $, showView, showFlash, addressDotHtml } = require("./helpers"); const {
$,
showView,
showFlash,
formatAddressHtml,
addressTitle,
} = require("./helpers");
const { state, currentAddress } = require("../../shared/state"); const { state, currentAddress } = require("../../shared/state");
const QRCode = require("qrcode"); const QRCode = require("qrcode");
@@ -12,8 +18,12 @@ const EXT_ICON =
function show() { function show() {
const addr = currentAddress(); const addr = currentAddress();
const address = addr ? addr.address : ""; const address = addr ? addr.address : "";
$("receive-dot").innerHTML = address ? addressDotHtml(address) : ""; const title = address ? addressTitle(address, state.wallets) : null;
$("receive-address").textContent = address; const ensName = addr ? addr.ensName || null : null;
$("receive-address-block").innerHTML = address
? formatAddressHtml(address, ensName, null, title)
: "";
$("receive-address-block").dataset.full = address;
const link = address ? `https://etherscan.io/address/${address}` : ""; const link = address ? `https://etherscan.io/address/${address}` : "";
$("receive-etherscan-link").innerHTML = link $("receive-etherscan-link").innerHTML = link
? `<a href="${link}" target="_blank" rel="noopener" class="inline-flex items-center">${EXT_ICON}</a>` ? `<a href="${link}" target="_blank" rel="noopener" class="inline-flex items-center">${EXT_ICON}</a>`
@@ -50,8 +60,16 @@ function show() {
} }
function init(ctx) { function init(ctx) {
$("receive-address-block").addEventListener("click", () => {
const addr = $("receive-address-block").dataset.full;
if (addr) {
navigator.clipboard.writeText(addr);
showFlash("Copied!");
}
});
$("btn-receive-copy").addEventListener("click", () => { $("btn-receive-copy").addEventListener("click", () => {
const addr = $("receive-address").textContent; const addr = $("receive-address-block").dataset.full;
if (addr) { if (addr) {
navigator.clipboard.writeText(addr); navigator.clipboard.writeText(addr);
showFlash("Copied!"); showFlash("Copied!");

View File

@@ -10,7 +10,11 @@ const {
const { state, currentAddress } = require("../../shared/state"); const { state, currentAddress } = require("../../shared/state");
let ctx; let ctx;
const { getProvider } = require("../../shared/balances"); const { getProvider } = require("../../shared/balances");
const { KNOWN_SYMBOLS, resolveSymbol } = require("../../shared/tokenList"); const {
KNOWN_SYMBOLS,
TOKEN_BY_ADDRESS,
resolveSymbol,
} = require("../../shared/tokenList");
const EXT_ICON = const EXT_ICON =
`<span style="display:inline-block;width:10px;height:10px;margin-left:4px;vertical-align:middle">` + `<span style="display:inline-block;width:10px;height:10px;margin-left:4px;vertical-align:middle">` +
@@ -124,6 +128,7 @@ function init(_ctx) {
let tokenSymbol = null; let tokenSymbol = null;
let tokenBalance = null; let tokenBalance = null;
let tokenName = null;
if (token !== "ETH") { if (token !== "ETH") {
const tb = (addr.tokenBalances || []).find( const tb = (addr.tokenBalances || []).find(
(t) => t.address.toLowerCase() === token.toLowerCase(), (t) => t.address.toLowerCase() === token.toLowerCase(),
@@ -134,6 +139,17 @@ function init(_ctx) {
state.trackedTokens, state.trackedTokens,
); );
tokenBalance = tb ? tb.balance || "0" : "0"; tokenBalance = tb ? tb.balance || "0" : "0";
// Resolve token name from balances, tracked tokens, or known list
const lower = token.toLowerCase();
tokenName =
(tb && tb.name) ||
(
(state.trackedTokens || []).find(
(t) => t.address.toLowerCase() === lower,
) || {}
).name ||
(TOKEN_BY_ADDRESS.get(lower) || {}).name ||
null;
} }
ctx.showConfirmTx({ ctx.showConfirmTx({
@@ -145,6 +161,7 @@ function init(_ctx) {
balance: addr.balance, balance: addr.balance,
tokenSymbol: tokenSymbol, tokenSymbol: tokenSymbol,
tokenBalance: tokenBalance, tokenBalance: tokenBalance,
tokenName: tokenName,
}); });
}); });