All checks were successful
check / check (push) Successful in 5s
Expands the confirm-tx warning system with three new warning types, all using the existing `visibility:hidden/visible` pattern from PR #98 (no animations, no layout shift). ## Changes 1. **Scam address list expanded** (7 → 652 addresses): Sourced from [MyEtherWallet/ethereum-lists](https://github.com/MyEtherWallet/ethereum-lists) darklist (MIT license). Checked synchronously before sending. 2. **Contract address warning**: When the recipient is a smart contract (detected via `getCode`), shows a warning that sending directly to a contract may result in permanent loss of funds. 3. **Null/burn address warning**: Detects known burn addresses (`0x0000...0000`, `0x...dead`, `0x...deadbeef`) and warns that funds are permanently destroyed. 4. **No-history warning** (existing from #98): Unchanged, still shows for EOAs with zero transaction history. All warnings use reserved-space `visibility:hidden/visible` elements — no layout shift, no animations. closes #114 Co-authored-by: clawbot <clawbot@noreply.git.eeqj.de> Co-authored-by: user <user@Mac.lan guest wan> Co-authored-by: clawbot <clawbot@eeqj.de> Reviewed-on: #118 Co-authored-by: clawbot <sneak+clawbot@sneak.cloud> Co-committed-by: clawbot <sneak+clawbot@sneak.cloud>
115 lines
3.8 KiB
JavaScript
115 lines
3.8 KiB
JavaScript
// Address warning module.
|
|
// Provides local and async (RPC-based) warning checks for Ethereum addresses.
|
|
// Returns arrays of {type, message, severity} objects.
|
|
|
|
const { isScamAddress } = require("./scamlist");
|
|
const { isBurnAddress } = require("./constants");
|
|
const { checkEtherscanLabel } = require("./etherscanLabels");
|
|
const { log } = require("./log");
|
|
|
|
/**
|
|
* Check an address against local-only lists (scam, burn, self-send).
|
|
* Synchronous — no network calls.
|
|
*
|
|
* @param {string} address - The target address to check.
|
|
* @param {object} [options] - Optional context.
|
|
* @param {string} [options.fromAddress] - Sender address (for self-send check).
|
|
* @returns {Array<{type: string, message: string, severity: string}>}
|
|
*/
|
|
function getLocalWarnings(address, options = {}) {
|
|
const warnings = [];
|
|
const addr = address.toLowerCase();
|
|
|
|
if (isScamAddress(addr)) {
|
|
warnings.push({
|
|
type: "scam",
|
|
message:
|
|
"This address is on a known scam/fraud list. Do not send funds to this address.",
|
|
severity: "critical",
|
|
});
|
|
}
|
|
|
|
if (isBurnAddress(addr)) {
|
|
warnings.push({
|
|
type: "burn",
|
|
message:
|
|
"This is a known null/burn address. Funds sent here are permanently destroyed and cannot be recovered.",
|
|
severity: "critical",
|
|
});
|
|
}
|
|
|
|
if (options.fromAddress && addr === options.fromAddress.toLowerCase()) {
|
|
warnings.push({
|
|
type: "self-send",
|
|
message: "You are sending to your own address.",
|
|
severity: "warning",
|
|
});
|
|
}
|
|
|
|
return warnings;
|
|
}
|
|
|
|
/**
|
|
* Check an address against local lists AND via RPC queries.
|
|
* Async — performs network calls to check contract status and tx history.
|
|
*
|
|
* @param {string} address - The target address to check.
|
|
* @param {object} provider - An ethers.js provider instance.
|
|
* @param {object} [options] - Optional context.
|
|
* @param {string} [options.fromAddress] - Sender address (for self-send check).
|
|
* @returns {Promise<Array<{type: string, message: string, severity: string}>>}
|
|
*/
|
|
async function getFullWarnings(address, provider, options = {}) {
|
|
const warnings = getLocalWarnings(address, options);
|
|
|
|
let isContract = false;
|
|
try {
|
|
const code = await provider.getCode(address);
|
|
if (code && code !== "0x") {
|
|
isContract = true;
|
|
warnings.push({
|
|
type: "contract",
|
|
message:
|
|
"This address is a smart contract, not a regular wallet.",
|
|
severity: "warning",
|
|
});
|
|
}
|
|
} catch (e) {
|
|
log.errorf("contract check failed:", e.message);
|
|
}
|
|
|
|
// Skip tx count check for contracts — they may legitimately have
|
|
// zero inbound EOA transactions.
|
|
if (!isContract) {
|
|
try {
|
|
const txCount = await provider.getTransactionCount(address);
|
|
if (txCount === 0) {
|
|
warnings.push({
|
|
type: "new-address",
|
|
message:
|
|
"This address has never sent a transaction. Double-check it is correct.",
|
|
severity: "info",
|
|
});
|
|
}
|
|
} catch (e) {
|
|
log.errorf("tx count check failed:", e.message);
|
|
}
|
|
}
|
|
|
|
// Etherscan label check (best-effort async — network failures are silent).
|
|
// Runs for ALL addresses including contracts, since many dangerous
|
|
// flagged addresses on Etherscan (drainers, phishing contracts) are contracts.
|
|
try {
|
|
const etherscanWarning = await checkEtherscanLabel(address);
|
|
if (etherscanWarning) {
|
|
warnings.push(etherscanWarning);
|
|
}
|
|
} catch (e) {
|
|
log.errorf("etherscan label check failed:", e.message);
|
|
}
|
|
|
|
return warnings;
|
|
}
|
|
|
|
module.exports = { getLocalWarnings, getFullWarnings };
|