Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7f259e501e |
@@ -1020,7 +1020,7 @@ on the approval screen, the amount on the wait, success and error screens, the
|
||||
transaction history and the transaction detail screen, and the refusal of a fee
|
||||
above 1 ETH. A chain id that names no network reads `ETH`. Wherever this
|
||||
document shows ETH as the label of a native balance, value or fee, in a "Native
|
||||
ETH transfer" type line, in the contract-recipient warning or in that refusal,
|
||||
ETH transfer" type line, in the two recipient warnings or in that refusal,
|
||||
Sepolia shows `SepoliaETH`. The swap lines keep `ETH`, the router's own name for
|
||||
the native currency, and the ETH/USD price line, shown on mainnet only, keeps
|
||||
its fixed wording.
|
||||
@@ -1730,8 +1730,10 @@ view would leave a wallet one click from deletion.
|
||||
reserved either way
|
||||
- Warnings: inline warnings from the local checks (scam address, self-send)
|
||||
plus four reserved warning boxes made visible by the async checks —
|
||||
recipient with no transaction history, recipient is a contract, burn
|
||||
address, and an Etherscan phishing/scam label
|
||||
recipient that has never sent a transaction and holds no ETH, recipient is
|
||||
a contract, burn address, and an Etherscan phishing/scam label. An address
|
||||
that has received ETH but never sent a transaction still holds that ETH,
|
||||
so it gets no warning
|
||||
- Errors (insufficient balance), plus three reserved error boxes — the
|
||||
amount plus the fee exceeds the balance (ETH transfers), not enough ETH to
|
||||
pay the fee for the transfer (ERC-20 transfers), and the fee could not be
|
||||
|
||||
+6
-11
@@ -634,17 +634,12 @@
|
||||
</div>
|
||||
</div>
|
||||
<div id="confirm-warnings" class="mb-2 invisible"></div>
|
||||
<div id="confirm-recipient-warning" class="mb-2 invisible">
|
||||
<div
|
||||
class="border border-red-500 border-dashed p-2 text-xs font-bold text-red-500"
|
||||
>
|
||||
WARNING: The recipient address has ZERO transaction
|
||||
history. This may indicate a fresh or unused address.
|
||||
Double-check the address before sending.
|
||||
</div>
|
||||
</div>
|
||||
<!-- Its sentence names the network's native token, so show()
|
||||
in confirmTx.js sets it. -->
|
||||
<!-- These two sentences name the network's native token, so
|
||||
show() in confirmTx.js sets them. -->
|
||||
<div
|
||||
id="confirm-recipient-warning"
|
||||
class="mb-2 border border-red-500 border-dashed p-2 text-xs font-bold text-red-500 invisible"
|
||||
></div>
|
||||
<div
|
||||
id="confirm-contract-warning"
|
||||
class="mb-2 border border-red-500 border-dashed p-2 text-xs font-bold text-red-500 invisible"
|
||||
|
||||
@@ -217,7 +217,14 @@ function show(txInfo) {
|
||||
nativeCurrency() +
|
||||
" to this address and try again.";
|
||||
|
||||
// Shown later, once checkRecipientHistory() finds a contract.
|
||||
// Both shown later, by checkRecipientHistory(). The first sentence says
|
||||
// exactly what getFullWarnings() checks.
|
||||
$("confirm-recipient-warning").textContent =
|
||||
"WARNING: The recipient address has never sent a transaction and" +
|
||||
" holds no " +
|
||||
nativeCurrency() +
|
||||
". This may indicate a fresh or unused address. Double-check the" +
|
||||
" address before sending.";
|
||||
$("confirm-contract-warning").textContent =
|
||||
"WARNING: The recipient is a smart contract. Sending " +
|
||||
nativeCurrency() +
|
||||
|
||||
@@ -51,7 +51,8 @@ function getLocalWarnings(address, options = {}) {
|
||||
|
||||
/**
|
||||
* Check an address against local lists AND via RPC queries.
|
||||
* Async — performs network calls to check contract status and tx history.
|
||||
* Async — performs network calls to check contract status, tx count and
|
||||
* balance.
|
||||
*
|
||||
* @param {string} address - The target address to check.
|
||||
* @param {object} provider - An ethers.js provider instance.
|
||||
@@ -78,21 +79,30 @@ async function getFullWarnings(address, provider, options = {}) {
|
||||
log.errorf("contract check failed:", e.shortMessage || e.message);
|
||||
}
|
||||
|
||||
// Skip tx count check for contracts — they may legitimately have
|
||||
// zero inbound EOA transactions.
|
||||
// The transaction count is the number of transactions the address has
|
||||
// sent, so an address that has only ever received has a count of zero.
|
||||
// Native token it received stays in its balance until it sends a
|
||||
// transaction, so the warning also needs a zero balance. A contract is
|
||||
// skipped: it has its own warning above.
|
||||
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",
|
||||
});
|
||||
const balance = await provider.getBalance(address);
|
||||
if (balance === 0n) {
|
||||
warnings.push({
|
||||
type: "new-address",
|
||||
message:
|
||||
"This address has never sent a transaction and holds none of the network's native token. Double-check it is correct.",
|
||||
severity: "info",
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
log.errorf("tx count check failed:", e.shortMessage || e.message);
|
||||
log.errorf(
|
||||
"tx count or balance check failed:",
|
||||
e.shortMessage || e.message,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
// The confirmation screen's warning for a recipient that has never sent a
|
||||
// transaction (https://git.eeqj.de/sneak/AutistMask/issues/528).
|
||||
//
|
||||
// The node's transaction count for an address is the number of transactions
|
||||
// it has sent, so an address that only ever receives, such as a savings
|
||||
// address or an exchange deposit address, has a count of zero. The warning
|
||||
// used to fire on that count alone. It now also needs a zero balance: ETH an
|
||||
// address received stays in its balance until it sends a transaction.
|
||||
|
||||
"use strict";
|
||||
|
||||
const { getFullWarnings } = require("../src/shared/addressWarnings");
|
||||
|
||||
global.fetch = jest.fn(async () => {
|
||||
throw new Error("tests must not perform network requests");
|
||||
});
|
||||
|
||||
const RECIPIENT = "0x" + "b".repeat(40);
|
||||
|
||||
// The warning types getFullWarnings() returns for RECIPIENT when the node
|
||||
// reports it as a regular address with `txCount` sent transactions and a
|
||||
// balance of `balance` wei.
|
||||
async function warningTypes(txCount, balance) {
|
||||
const provider = {
|
||||
getCode: async () => "0x",
|
||||
getTransactionCount: async () => txCount,
|
||||
getBalance: async () => balance,
|
||||
};
|
||||
const warnings = await getFullWarnings(RECIPIENT, provider);
|
||||
return warnings.map((w) => w.type);
|
||||
}
|
||||
|
||||
test("a recipient that has received 0.5 ETH and never sent a transaction gets no warning", async () => {
|
||||
expect(await warningTypes(0, 500000000000000000n)).toEqual([]);
|
||||
});
|
||||
|
||||
test("a recipient that has never sent a transaction and holds no ETH gets the warning", async () => {
|
||||
expect(await warningTypes(0, 0n)).toEqual(["new-address"]);
|
||||
});
|
||||
@@ -267,6 +267,13 @@ describe.each([
|
||||
);
|
||||
});
|
||||
|
||||
test("the warning for a recipient that has never sent a transaction", async () => {
|
||||
await confirmSend("0.1");
|
||||
expect(text("confirm-recipient-warning")).toContain(
|
||||
"has never sent a transaction and holds no " + symbol + ".",
|
||||
);
|
||||
});
|
||||
|
||||
// A token reports whatever symbol it likes. One reporting the label the
|
||||
// wallet shows its native token under, on this network or any other, is
|
||||
// a fake, exactly as one reporting `ETH` always was.
|
||||
|
||||
@@ -74,7 +74,7 @@ test("ethers puts the URL in the error message, not in the short message", async
|
||||
test("the recipient checks before a send", async () => {
|
||||
await getFullWarnings(ADDRESS, getProvider(RPC_URL, "mainnet"));
|
||||
expectFailureLoggedWithoutKey("contract check failed");
|
||||
expectFailureLoggedWithoutKey("tx count check failed");
|
||||
expectFailureLoggedWithoutKey("tx count or balance check failed");
|
||||
});
|
||||
|
||||
test("the ENS reverse lookup", async () => {
|
||||
|
||||
Reference in New Issue
Block a user