feat: expand confirm-tx warnings — closes #114
- Refactor address warnings into src/shared/addressWarnings.js module - getLocalWarnings(address, options): sync checks against local lists - getFullWarnings(address, provider, options): async local + RPC checks - Expand scam address list from 652 to 2417 addresses - Added EtherScamDB (MIT) as additional source - Update confirmTx.js to use the new addressWarnings module
This commit is contained in:
98
src/shared/addressWarnings.js
Normal file
98
src/shared/addressWarnings.js
Normal file
@@ -0,0 +1,98 @@
|
||||
// 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 { 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);
|
||||
|
||||
try {
|
||||
const code = await provider.getCode(address);
|
||||
if (code && code !== "0x") {
|
||||
warnings.push({
|
||||
type: "contract",
|
||||
message:
|
||||
"This address is a smart contract, not a regular wallet.",
|
||||
severity: "warning",
|
||||
});
|
||||
// If it's a contract, skip the tx count check — contracts
|
||||
// may legitimately have zero inbound EOA transactions.
|
||||
return warnings;
|
||||
}
|
||||
} catch (e) {
|
||||
log.errorf("contract check failed:", e.message);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
return warnings;
|
||||
}
|
||||
|
||||
module.exports = { getLocalWarnings, getFullWarnings };
|
||||
Reference in New Issue
Block a user