Compare commits

...

1 Commits

Author SHA1 Message Date
user
f01a662000 feat: expand warning types for send confirmation
All checks were successful
check / check (push) Successful in 23s
- Combine MEW darklist (652) and CryptoScamDB (2043) into 2314 scam addresses
- Add null/burn address detection with permanent loss warning
- Add contract address detection warning (sending directly to contracts)
- Unify all warnings into single warnings element (sync + async)
- Zero-history warning now uses unified warning system

Closes #114
2026-02-28 16:11:02 -08:00
2 changed files with 2387 additions and 32 deletions

View File

@@ -24,7 +24,7 @@ const { getSignerForAddress } = require("../../shared/wallet");
const { decryptWithPassword } = require("../../shared/vault");
const { formatUsd, getPrice } = require("../../shared/prices");
const { getProvider } = require("../../shared/balances");
const { isScamAddress } = require("../../shared/scamlist");
const { isScamAddress, isNullOrBurnAddress } = require("../../shared/scamlist");
const { ERC20_ABI } = require("../../shared/constants");
const { log } = require("../../shared/log");
const makeBlockie = require("ethereum-blockies-base64");
@@ -38,6 +38,28 @@ const EXT_ICON =
`</svg></span>`;
let pendingTx = null;
// Track active warnings so async checks can append without overwriting.
let activeWarnings = [];
function renderWarnings(el, warnings) {
activeWarnings = warnings.slice();
if (warnings.length > 0) {
el.innerHTML = warnings
.map(
(w) =>
`<div class="border border-border border-dashed p-2 mb-1 text-xs font-bold">WARNING: ${w}</div>`,
)
.join("");
el.classList.remove("hidden");
} else {
el.classList.add("hidden");
}
}
function appendWarning(el, message) {
activeWarnings.push(message);
renderWarnings(el, activeWarnings);
}
function restore() {
const d = state.viewData;
@@ -165,29 +187,24 @@ function show(txInfo) {
$("confirm-balance").textContent = valueWithUsd(bal + " ETH", balUsd);
}
// Check for warnings
// Check for warnings (synchronous checks first, async checks added later)
const warnings = [];
if (isScamAddress(txInfo.to)) {
warnings.push(
"This address is on a known scam/fraud list. Do not send funds to this address.",
);
}
if (isNullOrBurnAddress(txInfo.to)) {
warnings.push(
"This is a null or burn address. Funds sent here will be permanently lost.",
);
}
if (txInfo.to.toLowerCase() === txInfo.from.toLowerCase()) {
warnings.push("You are sending to your own address.");
}
const warningsEl = $("confirm-warnings");
if (warnings.length > 0) {
warningsEl.innerHTML = warnings
.map(
(w) =>
`<div class="border border-border border-dashed p-2 mb-1 text-xs font-bold">WARNING: ${w}</div>`,
)
.join("");
warningsEl.classList.remove("hidden");
} else {
warningsEl.classList.add("hidden");
}
renderWarnings(warningsEl, warnings);
// Check for errors
const errors = [];
@@ -243,8 +260,11 @@ function show(txInfo) {
state.viewData = { pendingTx: txInfo };
showView("confirm-tx");
// Reset recipient warning to hidden (space always reserved, no layout shift)
$("confirm-recipient-warning").style.visibility = "hidden";
// Hide the legacy recipient warning element (warnings now unified)
const legacyWarningEl = $("confirm-recipient-warning");
if (legacyWarningEl) {
legacyWarningEl.style.display = "none";
}
estimateGas(txInfo);
checkRecipientHistory(txInfo);
@@ -291,19 +311,24 @@ async function estimateGas(txInfo) {
}
async function checkRecipientHistory(txInfo) {
const el = $("confirm-recipient-warning");
const warningsEl = $("confirm-warnings");
try {
const provider = getProvider(state.rpcUrl);
// Skip warning for contract addresses — they may legitimately
// have zero outgoing transactions (getTransactionCount returns
// the nonce, i.e. sent-tx count only).
const code = await provider.getCode(txInfo.to);
if (code && code !== "0x") {
// Recipient is a contract address — warn the user
appendWarning(
warningsEl,
"The recipient is a contract address. Sending tokens directly to a contract may result in permanent loss of funds.",
);
return;
}
const txCount = await provider.getTransactionCount(txInfo.to);
if (txCount === 0) {
el.style.visibility = "visible";
appendWarning(
warningsEl,
"The recipient address has ZERO transaction history. This may indicate a fresh or unused address. Double-check the address before sending.",
);
}
} catch (e) {
log.errorf("recipient history check failed:", e.message);

File diff suppressed because it is too large Load Diff