Disable send button after broadcast, show tx link and elapsed timer
Some checks failed
check / check (push) Has been cancelled

Once a transaction is successfully broadcast: disable the send button
to prevent double-sends, immediately show an etherscan link for the
pending tx, and display a live elapsed-time counter that updates every
second until confirmation arrives.
This commit is contained in:
2026-02-26 12:43:11 +07:00
parent 2aebf3ddf9
commit df95522f48

View File

@@ -19,6 +19,7 @@ const { getProvider } = require("../../shared/balances");
const { isScamAddress } = require("../../shared/scamlist"); const { isScamAddress } = require("../../shared/scamlist");
let pendingTx = null; let pendingTx = null;
let elapsedTimer = null;
function show(txInfo) { function show(txInfo) {
pendingTx = txInfo; pendingTx = txInfo;
@@ -172,8 +173,43 @@ function init(ctx) {
to: pendingTx.to, to: pendingTx.to,
value: parseEther(pendingTx.amount), value: parseEther(pendingTx.amount),
}); });
statusEl.textContent = "Sent. Waiting for confirmation...";
// Disable send button immediately after broadcast
const sendBtn = $("btn-confirm-send");
sendBtn.disabled = true;
sendBtn.classList.add("text-muted");
// Show etherscan link and elapsed timer
const broadcastTime = Date.now();
statusEl.innerHTML = "";
statusEl.appendChild(
document.createTextNode(
"Broadcast. Waiting for confirmation... ",
),
);
const timerSpan = document.createElement("span");
timerSpan.textContent = "(0s)";
statusEl.appendChild(timerSpan);
statusEl.appendChild(document.createElement("br"));
const txLink = document.createElement("a");
txLink.href = "https://etherscan.io/tx/" + tx.hash;
txLink.target = "_blank";
txLink.rel = "noopener";
txLink.className = "underline decoration-dashed break-all";
txLink.textContent = tx.hash;
statusEl.appendChild(document.createTextNode("Tx: "));
statusEl.appendChild(txLink);
if (elapsedTimer) clearInterval(elapsedTimer);
elapsedTimer = setInterval(() => {
const elapsed = Math.floor((Date.now() - broadcastTime) / 1000);
timerSpan.textContent = "(" + elapsed + "s)";
}, 1000);
const receipt = await tx.wait(); const receipt = await tx.wait();
clearInterval(elapsedTimer);
elapsedTimer = null;
statusEl.innerHTML = ""; statusEl.innerHTML = "";
statusEl.appendChild( statusEl.appendChild(
document.createTextNode( document.createTextNode(
@@ -189,6 +225,10 @@ function init(ctx) {
statusEl.appendChild(link); statusEl.appendChild(link);
ctx.doRefreshAndRender(); ctx.doRefreshAndRender();
} catch (e) { } catch (e) {
if (elapsedTimer) {
clearInterval(elapsedTimer);
elapsedTimer = null;
}
statusEl.textContent = "Failed: " + (e.shortMessage || e.message); statusEl.textContent = "Failed: " + (e.shortMessage || e.message);
} }
}); });