Compare commits
23 Commits
f290298244
...
feat/issue
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e13af842df | ||
| 6aeab54e8c | |||
| f65764d501 | |||
| 4e097c1e32 | |||
|
|
3f6f98dcaf | ||
|
|
3e900dc14c | ||
|
|
5dfc6e332b | ||
| a182aa534b | |||
| a388100262 | |||
| dd3cabf816 | |||
|
|
235e5e7fa7 | ||
|
|
be06bd8f0c | ||
|
|
a72359432b | ||
|
|
2bdb547995 | ||
| 834228b572 | |||
|
|
813993f17c | ||
| 5f01d9f111 | |||
|
|
d78af3ec80 | ||
| 753fb5658a | |||
| bdb2031d46 | |||
| 25ecaee128 | |||
|
|
ff4b5ee24d | ||
|
|
ca6e9054f9 |
@@ -437,6 +437,10 @@ transitions.
|
||||
- **When**: User tapped a transaction row from AddressDetail or AddressToken.
|
||||
- **Elements**:
|
||||
- "Transaction" heading, "Back" button
|
||||
- Type: transaction classification — one of: Native ETH Transfer, ERC-20
|
||||
Token Transfer, Swap, Token Approval, Contract Call, Contract Creation
|
||||
- Token contract: shown for ERC-20 transfers — color dot + full contract
|
||||
address (tap to copy) + etherscan token link
|
||||
- Status: "Success" or "Failed"
|
||||
- Time: ISO datetime + relative age in parentheses
|
||||
- Amount: value + symbol (bold)
|
||||
@@ -445,6 +449,11 @@ transitions.
|
||||
- To: blockie + color dot + full address (tap to copy) + etherscan link
|
||||
- ENS name if available
|
||||
- Transaction hash: full hash (tap to copy) + etherscan link
|
||||
- Block: block number (tap to copy) + etherscan block link
|
||||
- Nonce: transaction nonce (tap to copy)
|
||||
- Transaction fee: ETH amount (tap to copy)
|
||||
- Gas price: value in Gwei (tap to copy)
|
||||
- Gas used: integer (tap to copy)
|
||||
- **Transitions**:
|
||||
- "Back" → **AddressToken** (if `selectedToken` set) or **AddressDetail**
|
||||
|
||||
|
||||
@@ -107,7 +107,8 @@
|
||||
</div>
|
||||
<div
|
||||
id="add-wallet-phrase-warning"
|
||||
class="text-xs mb-2 border border-border border-dashed p-2 hidden"
|
||||
class="text-xs mb-2 border border-border border-dashed p-2"
|
||||
style="visibility: hidden"
|
||||
>
|
||||
Write these words down and keep them safe. Anyone with
|
||||
them can take your funds; if you lose them, your wallet
|
||||
@@ -184,7 +185,7 @@
|
||||
<!-- active address headline -->
|
||||
<div
|
||||
id="total-value"
|
||||
class="text-2xl font-bold min-h-[2rem]"
|
||||
class="text-2xl font-bold min-h-[2rem] text-fg"
|
||||
></div>
|
||||
<div
|
||||
id="total-value-sub"
|
||||
@@ -375,7 +376,8 @@
|
||||
</p>
|
||||
<div
|
||||
id="export-privkey-flash"
|
||||
class="text-xs mb-2 hidden"
|
||||
class="text-xs mb-2 min-h-[1.25rem]"
|
||||
style="visibility: hidden"
|
||||
></div>
|
||||
<div id="export-privkey-password-section" class="mb-2">
|
||||
<label class="block mb-1">Password</label>
|
||||
@@ -579,13 +581,17 @@
|
||||
<div class="text-xs text-muted mb-1">Your balance</div>
|
||||
<div id="confirm-balance" class="text-xs"></div>
|
||||
</div>
|
||||
<div id="confirm-fee" class="mb-3 hidden">
|
||||
<div id="confirm-fee" class="mb-3" style="visibility: hidden">
|
||||
<div class="text-xs text-muted mb-1">
|
||||
Estimated network fee
|
||||
</div>
|
||||
<div id="confirm-fee-amount" class="text-xs"></div>
|
||||
</div>
|
||||
<div id="confirm-warnings" class="mb-2 hidden"></div>
|
||||
<div
|
||||
id="confirm-warnings"
|
||||
class="mb-2"
|
||||
style="visibility: hidden"
|
||||
></div>
|
||||
<div
|
||||
id="confirm-recipient-warning"
|
||||
class="mb-2"
|
||||
@@ -599,34 +605,10 @@
|
||||
Double-check the address before sending.
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
id="confirm-contract-warning"
|
||||
class="mb-2"
|
||||
style="visibility: hidden"
|
||||
>
|
||||
<div
|
||||
class="border border-red-500 border-dashed p-2 text-xs font-bold text-red-500"
|
||||
>
|
||||
WARNING: The recipient is a smart contract. Sending ETH
|
||||
or tokens directly to a contract may result in permanent
|
||||
loss of funds.
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
id="confirm-burn-warning"
|
||||
class="mb-2"
|
||||
style="visibility: hidden"
|
||||
>
|
||||
<div
|
||||
class="border border-red-500 border-dashed p-2 text-xs font-bold text-red-500"
|
||||
>
|
||||
WARNING: This is a known null/burn address. Funds sent
|
||||
here are permanently destroyed and cannot be recovered.
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
id="confirm-errors"
|
||||
class="mb-2 border border-border border-dashed p-2 hidden"
|
||||
class="mb-2 border border-border border-dashed p-2"
|
||||
style="visibility: hidden; min-height: 1.25rem"
|
||||
></div>
|
||||
<div class="mb-2">
|
||||
<label class="block mb-1 text-xs">Password</label>
|
||||
@@ -639,6 +621,7 @@
|
||||
<div
|
||||
id="confirm-tx-password-error"
|
||||
class="text-xs mb-2 min-h-[1.25rem]"
|
||||
style="visibility: hidden"
|
||||
></div>
|
||||
<button
|
||||
id="btn-confirm-send"
|
||||
@@ -753,7 +736,8 @@
|
||||
</button>
|
||||
<div
|
||||
id="receive-erc20-warning"
|
||||
class="text-xs border border-border border-dashed p-2 mt-3 hidden"
|
||||
class="text-xs border border-border border-dashed p-2 mt-3"
|
||||
style="visibility: hidden"
|
||||
></div>
|
||||
</div>
|
||||
|
||||
@@ -781,7 +765,8 @@
|
||||
</div>
|
||||
<div
|
||||
id="add-token-info"
|
||||
class="text-xs text-muted mb-2 hidden"
|
||||
class="text-xs text-muted mb-2 min-h-[1.25rem]"
|
||||
style="visibility: hidden"
|
||||
></div>
|
||||
<div class="mb-2">
|
||||
<label class="block mb-1 text-xs text-muted"
|
||||
@@ -839,7 +824,7 @@
|
||||
<div class="bg-well p-3 mx-1 mb-3">
|
||||
<h3 class="font-bold mb-1">Display</h3>
|
||||
<label
|
||||
class="text-xs flex items-center gap-1 cursor-pointer"
|
||||
class="text-xs flex items-center gap-1 cursor-pointer mb-2"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
@@ -847,6 +832,17 @@
|
||||
/>
|
||||
Show tracked tokens with zero balance
|
||||
</label>
|
||||
<div class="text-xs flex items-center gap-1">
|
||||
<label for="settings-theme">Theme:</label>
|
||||
<select
|
||||
id="settings-theme"
|
||||
class="border border-border p-1 bg-bg text-fg text-xs cursor-pointer"
|
||||
>
|
||||
<option value="system">System</option>
|
||||
<option value="light">Light</option>
|
||||
<option value="dark">Dark</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-well p-3 mx-1 mb-3">
|
||||
@@ -928,6 +924,12 @@
|
||||
/>
|
||||
<span class="text-xs text-muted">gwei</span>
|
||||
</div>
|
||||
<label
|
||||
class="text-xs flex items-center gap-1 cursor-pointer mb-1"
|
||||
>
|
||||
<input type="checkbox" id="settings-utc-timestamps" />
|
||||
UTC Timestamps
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="bg-well p-3 mx-1 mb-3">
|
||||
@@ -963,7 +965,8 @@
|
||||
</p>
|
||||
<div
|
||||
id="delete-wallet-flash"
|
||||
class="text-xs text-red-500 mb-2 hidden"
|
||||
class="text-xs text-red-500 mb-2 min-h-[1.25rem]"
|
||||
style="visibility: hidden"
|
||||
></div>
|
||||
<div class="mb-2">
|
||||
<label class="block mb-1">Password</label>
|
||||
@@ -1038,7 +1041,8 @@
|
||||
/>
|
||||
<div
|
||||
id="settings-addtoken-info"
|
||||
class="text-xs text-muted mt-1 hidden"
|
||||
class="text-xs text-muted mt-1 min-h-[1.25rem]"
|
||||
style="visibility: hidden"
|
||||
></div>
|
||||
<button
|
||||
id="btn-settings-addtoken-manual"
|
||||
@@ -1060,60 +1064,134 @@
|
||||
<h2 id="tx-detail-heading" class="font-bold mb-2">
|
||||
Transaction
|
||||
</h2>
|
||||
<div id="tx-detail-type-section" class="mb-4 hidden">
|
||||
<div class="text-xs text-muted mb-1">Type</div>
|
||||
<div id="tx-detail-type" class="text-xs font-bold"></div>
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<div class="text-xs text-muted mb-1">Status</div>
|
||||
<div id="tx-detail-status" class="text-xs"></div>
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<div class="text-xs text-muted mb-1">Time</div>
|
||||
<div id="tx-detail-time" class="text-xs"></div>
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<div class="text-xs text-muted mb-1">Amount</div>
|
||||
<div id="tx-detail-value" class="text-xs"></div>
|
||||
</div>
|
||||
<div class="mb-4 hidden">
|
||||
<div class="text-xs text-muted mb-1">Native quantity</div>
|
||||
<div id="tx-detail-native" class="text-xs"></div>
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<div class="text-xs text-muted mb-1">From</div>
|
||||
<div id="tx-detail-from" class="text-xs break-all"></div>
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<div class="text-xs text-muted mb-1">To</div>
|
||||
<div id="tx-detail-to" class="text-xs break-all"></div>
|
||||
</div>
|
||||
<div id="tx-detail-calldata-section" class="mb-4 hidden">
|
||||
<div
|
||||
id="tx-detail-calldata-well"
|
||||
class="mb-3 border border-border border-dashed p-2"
|
||||
>
|
||||
<div class="text-xs text-muted mb-1">Action</div>
|
||||
|
||||
<!-- ── Identity ── -->
|
||||
<div class="tx-detail-group mb-1">
|
||||
<div class="mb-3">
|
||||
<div class="text-xs text-muted mb-1">
|
||||
Transaction hash
|
||||
</div>
|
||||
<div
|
||||
id="tx-detail-calldata-action"
|
||||
class="text-xs font-bold mb-2"
|
||||
id="tx-detail-hash"
|
||||
class="text-xs break-all"
|
||||
></div>
|
||||
</div>
|
||||
<div id="tx-detail-type-section" class="mb-3 hidden">
|
||||
<div class="text-xs text-muted mb-1">Type</div>
|
||||
<div
|
||||
id="tx-detail-calldata-details"
|
||||
class="text-xs"
|
||||
id="tx-detail-type"
|
||||
class="text-xs font-bold"
|
||||
></div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<div class="text-xs text-muted mb-1">Status</div>
|
||||
<div id="tx-detail-status" class="text-xs"></div>
|
||||
</div>
|
||||
<div class="mb-1">
|
||||
<div class="text-xs text-muted mb-1">Time</div>
|
||||
<div id="tx-detail-time" class="text-xs"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ── Value ── -->
|
||||
<div class="tx-detail-group mb-1">
|
||||
<div class="mb-3">
|
||||
<div class="text-xs text-muted mb-1">Amount</div>
|
||||
<div id="tx-detail-value" class="text-xs"></div>
|
||||
</div>
|
||||
<div class="mb-3 hidden">
|
||||
<div class="text-xs text-muted mb-1">
|
||||
Native quantity
|
||||
</div>
|
||||
<div id="tx-detail-native" class="text-xs"></div>
|
||||
</div>
|
||||
<div
|
||||
id="tx-detail-token-contract-section"
|
||||
class="mb-1 hidden"
|
||||
>
|
||||
<div class="text-xs text-muted mb-1">
|
||||
Token contract
|
||||
</div>
|
||||
<div
|
||||
id="tx-detail-token-contract"
|
||||
class="text-xs break-all"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<div class="text-xs text-muted mb-1">Transaction hash</div>
|
||||
<div id="tx-detail-hash" class="text-xs break-all"></div>
|
||||
|
||||
<!-- ── Parties ── -->
|
||||
<div class="tx-detail-group mb-1">
|
||||
<div class="mb-3">
|
||||
<div class="text-xs text-muted mb-1">From</div>
|
||||
<div
|
||||
id="tx-detail-from"
|
||||
class="text-xs break-all"
|
||||
></div>
|
||||
</div>
|
||||
<div class="mb-1">
|
||||
<div class="text-xs text-muted mb-1">To</div>
|
||||
<div id="tx-detail-to" class="text-xs break-all"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ── Protocol ── -->
|
||||
<div id="tx-detail-calldata-section" class="mb-1 hidden">
|
||||
<div class="tx-detail-group mb-1">
|
||||
<div
|
||||
id="tx-detail-calldata-well"
|
||||
class="border border-border border-dashed p-2"
|
||||
>
|
||||
<div class="text-xs text-muted mb-1">Action</div>
|
||||
<div
|
||||
id="tx-detail-calldata-action"
|
||||
class="text-xs font-bold mb-2"
|
||||
></div>
|
||||
<div
|
||||
id="tx-detail-calldata-details"
|
||||
class="text-xs"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ── On-chain details ── -->
|
||||
<div
|
||||
id="tx-detail-onchain-group"
|
||||
class="tx-detail-group mb-1 hidden"
|
||||
>
|
||||
<div id="tx-detail-block-section" class="mb-3 hidden">
|
||||
<div class="text-xs text-muted mb-1">Block</div>
|
||||
<div id="tx-detail-block" class="text-xs"></div>
|
||||
</div>
|
||||
<div id="tx-detail-nonce-section" class="mb-3 hidden">
|
||||
<div class="text-xs text-muted mb-1">Nonce</div>
|
||||
<div id="tx-detail-nonce" class="text-xs"></div>
|
||||
</div>
|
||||
<div id="tx-detail-fee-section" class="mb-3 hidden">
|
||||
<div class="text-xs text-muted mb-1">
|
||||
Transaction fee
|
||||
</div>
|
||||
<div id="tx-detail-fee" class="text-xs"></div>
|
||||
</div>
|
||||
<div id="tx-detail-gasprice-section" class="mb-3 hidden">
|
||||
<div class="text-xs text-muted mb-1">Gas price</div>
|
||||
<div id="tx-detail-gasprice" class="text-xs"></div>
|
||||
</div>
|
||||
<div id="tx-detail-gasused-section" class="mb-1 hidden">
|
||||
<div class="text-xs text-muted mb-1">Gas used</div>
|
||||
<div id="tx-detail-gasused" class="text-xs"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ── Raw data ── -->
|
||||
<div id="tx-detail-rawdata-section" class="mb-4 hidden">
|
||||
<div class="text-xs text-muted mb-1">Raw data</div>
|
||||
<div
|
||||
id="tx-detail-rawdata"
|
||||
class="text-xs break-all font-mono border border-border border-dashed p-2"
|
||||
></div>
|
||||
<div class="tx-detail-group">
|
||||
<div class="text-xs text-muted mb-1">Raw data</div>
|
||||
<div
|
||||
id="tx-detail-rawdata"
|
||||
class="text-xs break-all font-mono border border-border border-dashed p-2"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1164,7 +1242,8 @@
|
||||
</div>
|
||||
<div
|
||||
id="approve-tx-error"
|
||||
class="text-xs mb-2 border border-border border-dashed p-1 min-h-[1.25rem] hidden"
|
||||
class="text-xs mb-2 border border-border border-dashed p-1 min-h-[1.25rem]"
|
||||
style="visibility: hidden"
|
||||
></div>
|
||||
<div class="flex justify-between">
|
||||
<button
|
||||
@@ -1192,8 +1271,10 @@
|
||||
|
||||
<div
|
||||
id="approve-sign-danger-warning"
|
||||
class="hidden mb-3 p-2 text-xs font-bold"
|
||||
class="mb-3 p-2 text-xs font-bold"
|
||||
style="
|
||||
visibility: hidden;
|
||||
min-height: 1.25rem;
|
||||
background: #fee2e2;
|
||||
color: #991b1b;
|
||||
border: 2px solid #dc2626;
|
||||
@@ -1230,7 +1311,8 @@
|
||||
</div>
|
||||
<div
|
||||
id="approve-sign-error"
|
||||
class="text-xs mb-2 border border-border border-dashed p-1 min-h-[1.25rem] hidden"
|
||||
class="text-xs mb-2 border border-border border-dashed p-1 min-h-[1.25rem]"
|
||||
style="visibility: hidden"
|
||||
></div>
|
||||
<div class="flex justify-between">
|
||||
<button
|
||||
|
||||
@@ -6,6 +6,7 @@ const { state, saveState, loadState } = require("../shared/state");
|
||||
const { refreshPrices } = require("../shared/prices");
|
||||
const { refreshBalances } = require("../shared/balances");
|
||||
const { $, showView } = require("./views/helpers");
|
||||
const { applyTheme } = require("./theme");
|
||||
|
||||
const home = require("./views/home");
|
||||
const welcome = require("./views/welcome");
|
||||
@@ -176,6 +177,7 @@ async function init() {
|
||||
}
|
||||
|
||||
await loadState();
|
||||
applyTheme(state.theme);
|
||||
|
||||
// Auto-default active address
|
||||
if (
|
||||
|
||||
@@ -15,7 +15,40 @@
|
||||
--color-section: #dddddd;
|
||||
}
|
||||
|
||||
html.dark {
|
||||
--color-bg: #000000;
|
||||
--color-fg: #ffffff;
|
||||
--color-muted: #aaaaaa;
|
||||
--color-border: #ffffff;
|
||||
--color-border-light: #444444;
|
||||
--color-hover: #222222;
|
||||
--color-well: #1a1a1a;
|
||||
--color-danger-well: #2a0a0a;
|
||||
--color-section: #2a2a2a;
|
||||
}
|
||||
|
||||
body {
|
||||
width: 396px;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
/* Copy-flash feedback: inverts colors then fades back */
|
||||
.copy-flash-active {
|
||||
background-color: var(--color-fg) !important;
|
||||
color: var(--color-bg) !important;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.copy-flash-fade {
|
||||
transition:
|
||||
background-color 225ms ease-out,
|
||||
color 225ms ease-out;
|
||||
}
|
||||
|
||||
/* Transaction detail view — visual grouping of related fields */
|
||||
.tx-detail-group {
|
||||
border-bottom: 1px solid var(--color-border-light);
|
||||
padding-bottom: 0.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
padding-top: 0.25rem;
|
||||
}
|
||||
|
||||
33
src/popup/theme.js
Normal file
33
src/popup/theme.js
Normal file
@@ -0,0 +1,33 @@
|
||||
// Theme management: applies light/dark class to <html> based on preference.
|
||||
|
||||
let mediaQuery = null;
|
||||
let mediaHandler = null;
|
||||
|
||||
function applyTheme(theme) {
|
||||
// Clean up previous system listener
|
||||
if (mediaQuery && mediaHandler) {
|
||||
mediaQuery.removeEventListener("change", mediaHandler);
|
||||
mediaHandler = null;
|
||||
}
|
||||
|
||||
if (theme === "dark") {
|
||||
document.documentElement.classList.add("dark");
|
||||
} else if (theme === "light") {
|
||||
document.documentElement.classList.remove("dark");
|
||||
} else {
|
||||
// system
|
||||
mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
||||
const update = () => {
|
||||
if (mediaQuery.matches) {
|
||||
document.documentElement.classList.add("dark");
|
||||
} else {
|
||||
document.documentElement.classList.remove("dark");
|
||||
}
|
||||
};
|
||||
mediaHandler = update;
|
||||
mediaQuery.addEventListener("change", update);
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { applyTheme };
|
||||
@@ -7,7 +7,8 @@ const { log } = require("../../shared/log");
|
||||
|
||||
function show() {
|
||||
$("add-token-address").value = "";
|
||||
$("add-token-info").classList.add("hidden");
|
||||
$("add-token-info").textContent = "";
|
||||
$("add-token-info").style.visibility = "hidden";
|
||||
const list = $("common-token-list");
|
||||
list.innerHTML = getTopTokens(25)
|
||||
.map(
|
||||
@@ -45,7 +46,7 @@ function init(ctx) {
|
||||
}
|
||||
const infoEl = $("add-token-info");
|
||||
infoEl.textContent = "Looking up token...";
|
||||
infoEl.classList.remove("hidden");
|
||||
infoEl.style.visibility = "visible";
|
||||
log.debugf("Looking up token contract", contractAddr);
|
||||
try {
|
||||
const info = await lookupTokenInfo(contractAddr, state.rpcUrl);
|
||||
@@ -63,7 +64,8 @@ function init(ctx) {
|
||||
const detail = e.shortMessage || e.message || String(e);
|
||||
log.errorf("Token lookup failed for", contractAddr, detail);
|
||||
showFlash(detail);
|
||||
infoEl.classList.add("hidden");
|
||||
infoEl.textContent = "";
|
||||
infoEl.style.visibility = "hidden";
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -11,6 +11,25 @@ const { encryptWithPassword } = require("../../shared/vault");
|
||||
const { state, saveState } = require("../../shared/state");
|
||||
const { scanForAddresses } = require("../../shared/balances");
|
||||
|
||||
/**
|
||||
* Check if an address already exists in ANY wallet (hd, xprv, or key).
|
||||
* Returns the wallet object if found, or undefined.
|
||||
*/
|
||||
function findWalletByAddress(addr) {
|
||||
const lower = addr.toLowerCase();
|
||||
return state.wallets.find((w) =>
|
||||
w.addresses.some((a) => a.address.toLowerCase() === lower),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an xpub already exists in any HD-type wallet (hd or xprv).
|
||||
* Returns the wallet object if found, or undefined.
|
||||
*/
|
||||
function findWalletByXpub(xpub) {
|
||||
return state.wallets.find((w) => w.xpub && w.xpub === xpub);
|
||||
}
|
||||
|
||||
let currentMode = "mnemonic";
|
||||
|
||||
const MODES = ["mnemonic", "privkey", "xprv"];
|
||||
@@ -52,7 +71,7 @@ function show() {
|
||||
$("import-xprv-key").value = "";
|
||||
$("add-wallet-password").value = "";
|
||||
$("add-wallet-password-confirm").value = "";
|
||||
$("add-wallet-phrase-warning").classList.add("hidden");
|
||||
$("add-wallet-phrase-warning").style.visibility = "hidden";
|
||||
switchMode("mnemonic");
|
||||
showView("add-wallet");
|
||||
}
|
||||
@@ -97,18 +116,18 @@ async function importMnemonic(ctx) {
|
||||
const pw = validatePassword();
|
||||
if (!pw) return;
|
||||
const { xpub, firstAddress } = hdWalletFromMnemonic(mnemonic);
|
||||
const duplicate = state.wallets.find(
|
||||
(w) =>
|
||||
w.type === "hd" &&
|
||||
w.addresses[0] &&
|
||||
w.addresses[0].address.toLowerCase() === firstAddress.toLowerCase(),
|
||||
);
|
||||
if (duplicate) {
|
||||
const xpubDup = findWalletByXpub(xpub);
|
||||
if (xpubDup) {
|
||||
showFlash(
|
||||
"This recovery phrase is already added (" + duplicate.name + ").",
|
||||
"This recovery phrase is already added (" + xpubDup.name + ").",
|
||||
);
|
||||
return;
|
||||
}
|
||||
const addrDup = findWalletByAddress(firstAddress);
|
||||
if (addrDup) {
|
||||
showFlash("Address already exists in wallet (" + addrDup.name + ").");
|
||||
return;
|
||||
}
|
||||
const encrypted = await encryptWithPassword(mnemonic, pw);
|
||||
const walletNum = state.wallets.length + 1;
|
||||
const wallet = {
|
||||
@@ -162,15 +181,10 @@ async function importPrivateKey(ctx) {
|
||||
}
|
||||
const pw = validatePassword();
|
||||
if (!pw) return;
|
||||
const duplicate = state.wallets.find(
|
||||
(w) =>
|
||||
w.type === "key" &&
|
||||
w.addresses[0] &&
|
||||
w.addresses[0].address.toLowerCase() === addr.toLowerCase(),
|
||||
);
|
||||
const duplicate = findWalletByAddress(addr);
|
||||
if (duplicate) {
|
||||
showFlash(
|
||||
"This private key is already added (" + duplicate.name + ").",
|
||||
"This address already exists in wallet (" + duplicate.name + ").",
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -208,14 +222,14 @@ async function importXprvKey(ctx) {
|
||||
return;
|
||||
}
|
||||
const { xpub, firstAddress } = result;
|
||||
const duplicate = state.wallets.find(
|
||||
(w) =>
|
||||
(w.type === "hd" || w.type === "xprv") &&
|
||||
w.addresses[0] &&
|
||||
w.addresses[0].address.toLowerCase() === firstAddress.toLowerCase(),
|
||||
);
|
||||
if (duplicate) {
|
||||
showFlash("This key is already added (" + duplicate.name + ").");
|
||||
const xpubDup = findWalletByXpub(xpub);
|
||||
if (xpubDup) {
|
||||
showFlash("This key is already added (" + xpubDup.name + ").");
|
||||
return;
|
||||
}
|
||||
const addrDup = findWalletByAddress(firstAddress);
|
||||
if (addrDup) {
|
||||
showFlash("Address already exists in wallet (" + addrDup.name + ").");
|
||||
return;
|
||||
}
|
||||
const pw = validatePassword();
|
||||
@@ -267,7 +281,7 @@ function init(ctx) {
|
||||
// Generate mnemonic
|
||||
$("btn-generate-phrase").addEventListener("click", () => {
|
||||
$("wallet-mnemonic").value = generateMnemonic();
|
||||
$("add-wallet-phrase-warning").classList.remove("hidden");
|
||||
$("add-wallet-phrase-warning").style.visibility = "visible";
|
||||
});
|
||||
|
||||
// Import / confirm
|
||||
|
||||
@@ -2,6 +2,7 @@ const {
|
||||
$,
|
||||
showView,
|
||||
showFlash,
|
||||
flashCopyFeedback,
|
||||
balanceLinesForAddress,
|
||||
addressDotHtml,
|
||||
addressTitle,
|
||||
@@ -94,18 +95,39 @@ function show() {
|
||||
function isoDate(timestamp) {
|
||||
const d = new Date(timestamp * 1000);
|
||||
const pad = (n) => String(n).padStart(2, "0");
|
||||
if (state.utcTimestamps) {
|
||||
return (
|
||||
d.getUTCFullYear() +
|
||||
"-" +
|
||||
pad(d.getUTCMonth() + 1) +
|
||||
"-" +
|
||||
pad(d.getUTCDate()) +
|
||||
"T" +
|
||||
pad(d.getUTCHours()) +
|
||||
":" +
|
||||
pad(d.getUTCMinutes()) +
|
||||
":" +
|
||||
pad(d.getUTCSeconds()) +
|
||||
"Z"
|
||||
);
|
||||
}
|
||||
const offsetMin = -d.getTimezoneOffset();
|
||||
const sign = offsetMin >= 0 ? "+" : "-";
|
||||
const absOff = Math.abs(offsetMin);
|
||||
const tzStr = sign + pad(Math.floor(absOff / 60)) + ":" + pad(absOff % 60);
|
||||
return (
|
||||
d.getFullYear() +
|
||||
"-" +
|
||||
pad(d.getMonth() + 1) +
|
||||
"-" +
|
||||
pad(d.getDate()) +
|
||||
" " +
|
||||
"T" +
|
||||
pad(d.getHours()) +
|
||||
":" +
|
||||
pad(d.getMinutes()) +
|
||||
":" +
|
||||
pad(d.getSeconds())
|
||||
pad(d.getSeconds()) +
|
||||
tzStr
|
||||
);
|
||||
}
|
||||
|
||||
@@ -241,6 +263,7 @@ function init(_ctx) {
|
||||
if (addr) {
|
||||
navigator.clipboard.writeText(addr);
|
||||
showFlash("Copied!");
|
||||
flashCopyFeedback($("address-full"));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -310,8 +333,8 @@ function init(_ctx) {
|
||||
$("export-privkey-address").textContent = addr.address;
|
||||
$("export-privkey-address").dataset.full = addr.address;
|
||||
$("export-privkey-password").value = "";
|
||||
$("export-privkey-flash").classList.add("hidden");
|
||||
$("export-privkey-flash").textContent = "";
|
||||
$("export-privkey-flash").style.visibility = "hidden";
|
||||
$("export-privkey-password-section").classList.remove("hidden");
|
||||
$("export-privkey-result").classList.add("hidden");
|
||||
$("export-privkey-value").textContent = "";
|
||||
@@ -322,7 +345,7 @@ function init(_ctx) {
|
||||
const password = $("export-privkey-password").value;
|
||||
if (!password) {
|
||||
$("export-privkey-flash").textContent = "Password is required.";
|
||||
$("export-privkey-flash").classList.remove("hidden");
|
||||
$("export-privkey-flash").style.visibility = "visible";
|
||||
return;
|
||||
}
|
||||
const btn = $("btn-export-privkey-confirm");
|
||||
@@ -343,10 +366,10 @@ function init(_ctx) {
|
||||
$("export-privkey-password-section").classList.add("hidden");
|
||||
$("export-privkey-value").textContent = privateKey;
|
||||
$("export-privkey-result").classList.remove("hidden");
|
||||
$("export-privkey-flash").classList.add("hidden");
|
||||
$("export-privkey-flash").style.visibility = "hidden";
|
||||
} catch {
|
||||
$("export-privkey-flash").textContent = "Wrong password.";
|
||||
$("export-privkey-flash").classList.remove("hidden");
|
||||
$("export-privkey-flash").style.visibility = "visible";
|
||||
} finally {
|
||||
btn.disabled = false;
|
||||
btn.classList.remove("text-muted");
|
||||
@@ -358,6 +381,7 @@ function init(_ctx) {
|
||||
if (key) {
|
||||
navigator.clipboard.writeText(key);
|
||||
showFlash("Copied!");
|
||||
flashCopyFeedback($("export-privkey-value"));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -366,6 +390,7 @@ function init(_ctx) {
|
||||
if (full) {
|
||||
navigator.clipboard.writeText(full);
|
||||
showFlash("Copied!");
|
||||
flashCopyFeedback($("export-privkey-address"));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ const {
|
||||
$,
|
||||
showView,
|
||||
showFlash,
|
||||
flashCopyFeedback,
|
||||
addressDotHtml,
|
||||
addressTitle,
|
||||
escapeHtml,
|
||||
@@ -47,18 +48,39 @@ function etherscanAddressLink(address) {
|
||||
function isoDate(timestamp) {
|
||||
const d = new Date(timestamp * 1000);
|
||||
const pad = (n) => String(n).padStart(2, "0");
|
||||
if (state.utcTimestamps) {
|
||||
return (
|
||||
d.getUTCFullYear() +
|
||||
"-" +
|
||||
pad(d.getUTCMonth() + 1) +
|
||||
"-" +
|
||||
pad(d.getUTCDate()) +
|
||||
"T" +
|
||||
pad(d.getUTCHours()) +
|
||||
":" +
|
||||
pad(d.getUTCMinutes()) +
|
||||
":" +
|
||||
pad(d.getUTCSeconds()) +
|
||||
"Z"
|
||||
);
|
||||
}
|
||||
const offsetMin = -d.getTimezoneOffset();
|
||||
const sign = offsetMin >= 0 ? "+" : "-";
|
||||
const absOff = Math.abs(offsetMin);
|
||||
const tzStr = sign + pad(Math.floor(absOff / 60)) + ":" + pad(absOff % 60);
|
||||
return (
|
||||
d.getFullYear() +
|
||||
"-" +
|
||||
pad(d.getMonth() + 1) +
|
||||
"-" +
|
||||
pad(d.getDate()) +
|
||||
" " +
|
||||
"T" +
|
||||
pad(d.getHours()) +
|
||||
":" +
|
||||
pad(d.getMinutes()) +
|
||||
":" +
|
||||
pad(d.getSeconds())
|
||||
pad(d.getSeconds()) +
|
||||
tzStr
|
||||
);
|
||||
}
|
||||
|
||||
@@ -317,6 +339,7 @@ function init(_ctx) {
|
||||
if (addr) {
|
||||
navigator.clipboard.writeText(addr);
|
||||
showFlash("Copied!");
|
||||
flashCopyFeedback($("address-token-full"));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -325,6 +348,7 @@ function init(_ctx) {
|
||||
if (copyEl) {
|
||||
navigator.clipboard.writeText(copyEl.dataset.copy);
|
||||
showFlash("Copied!");
|
||||
flashCopyFeedback(copyEl);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -373,6 +397,7 @@ function init(_ctx) {
|
||||
copyEl.addEventListener("click", () => {
|
||||
navigator.clipboard.writeText(copyEl.dataset.copy);
|
||||
showFlash("Copied!");
|
||||
flashCopyFeedback(copyEl);
|
||||
});
|
||||
}
|
||||
updateSendBalance();
|
||||
|
||||
@@ -269,7 +269,7 @@ function showTxApproval(details) {
|
||||
}
|
||||
|
||||
$("approve-tx-password").value = "";
|
||||
$("approve-tx-error").classList.add("hidden");
|
||||
hideError("approve-tx-error");
|
||||
|
||||
showView("approve-tx");
|
||||
}
|
||||
@@ -351,10 +351,10 @@ function showSignApproval(details) {
|
||||
if (warningEl) {
|
||||
if (sp.dangerWarning) {
|
||||
warningEl.textContent = sp.dangerWarning;
|
||||
warningEl.classList.remove("hidden");
|
||||
warningEl.style.visibility = "visible";
|
||||
} else {
|
||||
warningEl.textContent = "";
|
||||
warningEl.classList.add("hidden");
|
||||
warningEl.style.visibility = "hidden";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ const {
|
||||
hideError,
|
||||
showView,
|
||||
showFlash,
|
||||
flashCopyFeedback,
|
||||
addressTitle,
|
||||
addressDotHtml,
|
||||
escapeHtml,
|
||||
@@ -25,7 +26,7 @@ const { decryptWithPassword } = require("../../shared/vault");
|
||||
const { formatUsd, getPrice } = require("../../shared/prices");
|
||||
const { getProvider } = require("../../shared/balances");
|
||||
const { isScamAddress } = require("../../shared/scamlist");
|
||||
const { ERC20_ABI, isBurnAddress } = require("../../shared/constants");
|
||||
const { ERC20_ABI } = require("../../shared/constants");
|
||||
const { log } = require("../../shared/log");
|
||||
const makeBlockie = require("ethereum-blockies-base64");
|
||||
const txStatus = require("./txStatus");
|
||||
@@ -117,6 +118,7 @@ function show(txInfo) {
|
||||
copyEl.onclick = () => {
|
||||
navigator.clipboard.writeText(copyEl.dataset.copy);
|
||||
showFlash("Copied!");
|
||||
flashCopyFeedback(copyEl);
|
||||
};
|
||||
}
|
||||
} else {
|
||||
@@ -165,18 +167,13 @@ function show(txInfo) {
|
||||
$("confirm-balance").textContent = valueWithUsd(bal + " ETH", balUsd);
|
||||
}
|
||||
|
||||
// Check for warnings (synchronous checks)
|
||||
// Check for warnings
|
||||
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 (isBurnAddress(txInfo.to)) {
|
||||
warnings.push(
|
||||
"This is a known null/burn address. Funds sent here are permanently destroyed and cannot be recovered.",
|
||||
);
|
||||
}
|
||||
if (txInfo.to.toLowerCase() === txInfo.from.toLowerCase()) {
|
||||
warnings.push("You are sending to your own address.");
|
||||
}
|
||||
@@ -189,9 +186,10 @@ function show(txInfo) {
|
||||
`<div class="border border-border border-dashed p-2 mb-1 text-xs font-bold">WARNING: ${w}</div>`,
|
||||
)
|
||||
.join("");
|
||||
warningsEl.classList.remove("hidden");
|
||||
warningsEl.style.visibility = "visible";
|
||||
} else {
|
||||
warningsEl.classList.add("hidden");
|
||||
warningsEl.innerHTML = "";
|
||||
warningsEl.style.visibility = "hidden";
|
||||
}
|
||||
|
||||
// Check for errors
|
||||
@@ -229,11 +227,12 @@ function show(txInfo) {
|
||||
errorsEl.innerHTML = errors
|
||||
.map((e) => `<div class="text-xs">${e}</div>`)
|
||||
.join("");
|
||||
errorsEl.classList.remove("hidden");
|
||||
errorsEl.style.visibility = "visible";
|
||||
sendBtn.disabled = true;
|
||||
sendBtn.classList.add("text-muted");
|
||||
} else {
|
||||
errorsEl.classList.add("hidden");
|
||||
errorsEl.innerHTML = "";
|
||||
errorsEl.style.visibility = "hidden";
|
||||
sendBtn.disabled = false;
|
||||
sendBtn.classList.remove("text-muted");
|
||||
}
|
||||
@@ -243,20 +242,13 @@ function show(txInfo) {
|
||||
hideError("confirm-tx-password-error");
|
||||
|
||||
// Gas estimate — show placeholder then fetch async
|
||||
$("confirm-fee").classList.remove("hidden");
|
||||
$("confirm-fee").style.visibility = "visible";
|
||||
$("confirm-fee-amount").textContent = "Estimating...";
|
||||
state.viewData = { pendingTx: txInfo };
|
||||
showView("confirm-tx");
|
||||
|
||||
// Reset async warnings to hidden (space always reserved, no layout shift)
|
||||
// Reset recipient warning to hidden (space always reserved, no layout shift)
|
||||
$("confirm-recipient-warning").style.visibility = "hidden";
|
||||
$("confirm-contract-warning").style.visibility = "hidden";
|
||||
$("confirm-burn-warning").style.visibility = "hidden";
|
||||
|
||||
// Show burn warning via reserved element (in addition to inline warning)
|
||||
if (isBurnAddress(txInfo.to)) {
|
||||
$("confirm-burn-warning").style.visibility = "visible";
|
||||
}
|
||||
|
||||
estimateGas(txInfo);
|
||||
checkRecipientHistory(txInfo);
|
||||
@@ -303,17 +295,19 @@ async function estimateGas(txInfo) {
|
||||
}
|
||||
|
||||
async function checkRecipientHistory(txInfo) {
|
||||
const el = $("confirm-recipient-warning");
|
||||
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 — warn the user
|
||||
$("confirm-contract-warning").style.visibility = "visible";
|
||||
return;
|
||||
}
|
||||
const txCount = await provider.getTransactionCount(txInfo.to);
|
||||
if (txCount === 0) {
|
||||
$("confirm-recipient-warning").style.visibility = "visible";
|
||||
el.style.visibility = "visible";
|
||||
}
|
||||
} catch (e) {
|
||||
log.errorf("recipient history check failed:", e.message);
|
||||
|
||||
@@ -12,7 +12,7 @@ function show(walletIdx) {
|
||||
wallet.name || "Wallet " + (walletIdx + 1);
|
||||
$("delete-wallet-password").value = "";
|
||||
$("delete-wallet-flash").textContent = "";
|
||||
$("delete-wallet-flash").classList.add("hidden");
|
||||
$("delete-wallet-flash").style.visibility = "hidden";
|
||||
showView("delete-wallet-confirm");
|
||||
}
|
||||
|
||||
@@ -29,14 +29,14 @@ function init(_ctx) {
|
||||
if (!pw) {
|
||||
$("delete-wallet-flash").textContent =
|
||||
"Please enter your password.";
|
||||
$("delete-wallet-flash").classList.remove("hidden");
|
||||
$("delete-wallet-flash").style.visibility = "visible";
|
||||
return;
|
||||
}
|
||||
|
||||
if (deleteWalletIndex === null) {
|
||||
$("delete-wallet-flash").textContent =
|
||||
"No wallet selected for deletion.";
|
||||
$("delete-wallet-flash").classList.remove("hidden");
|
||||
$("delete-wallet-flash").style.visibility = "visible";
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ function init(_ctx) {
|
||||
await decryptWithPassword(wallet.encryptedSecret, pw);
|
||||
} catch (_e) {
|
||||
$("delete-wallet-flash").textContent = "Wrong password.";
|
||||
$("delete-wallet-flash").classList.remove("hidden");
|
||||
$("delete-wallet-flash").style.visibility = "visible";
|
||||
btn.disabled = false;
|
||||
btn.classList.remove("text-muted");
|
||||
return;
|
||||
|
||||
@@ -40,11 +40,13 @@ function $(id) {
|
||||
function showError(id, msg) {
|
||||
const el = $(id);
|
||||
el.textContent = msg;
|
||||
el.classList.remove("hidden");
|
||||
el.style.visibility = "visible";
|
||||
}
|
||||
|
||||
function hideError(id) {
|
||||
$(id).classList.add("hidden");
|
||||
const el = $(id);
|
||||
el.textContent = "";
|
||||
el.style.visibility = "hidden";
|
||||
}
|
||||
|
||||
function showView(name) {
|
||||
@@ -226,18 +228,39 @@ function formatAddressHtml(address, ensName, maxLen, title) {
|
||||
function isoDate(timestamp) {
|
||||
const d = new Date(timestamp * 1000);
|
||||
const pad = (n) => String(n).padStart(2, "0");
|
||||
if (state.utcTimestamps) {
|
||||
return (
|
||||
d.getUTCFullYear() +
|
||||
"-" +
|
||||
pad(d.getUTCMonth() + 1) +
|
||||
"-" +
|
||||
pad(d.getUTCDate()) +
|
||||
"T" +
|
||||
pad(d.getUTCHours()) +
|
||||
":" +
|
||||
pad(d.getUTCMinutes()) +
|
||||
":" +
|
||||
pad(d.getUTCSeconds()) +
|
||||
"Z"
|
||||
);
|
||||
}
|
||||
const offsetMin = -d.getTimezoneOffset();
|
||||
const sign = offsetMin >= 0 ? "+" : "-";
|
||||
const absOff = Math.abs(offsetMin);
|
||||
const tzStr = sign + pad(Math.floor(absOff / 60)) + ":" + pad(absOff % 60);
|
||||
return (
|
||||
d.getFullYear() +
|
||||
"-" +
|
||||
pad(d.getMonth() + 1) +
|
||||
"-" +
|
||||
pad(d.getDate()) +
|
||||
" " +
|
||||
"T" +
|
||||
pad(d.getHours()) +
|
||||
":" +
|
||||
pad(d.getMinutes()) +
|
||||
":" +
|
||||
pad(d.getSeconds())
|
||||
pad(d.getSeconds()) +
|
||||
tzStr
|
||||
);
|
||||
}
|
||||
|
||||
@@ -258,12 +281,26 @@ function timeAgo(timestamp) {
|
||||
return years + " year" + (years !== 1 ? "s" : "") + " ago";
|
||||
}
|
||||
|
||||
function flashCopyFeedback(el) {
|
||||
if (!el) return;
|
||||
el.classList.remove("copy-flash-fade");
|
||||
el.classList.add("copy-flash-active");
|
||||
setTimeout(() => {
|
||||
el.classList.remove("copy-flash-active");
|
||||
el.classList.add("copy-flash-fade");
|
||||
setTimeout(() => {
|
||||
el.classList.remove("copy-flash-fade");
|
||||
}, 275);
|
||||
}, 75);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
$,
|
||||
showError,
|
||||
hideError,
|
||||
showView,
|
||||
showFlash,
|
||||
flashCopyFeedback,
|
||||
balanceLine,
|
||||
balanceLinesForAddress,
|
||||
addressColor,
|
||||
|
||||
@@ -2,6 +2,7 @@ const {
|
||||
$,
|
||||
showView,
|
||||
showFlash,
|
||||
flashCopyFeedback,
|
||||
balanceLinesForAddress,
|
||||
isoDate,
|
||||
timeAgo,
|
||||
@@ -85,9 +86,10 @@ function renderActiveAddress() {
|
||||
el.innerHTML =
|
||||
`<span class="underline decoration-dashed cursor-pointer" id="active-addr-copy">${dot}${escapeHtml(addr)}</span>` +
|
||||
`<a href="${link}" target="_blank" rel="noopener" class="inline-flex items-center">${EXT_ICON}</a>`;
|
||||
$("active-addr-copy").addEventListener("click", () => {
|
||||
$("active-addr-copy").addEventListener("click", (e) => {
|
||||
navigator.clipboard.writeText(addr);
|
||||
showFlash("Copied!");
|
||||
flashCopyFeedback(e.currentTarget);
|
||||
});
|
||||
} else {
|
||||
el.textContent = "";
|
||||
|
||||
@@ -2,6 +2,7 @@ const {
|
||||
$,
|
||||
showView,
|
||||
showFlash,
|
||||
flashCopyFeedback,
|
||||
formatAddressHtml,
|
||||
addressTitle,
|
||||
} = require("./helpers");
|
||||
@@ -52,19 +53,21 @@ function show() {
|
||||
"This is an ERC-20 token. Only send " +
|
||||
symbol +
|
||||
" on the Ethereum network to this address. Sending tokens on other networks will result in permanent loss.";
|
||||
warningEl.classList.remove("hidden");
|
||||
warningEl.style.visibility = "visible";
|
||||
} else {
|
||||
warningEl.classList.add("hidden");
|
||||
warningEl.textContent = "";
|
||||
warningEl.style.visibility = "hidden";
|
||||
}
|
||||
showView("receive");
|
||||
}
|
||||
|
||||
function init(ctx) {
|
||||
$("receive-address-block").addEventListener("click", () => {
|
||||
$("receive-address-block").addEventListener("click", (e) => {
|
||||
const addr = $("receive-address-block").dataset.full;
|
||||
if (addr) {
|
||||
navigator.clipboard.writeText(addr);
|
||||
showFlash("Copied!");
|
||||
flashCopyFeedback(e.currentTarget);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -73,6 +76,7 @@ function init(ctx) {
|
||||
if (addr) {
|
||||
navigator.clipboard.writeText(addr);
|
||||
showFlash("Copied!");
|
||||
flashCopyFeedback($("receive-address-block"));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const { $, showView, showFlash, escapeHtml } = require("./helpers");
|
||||
const { applyTheme } = require("../theme");
|
||||
const { state, saveState } = require("../../shared/state");
|
||||
const { ETHEREUM_MAINNET_CHAIN_ID } = require("../../shared/constants");
|
||||
const { log, debugFetch } = require("../../shared/log");
|
||||
@@ -214,6 +215,13 @@ function init(ctx) {
|
||||
await saveState();
|
||||
});
|
||||
|
||||
$("settings-theme").value = state.theme;
|
||||
$("settings-theme").addEventListener("change", async () => {
|
||||
state.theme = $("settings-theme").value;
|
||||
await saveState();
|
||||
applyTheme(state.theme);
|
||||
});
|
||||
|
||||
$("settings-hide-low-holders").checked = state.hideLowHolderTokens;
|
||||
$("settings-hide-low-holders").addEventListener("change", async () => {
|
||||
state.hideLowHolderTokens = $("settings-hide-low-holders").checked;
|
||||
@@ -241,6 +249,12 @@ function init(ctx) {
|
||||
}
|
||||
});
|
||||
|
||||
$("settings-utc-timestamps").checked = state.utcTimestamps;
|
||||
$("settings-utc-timestamps").addEventListener("change", async () => {
|
||||
state.utcTimestamps = $("settings-utc-timestamps").checked;
|
||||
await saveState();
|
||||
});
|
||||
|
||||
$("btn-main-add-wallet").addEventListener("click", ctx.showAddWalletView);
|
||||
|
||||
$("btn-settings-add-token").addEventListener(
|
||||
|
||||
@@ -73,7 +73,8 @@ function renderDropdown() {
|
||||
|
||||
function show() {
|
||||
$("settings-addtoken-address").value = "";
|
||||
$("settings-addtoken-info").classList.add("hidden");
|
||||
$("settings-addtoken-info").textContent = "";
|
||||
$("settings-addtoken-info").style.visibility = "hidden";
|
||||
renderTop10();
|
||||
renderDropdown();
|
||||
showView("settings-addtoken");
|
||||
@@ -129,7 +130,7 @@ function init(_ctx) {
|
||||
}
|
||||
const infoEl = $("settings-addtoken-info");
|
||||
infoEl.textContent = "Looking up token...";
|
||||
infoEl.classList.remove("hidden");
|
||||
infoEl.style.visibility = "visible";
|
||||
log.debugf("Looking up token contract", addr);
|
||||
try {
|
||||
const info = await lookupTokenInfo(addr, state.rpcUrl);
|
||||
@@ -143,7 +144,8 @@ function init(_ctx) {
|
||||
await saveState();
|
||||
showFlash("Added " + info.symbol);
|
||||
$("settings-addtoken-address").value = "";
|
||||
infoEl.classList.add("hidden");
|
||||
infoEl.textContent = "";
|
||||
infoEl.style.visibility = "hidden";
|
||||
renderTop10();
|
||||
renderDropdown();
|
||||
ctx.doRefreshAndRender();
|
||||
@@ -151,7 +153,8 @@ function init(_ctx) {
|
||||
const detail = e.shortMessage || e.message || String(e);
|
||||
log.errorf("Token lookup failed for", addr, detail);
|
||||
showFlash(detail);
|
||||
infoEl.classList.add("hidden");
|
||||
infoEl.textContent = "";
|
||||
infoEl.style.visibility = "hidden";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ const {
|
||||
$,
|
||||
showView,
|
||||
showFlash,
|
||||
flashCopyFeedback,
|
||||
addressDotHtml,
|
||||
addressTitle,
|
||||
escapeHtml,
|
||||
@@ -12,6 +13,7 @@ const {
|
||||
timeAgo,
|
||||
} = require("./helpers");
|
||||
const { state } = require("../../shared/state");
|
||||
const { formatEther, formatUnits } = require("ethers");
|
||||
const makeBlockie = require("ethereum-blockies-base64");
|
||||
const { log, debugFetch } = require("../../shared/log");
|
||||
const { decodeCalldata } = require("./approval");
|
||||
@@ -25,6 +27,25 @@ const EXT_ICON =
|
||||
|
||||
let ctx;
|
||||
|
||||
/**
|
||||
* Determine a human-readable transaction type string from tx fields.
|
||||
*/
|
||||
function getTransactionType(tx) {
|
||||
if (!tx.to) return "Contract Creation";
|
||||
if (tx.direction === "contract") {
|
||||
if (tx.directionLabel === "Swap") return "Swap";
|
||||
if (
|
||||
tx.method === "approve" ||
|
||||
tx.directionLabel === "Approve" ||
|
||||
tx.method === "setApprovalForAll"
|
||||
)
|
||||
return "Token Approval";
|
||||
return "Contract Call";
|
||||
}
|
||||
if (tx.symbol && tx.symbol !== "ETH") return "ERC-20 Token Transfer";
|
||||
return "Native ETH Transfer";
|
||||
}
|
||||
|
||||
function copyableHtml(text, extraClass) {
|
||||
const cls =
|
||||
"underline decoration-dashed cursor-pointer" +
|
||||
@@ -98,6 +119,7 @@ function show(tx) {
|
||||
direction: tx.direction || null,
|
||||
isContractCall: tx.isContractCall || false,
|
||||
method: tx.method || null,
|
||||
contractAddress: tx.contractAddress || null,
|
||||
},
|
||||
};
|
||||
render();
|
||||
@@ -134,30 +156,56 @@ function render() {
|
||||
nativeEl.parentElement.classList.add("hidden");
|
||||
}
|
||||
|
||||
// Show type label for contract interactions (Swap, Execute, etc.)
|
||||
// Always show transaction type as the first field
|
||||
const typeSection = $("tx-detail-type-section");
|
||||
const typeEl = $("tx-detail-type");
|
||||
const headingEl = $("tx-detail-heading");
|
||||
if (tx.direction === "contract" && tx.directionLabel) {
|
||||
if (typeSection) {
|
||||
typeEl.textContent = tx.directionLabel;
|
||||
typeSection.classList.remove("hidden");
|
||||
}
|
||||
} else {
|
||||
if (typeSection) typeSection.classList.add("hidden");
|
||||
if (typeSection && typeEl) {
|
||||
typeEl.textContent = getTransactionType(tx);
|
||||
typeSection.classList.remove("hidden");
|
||||
}
|
||||
if (headingEl) headingEl.textContent = "Transaction";
|
||||
|
||||
// Hide calldata and raw data sections; re-fetch if this is a contract call
|
||||
// Token contract address (for ERC-20 transfers)
|
||||
const tokenContractSection = $("tx-detail-token-contract-section");
|
||||
const tokenContractEl = $("tx-detail-token-contract");
|
||||
if (tokenContractSection && tokenContractEl) {
|
||||
if (tx.contractAddress) {
|
||||
const dot = addressDotHtml(tx.contractAddress);
|
||||
const link = `https://etherscan.io/token/${tx.contractAddress}`;
|
||||
tokenContractEl.innerHTML =
|
||||
`<div class="flex items-center">${dot}` +
|
||||
copyableHtml(tx.contractAddress, "break-all") +
|
||||
etherscanLinkHtml(link) +
|
||||
`</div>`;
|
||||
tokenContractSection.classList.remove("hidden");
|
||||
} else {
|
||||
tokenContractSection.classList.add("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
// Hide calldata and raw data sections; always fetch full tx details
|
||||
const calldataSection = $("tx-detail-calldata-section");
|
||||
if (calldataSection) calldataSection.classList.add("hidden");
|
||||
const rawDataSection = $("tx-detail-rawdata-section");
|
||||
if (rawDataSection) rawDataSection.classList.add("hidden");
|
||||
|
||||
if (tx.isContractCall || tx.direction === "contract") {
|
||||
loadCalldata(tx.hash, tx.to);
|
||||
// Hide on-chain detail sections (and their group wrapper) until populated
|
||||
const onchainGroup = $("tx-detail-onchain-group");
|
||||
if (onchainGroup) onchainGroup.classList.add("hidden");
|
||||
for (const id of [
|
||||
"tx-detail-block-section",
|
||||
"tx-detail-nonce-section",
|
||||
"tx-detail-fee-section",
|
||||
"tx-detail-gasprice-section",
|
||||
"tx-detail-gasused-section",
|
||||
]) {
|
||||
const el = $(id);
|
||||
if (el) el.classList.add("hidden");
|
||||
}
|
||||
|
||||
loadFullTxDetails(tx.hash, tx.to, tx.isContractCall);
|
||||
|
||||
const isoStr = isoDate(tx.timestamp);
|
||||
$("tx-detail-time").innerHTML =
|
||||
copyableHtml(isoStr) + " (" + escapeHtml(timeAgo(tx.timestamp)) + ")";
|
||||
@@ -171,11 +219,113 @@ function render() {
|
||||
el.onclick = () => {
|
||||
navigator.clipboard.writeText(el.dataset.copy);
|
||||
showFlash("Copied!");
|
||||
flashCopyFeedback(el);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
async function loadCalldata(txHash, toAddress) {
|
||||
function showDetailField(sectionId, contentId, value) {
|
||||
const section = $(sectionId);
|
||||
const el = $(contentId);
|
||||
if (!section || !el) return;
|
||||
el.innerHTML = copyableHtml(value, "");
|
||||
section.classList.remove("hidden");
|
||||
}
|
||||
|
||||
function populateOnChainDetails(txData) {
|
||||
// Block number
|
||||
if (txData.block_number != null) {
|
||||
const blockLink = `https://etherscan.io/block/${txData.block_number}`;
|
||||
const blockSection = $("tx-detail-block-section");
|
||||
const blockEl = $("tx-detail-block");
|
||||
if (blockSection && blockEl) {
|
||||
blockEl.innerHTML =
|
||||
copyableHtml(String(txData.block_number), "") +
|
||||
etherscanLinkHtml(blockLink);
|
||||
blockSection.classList.remove("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
// Nonce
|
||||
if (txData.nonce != null) {
|
||||
showDetailField(
|
||||
"tx-detail-nonce-section",
|
||||
"tx-detail-nonce",
|
||||
String(txData.nonce),
|
||||
);
|
||||
}
|
||||
|
||||
// Transaction fee
|
||||
const feeWei = txData.fee?.value || txData.tx_fee;
|
||||
if (feeWei) {
|
||||
const feeEth = formatEther(String(feeWei));
|
||||
showDetailField(
|
||||
"tx-detail-fee-section",
|
||||
"tx-detail-fee",
|
||||
feeEth + " ETH",
|
||||
);
|
||||
}
|
||||
|
||||
// Gas price
|
||||
const gasPrice = txData.gas_price;
|
||||
if (gasPrice) {
|
||||
const gwei = formatUnits(String(gasPrice), "gwei");
|
||||
showDetailField(
|
||||
"tx-detail-gasprice-section",
|
||||
"tx-detail-gasprice",
|
||||
gwei + " Gwei",
|
||||
);
|
||||
}
|
||||
|
||||
// Gas used
|
||||
const gasUsed = txData.gas_used;
|
||||
if (gasUsed) {
|
||||
showDetailField(
|
||||
"tx-detail-gasused-section",
|
||||
"tx-detail-gasused",
|
||||
String(gasUsed),
|
||||
);
|
||||
}
|
||||
|
||||
// Show the on-chain details group if any child section is visible
|
||||
const onchainGroup = $("tx-detail-onchain-group");
|
||||
if (onchainGroup) {
|
||||
const hasVisible = [
|
||||
"tx-detail-block-section",
|
||||
"tx-detail-nonce-section",
|
||||
"tx-detail-fee-section",
|
||||
"tx-detail-gasprice-section",
|
||||
"tx-detail-gasused-section",
|
||||
].some((id) => {
|
||||
const el = $(id);
|
||||
return el && !el.classList.contains("hidden");
|
||||
});
|
||||
if (hasVisible) {
|
||||
onchainGroup.classList.remove("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
// Bind copy handlers for newly added elements
|
||||
for (const id of [
|
||||
"tx-detail-block-section",
|
||||
"tx-detail-nonce-section",
|
||||
"tx-detail-fee-section",
|
||||
"tx-detail-gasprice-section",
|
||||
"tx-detail-gasused-section",
|
||||
]) {
|
||||
const section = $(id);
|
||||
if (!section) continue;
|
||||
section.querySelectorAll("[data-copy]").forEach((el) => {
|
||||
el.onclick = () => {
|
||||
navigator.clipboard.writeText(el.dataset.copy);
|
||||
showFlash("Copied!");
|
||||
flashCopyFeedback(el);
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function loadFullTxDetails(txHash, toAddress, isContractCall) {
|
||||
const section = $("tx-detail-calldata-section");
|
||||
const actionEl = $("tx-detail-calldata-action");
|
||||
const detailsEl = $("tx-detail-calldata-details");
|
||||
@@ -190,6 +340,10 @@ async function loadCalldata(txHash, toAddress) {
|
||||
);
|
||||
if (!resp.ok) return;
|
||||
const txData = await resp.json();
|
||||
|
||||
// Populate on-chain detail fields (block, nonce, gas, fee)
|
||||
populateOnChainDetails(txData);
|
||||
|
||||
const inputData = txData.raw_input || txData.input || null;
|
||||
if (!inputData || inputData === "0x") return;
|
||||
|
||||
@@ -248,6 +402,7 @@ async function loadCalldata(txHash, toAddress) {
|
||||
el.onclick = () => {
|
||||
navigator.clipboard.writeText(el.dataset.copy);
|
||||
showFlash("Copied!");
|
||||
flashCopyFeedback(el);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ const {
|
||||
$,
|
||||
showView,
|
||||
showFlash,
|
||||
flashCopyFeedback,
|
||||
addressDotHtml,
|
||||
addressTitle,
|
||||
escapeHtml,
|
||||
@@ -77,6 +78,7 @@ function attachCopyHandlers(viewId) {
|
||||
el.onclick = () => {
|
||||
navigator.clipboard.writeText(el.dataset.copy);
|
||||
showFlash("Copied!");
|
||||
flashCopyFeedback(el);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@@ -20,19 +20,6 @@ const ERC20_ABI = [
|
||||
"function approve(address spender, uint256 amount) returns (bool)",
|
||||
];
|
||||
|
||||
// Known null/burn addresses that permanently destroy funds.
|
||||
const BURN_ADDRESSES = new Set([
|
||||
"0x0000000000000000000000000000000000000000",
|
||||
"0x0000000000000000000000000000000000000001",
|
||||
"0x000000000000000000000000000000000000dead",
|
||||
"0xdead000000000000000000000000000000000000",
|
||||
"0x00000000000000000000000000000000deadbeef",
|
||||
]);
|
||||
|
||||
function isBurnAddress(address) {
|
||||
return BURN_ADDRESSES.has(address.toLowerCase());
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
DEBUG,
|
||||
DEBUG_MNEMONIC,
|
||||
@@ -41,6 +28,4 @@ module.exports = {
|
||||
DEFAULT_BLOCKSCOUT_URL,
|
||||
BIP44_ETH_PATH,
|
||||
ERC20_ABI,
|
||||
BURN_ADDRESSES,
|
||||
isBurnAddress,
|
||||
};
|
||||
|
||||
@@ -8,666 +8,23 @@
|
||||
// and does not enforce jurisdiction-specific sanctions.
|
||||
//
|
||||
// Sources:
|
||||
// - MyEtherWallet/ethereum-lists addresses-darklist.json (MIT license)
|
||||
// https://github.com/MyEtherWallet/ethereum-lists
|
||||
// - Known wallet-drainer contracts identified via Etherscan labels,
|
||||
// MistTrack alerts, and community incident reports.
|
||||
// MistTrack alerts, and community incident reports (e.g. address-
|
||||
// poisoning campaigns, phishing kit deployments).
|
||||
//
|
||||
// All addresses lowercased for comparison.
|
||||
|
||||
const SCAM_ADDRESSES = new Set([
|
||||
"0x0059b14e35dab1b4eee1e2926c7a5660da66f747",
|
||||
"0x008f3db10374099a11ec263415cb88c952abeedc",
|
||||
"0x00e01a648ff41346cdeb873182383333d2184dd1",
|
||||
"0x0153775362c3071c1860e8dbfd53ccc82fa226f5",
|
||||
"0x02673ebfbfaed5891f6b14248b0e2753a8758fbf",
|
||||
"0x02f4a464eebb46a50dd087074d7a2cf3f5a3598b",
|
||||
"0x0310c4385311d225cbcaca26fefc9ab45d3eba3e",
|
||||
"0x0387cfc283ffcf25a4a6a61e832545bbeb7c8fda",
|
||||
"0x03f034fb47965123ea4148e3147e2cfdc5b1f7a5",
|
||||
"0x052f585fa599bfb4bed290ff30c057627ccd8059",
|
||||
"0x05dd62c007cde143b402fa5da3937c40c70b4b14",
|
||||
"0x05e3650bfc907cc1b3c774f0c053c8b990ce1a4b",
|
||||
"0x05e5061133f752ea565f40f1e755d9604c313bc9",
|
||||
"0x069a6761e9897ced3f5d13f4aa9ad745e526c913",
|
||||
"0x071cf579507dd0661845694f709e68cf7ea506a4",
|
||||
"0x07425527076b4f73b5616716dda54fb14cf1219e",
|
||||
"0x0755e59d505c9b473aec50b476df3ea2045739aa",
|
||||
"0x07a065bbc565002740caccb22b452fdd029ba988",
|
||||
"0x07faacbe52a8b5d3d22f49206bdd9d9c1f71991d",
|
||||
"0x08389b19ad52f0d983609ab785b3a43a0e90355f",
|
||||
"0x09750ad360fdb7a2ee23669c4503c974d86d8694",
|
||||
"0x09cc69f6b484cada8e152d2002adfca496d723f3",
|
||||
"0x09faf25e57abd0a401bb5a2341d7f926c389f8d1",
|
||||
"0x0a00fb2e074ffaaf6c561164c6458b5c448120fc",
|
||||
"0x0a4392f623faf54de72cbf6f567e1a7808251cd3",
|
||||
"0x0a78fa6dab70385dd46fbdd20da5d868eb43f904",
|
||||
"0x0a9f58ee19a7131ed031ea66a032c05c7efe965a",
|
||||
"0x0ae775637e63fa95855246fd82e96802d05883fc",
|
||||
"0x0af16719353eddc122eaf834638406c499197860",
|
||||
"0x0b1f025593acd090a6c9b754e6e46acf88e89646",
|
||||
"0x0b21fd643aaaf5af800af67e14ebf4886be20164",
|
||||
"0x0b591a58137f154f59aea1284166d6a7b49821fd",
|
||||
"0x0b7f284d74f549731499c44aed2a10adcc9e9cc0",
|
||||
"0x0bdd81d2a676166f2a28691e8af64ebeeca67fae",
|
||||
"0x0c8b0b3e963becf16cda410fe1eb4b5d64022c94",
|
||||
"0x0c9d1b3ca852c67bbeabeeb51e9482a845d56868",
|
||||
"0x0d502f90c0a740b9c069ddec1c436d483ed7ab8e",
|
||||
"0x0d87ca679a7ab95598b34eb54dafc356b0373388",
|
||||
"0x0d9786138578fcdcce04435592545ef08422d755",
|
||||
"0x0d979f9ffdd579d67c29531cccba568d2172d0b0",
|
||||
"0x0dac7a548551dd2e0f7293005f14f9261d7e0196",
|
||||
"0x0dc04198cd942b55a7d63f5c3891122b6fa277ea",
|
||||
"0x0dcc89f3091d3ef66e00fb595ed0fafef4434192",
|
||||
"0x0dea8a35f4e39cdf65d3cc11f10612e9e0278b60",
|
||||
"0x0e04298d9eaffaf538fe04b4cd525b6d1b64c3ca",
|
||||
"0x0ef2724a6d8be9f72f3d35b62e1e8a37ceaf721e",
|
||||
"0x0f7a4c36b5ee28e581504e8dfa62fa83a11ca7a9",
|
||||
"0x101c55c14bbde713d4c718b67256133bac8126c6",
|
||||
"0x1086feeb031e45e8fcd770662aa8302d7c23ba1f",
|
||||
"0x116574a18659f0063150e0064e4ea00349a1492c",
|
||||
"0x119240ef17333e8dcb19a0dd4f5fc848981b0ff4",
|
||||
"0x122c7f492c51c247e293b0f996fa63de61474959",
|
||||
"0x12736c6b02381c3c50e41db3a69d7bb651a77d57",
|
||||
"0x1363077895b20ae90f80794ce4e575559517d033",
|
||||
"0x14130d36b36887620c37a404f859d11e293ec06a",
|
||||
"0x143494359bbacc878308075c1c9fa05fcda96651",
|
||||
"0x1447b1cb205158d98fdbd312b37ed9dd1481fb62",
|
||||
"0x1494403137159bb0dc545d11963fdf797ea1ecab",
|
||||
"0x15577e328dd6e17b7721c9ca4d00610d3ce3762f",
|
||||
"0x15847dcd428033c2cc2cb70edf2cbd6c84afc146",
|
||||
"0x15a99893dc47bfae5b06e9b4c8941aaca60f8af5",
|
||||
"0x15f4a5d5bbc071fc20bd60b9b7d81aaa8a1142ab",
|
||||
"0x16112015d50fac2d084e096feea0863800517f94",
|
||||
"0x169b6c7ed548e45ba9d87b2d32ff27e2d00051ef",
|
||||
"0x16b9c4333559256ca7d87b28c6fb2e8415b4711f",
|
||||
"0x175e0d5f3757b066a6f0cf7634b45f3085cb490b",
|
||||
"0x175f6dbf87215a6da7107977b4680bc3db31b2de",
|
||||
"0x17bd6f815fb71a77dc20e12177c4d763a3f67632",
|
||||
"0x181c71726f12ce2514e8b93019eb22645a79f966",
|
||||
"0x18345118bd04c405b4d74941563a21b5a2bf06b7",
|
||||
"0x18e81898ac31a43850fb8d0224477349de6d8d9a",
|
||||
"0x18ec1d727320cbed7c0c63cd655ade997b292c5e",
|
||||
"0x18f3489d959fd0e3fac366646e08f9aeabea4d75",
|
||||
"0x1982b0e96a0375e5b570e8e466d423a37af34b43",
|
||||
"0x199eee5b6ca1aaf030c77f0b5c50e39908fd2072",
|
||||
"0x19fb7020381fe9197bf841d5034d5467fe5a3c93",
|
||||
"0x1a2c53d132ff8a6e26f6b32c0abdc179b94f0721",
|
||||
"0x1aef1e14108786e0b049f37758529d866cc3c7e6",
|
||||
"0x1b42bf30cd988ad20500ce47cce52098576ec2a2",
|
||||
"0x1c0dffa23f342a62ace37bd4eede6180c40ccbec",
|
||||
"0x1c0e294310091654beac3d191089d3c376be123f",
|
||||
"0x1c2fb401d3dc4fd8131ccfc4589f281d58921402",
|
||||
"0x1c39d6e0278d1a28ce21dbd73826559b010224e5",
|
||||
"0x1c50139c266559b29d7cb27635e0da13bef76a09",
|
||||
"0x1ccc9b2769741ab0e1620721df7cf8ff1d70716b",
|
||||
"0x1ccd65d573057c388ea96cc8be30c18a6d21185d",
|
||||
"0x1cea7999fdafe5d156952ebf1816e8aa67a5485e",
|
||||
"0x1d60606d8a09b5015d773a80b0c660bb8d91809c",
|
||||
"0x1d64ea27764164debb4e891eb04d524f42904b08",
|
||||
"0x1d82886f997d0b124dfab342558bc463299c8a6b",
|
||||
"0x1de23f02e185fdc4f6bacc98d6c6419370e38538",
|
||||
"0x1dea82c5628ae89572a153a556312832ee33fda9",
|
||||
"0x1e12436889e2459202437077549e35b56f1299cb",
|
||||
"0x1e3c07ce10973fcaebc81468af1d3f390d2a4c71",
|
||||
"0x1e67f055367bcbce045e1211f09355eb7411236f",
|
||||
"0x1e75f03ff928bca6c1692179679afc0223d7824f",
|
||||
"0x1e80dad60d19fb8159af3f440a8ceaa0e5581847",
|
||||
"0x2056d2e97cc9ad78cf527b382495a8b9704ce011",
|
||||
"0x21918461c6aeca5eaec825b4746d64a0d4028df6",
|
||||
"0x22374a2e9e19bcea56e64f9de3329670cd1a458c",
|
||||
"0x2268751eafc860781074d25f4bd10ded480310b9",
|
||||
"0x22764de8f82f2d2a90e0ccca4556a2a5114b6461",
|
||||
"0x22eb0b23e5ad7ef827aff13b2e40ed63e277844e",
|
||||
"0x2315314c5cadb895c2c9982b847fd6f6a32d6129",
|
||||
"0x23d56797f64640e96feaf57b7874c897b53ef0e4",
|
||||
"0x240e125c20a4cc84bd6e7f8d1fd07aff4c06d43d",
|
||||
"0x247733af8b2bb8e63e3a2a419761c0fd71d40499",
|
||||
"0x24aa18952e80707dad3ab4c9c97e787f2af337ca",
|
||||
"0x24c00035b050bec633287c2babfbb9f4fe3c8a83",
|
||||
"0x259efb559a5d9ed64ccf44bd5188b325dc4738c8",
|
||||
"0x25dc5894db8ef7f7ff7096ea73b890c1a188d549",
|
||||
"0x25f8b4acd2c37d7ebae0066fdf9f13f327c0c4eb",
|
||||
"0x26f7eb488661c33c43089ad61944f3231222b32f",
|
||||
"0x2789b7b3557f39643198433daebf6b43512be65b",
|
||||
"0x2804e8b4c04c655376d18ada84d46fc345240e0a",
|
||||
"0x285cfe87f4ad22228a625dcd1f64b2bc6b27ecff",
|
||||
"0x2903e9f1d81fac8ccc313b5b496f2db7db6750b6",
|
||||
"0x29e225d888cf11c5e67613bffd30bcf071eb3d4a",
|
||||
"0x2a6d8021861f27ab992572d8689017b7a83c989d",
|
||||
"0x2a7d04018d7295d8069ec9721ee415c4bdc57909",
|
||||
"0x2b065809f6ec6df32878bcd26711a0e2bcf59c26",
|
||||
"0x2b3f15a55a68c4c81ae8331c2fe8e90008993f51",
|
||||
"0x2b5268fde5041f6b1afd77166de4e9ea5d9e967a",
|
||||
"0x2bcc8aefa2fc9d8e52dad098778bb0a8d08a4aa3",
|
||||
"0x2d146aa23645950fdefbb23f636a5d1674fe1047",
|
||||
"0x2d4498a2cf71f5b0946f0ebcfff97ca9d0cd5d04",
|
||||
"0x2da8703d18afed53b303119e4ff06cf035a9fadb",
|
||||
"0x2f141d0cd81011436df8fa04bdac01cb6cf51a65",
|
||||
"0x2f77f4523a13138b472ac6faef624cce68da2c46",
|
||||
"0x2f80a6700e4bea478ac027f019f04a78a7538d06",
|
||||
"0x3007a0db9caad557cf4589cfd550c21ce9399b15",
|
||||
"0x300d4fbdb7ef38488eb9338982686e04ba426715",
|
||||
"0x3018a3eab048a0a1c15003b383a181f089a039cc",
|
||||
"0x303f41f4e6a1e1fc9cc2738c722b73b3d9fe54cb",
|
||||
"0x31537238bb5b237254b629bf226b566c617f182b",
|
||||
"0x316b3b83c33b20249b61ded124f2620d8e823793",
|
||||
"0x33bf8bde242216da572d6486d641ae0a18137306",
|
||||
"0x33f6ee23ee223c4558a95bf4c0e9f5ed21e06319",
|
||||
"0x33f74739ce6be3b2c38af76f5adb3866cb4784c4",
|
||||
"0x34743ffa1f93e745668725e44efeb3c50a237796",
|
||||
"0x35ad1cb9a39de486cebcce3cf51661fd6c848193",
|
||||
"0x362291375bd3fc2ff0f928184bd6f373f92dea57",
|
||||
"0x3639b8b8eda816b2cb62b65159a183972a3cf863",
|
||||
"0x3681828da105fc3c44e212f6c3dc51a0a5a6f5c6",
|
||||
"0x36db23fd8e0fabb300ba95bfdf4a0f20b05eebfb",
|
||||
"0x3715b1ed9bbd5e165af97619b5c5e13e39f55504",
|
||||
"0x371850498d1bd60d67110d1d046ffabc10f957ec",
|
||||
"0x379ce20c018fb6301c1872c429ec7270ffa4dc5b",
|
||||
"0x37c81cc9ff71d0f97849a947bf22e8e529b72230",
|
||||
"0x37c85a7523b1832b4d0380b2f513e88b66e8c850",
|
||||
"0x37d0909cc7ec38f2d966092ea3607f77bc6bc008",
|
||||
"0x3810bd434103f1d0618b909ba14e4d2d707d79f7",
|
||||
"0x3853ba76ec6ae97818e2d0e0839c9eda6c396690",
|
||||
"0x3884eb0ae2a04bce65b5b0ca9c1bd069cbd52c66",
|
||||
"0x38b7ca3b78c51364095bc56146d25f55aee0af21",
|
||||
"0x38c36d3faab64c0770af26cc6ee95d91312bc53c",
|
||||
"0x394f59e83d88469d3ca3b8da15f31b73f27eada7",
|
||||
"0x395b53a4ef9736d698e86607047267f7f640fe34",
|
||||
"0x39a7c26ada0e575d69f05dd6b8086f0ddd99e207",
|
||||
"0x39ac3008be15cd3e3f23786faa0550c3e0b92ff2",
|
||||
"0x39d7c7acec5bb282a4fb6e998d3d0099ff7780cf",
|
||||
"0x39f3e7fa18d342de467ad9d7065a46c8385589f7",
|
||||
"0x3a3999e6501e2a36dd3c0b8fc2bd165fc4a22e54",
|
||||
"0x3aa65f17cde339df49afd2f88b3c8495842d5fb0",
|
||||
"0x3ad44a16451d65d97394ac793b0a2d90c8530499",
|
||||
"0x3b0009071a0a9983e9aab537fd8c9ad478310aeb",
|
||||
"0x3b5744c7f340e0d2dcf7a072a4c963b9a43c982b",
|
||||
"0x3c3b85b2ae785a8cc16c3d4df12cb27c6983dff5",
|
||||
"0x3cf71871d2f56a6af21bf17ca2652cbc12e8ba1f",
|
||||
"0x3d11b2189ad65e0e91e2f2b0e07cbc05ddc75b7a",
|
||||
"0x3de08b35c0e7f255f37a5dace9bd8eb78e99e985",
|
||||
"0x3dfe9f7af8864df0b7cc2a20430006fd1af8da1a",
|
||||
"0x3e2b9f6b67fc972419af5e9818281b745a6bf83b",
|
||||
"0x3f4d77cdabf58f5bfd2ef20784cafd58334542f8",
|
||||
"0x3fcb2d173389b7cd8079ef8b439dbd92e7e0ae28",
|
||||
"0x40b942240fec55473388cbf7dbcc5482e64b4367",
|
||||
"0x4114fb8b1879f61b18f7d2e623569a847a03e15a",
|
||||
"0x414bca672494b8f078112c52ae258f9e8de1a4a0",
|
||||
"0x41dfc5797c8043a2f4f7e7abf71291064e091fc6",
|
||||
"0x42a777e0f24390e7ed461a7af325526e53ac57d9",
|
||||
"0x42c5459911ae51d1d005cbe39749bd8d8e533c22",
|
||||
"0x42ff5fff0e369ef6880875efcacb3b7c77974abc",
|
||||
"0x434e9f6a1ac134fda3e7ceb3fd67c3d9b3518737",
|
||||
"0x439cb5628e64677c540a8635c86e41d83c1170d5",
|
||||
"0x43ac6aae3c5dd21855c3aabe3cadb7dfdcf2e5be",
|
||||
"0x43f030a549f780d1af59a782eaadce4dec7ba183",
|
||||
"0x4411db7be552b487e3681e890ed14de9a9b24f7b",
|
||||
"0x4423b4d5174dd6fca701c053bf48faeaaaee59f0",
|
||||
"0x44a7ff01f7d38c73530c279e19d31527bdcf8c78",
|
||||
"0x45029af827c652f47b1f678456b2cd009647c8ad",
|
||||
"0x4541c7745c82df8c10bd4a58e28161534b353064",
|
||||
"0x4566b8b849dcdbe04f64bf1909db313cf60d6e41",
|
||||
"0x45750cd6a3bb2206dbeb9cba5e68bf909ac945e3",
|
||||
"0x474aa9c6f46dc6379c638690fd8f5ade22df5205",
|
||||
"0x47dc6f08214f891cc910d6d2abfb504c2584f14f",
|
||||
"0x484aa220812a5ed3d1162686bc8592eb39276348",
|
||||
"0x4899f3371fb9f8e68a0b639bf1fd75220a089c42",
|
||||
"0x48d0a447b1d7b9a89112578db4536032d3047b2e",
|
||||
"0x49311a81f5f5df6c109599ed5d7413d85b8bca18",
|
||||
"0x495a8b1fdba38d726e514e95b4f1657c69fefa0a",
|
||||
"0x4999924fd714092fe92ca9a792a8549f798c1dc2",
|
||||
"0x4a0d27a1044dd871a93275de5109e5f5efc4d46e",
|
||||
"0x4a500bf6818ba31bb2b1dc90a354ab64ad3301dd",
|
||||
"0x4bb1c210e3921e0f051ed00e898b9605c902114e",
|
||||
"0x4bde78ead56a30055d33bf84f52e420b0f6070ba",
|
||||
"0x4bf722014e54aeab05fcf1519e6e4c0c3f742e43",
|
||||
"0x4c191dca6cecfa1e55caa3cf178eea52728b13e7",
|
||||
"0x4c569022016eba68ea10dee702670dc82d2749af",
|
||||
"0x4cdc1cba0aeb5539f2e0ba158281e67e0e54a9b1",
|
||||
"0x4da9608f15c504a2b5c46491d9ccf257c5e2ff71",
|
||||
"0x4de76b3dfd38292ba71cf2465ca3a1d526dcb567",
|
||||
"0x4e556877e96fdf3bef67c81ef72e20ab29a9aebf",
|
||||
"0x4e790c545478029d20816a7212c46adde058d63e",
|
||||
"0x4fafc9291a0112a0ee0928361c02848ff2fdf6bd",
|
||||
"0x501577cd4865d7d50664a1519a79f1c0e7069154",
|
||||
"0x504f1e10da987490db4f0d92931497f635e240e8",
|
||||
"0x508e1101755a4a6ae228b0e18002a816ce3418ce",
|
||||
"0x514e9ca5406f112aba902b0cba87395b914d861e",
|
||||
"0x5167052b83f36952d1a9901e0de2b2038c3dd1a3",
|
||||
"0x51dcd13361c5d921d2c4818e419011301e7be34e",
|
||||
"0x52005b77fbebf53cfd9527a388f58d0431aaaa3e",
|
||||
"0x52b34625687d6266a3b98fd5d214828f0670d7ed",
|
||||
"0x52b7c8857be3853fa68e09d9ba7a9adf075040ea",
|
||||
"0x545f5e5c54d8ac72af1c7de8c070387b73841a24",
|
||||
"0x55456cbd1f11298b80a53c896f4b1dc9bc16c731",
|
||||
"0x55c4dfc965b911afee18a7d2d94a245b867395b6",
|
||||
"0x560644f0980300b31dcde7b5f78d0d53e375371f",
|
||||
"0x560833296ef7a7f41b30c1065225fa9b33830c19",
|
||||
"0x56f0e244ea07e894170731285daf8cf4864e368e",
|
||||
"0x570ac27d1048dcba1a4c58fe80109b9cf9b0e2ef",
|
||||
"0x57b818a1070373e21fcedf48d4368e1703c75852",
|
||||
"0x57d02550f47dd932d2fb84e0aa883c9d8d53c313",
|
||||
"0x57d4e4ea0a207074d7e45fe60c939d2f4d3ed06b",
|
||||
"0x57dcf20135b0cb9d167e8ebfe13b84bfd67645ed",
|
||||
"0x581cc257051a34972641d008c3915a75771be274",
|
||||
"0x58a166f9a6ff996e2349eea90d42cc198529a037",
|
||||
"0x5b67a30108e1a5f3d5a809d57e76cd16fdfde7a7",
|
||||
"0x5b6d3d66e18dfd31ed9a753c406963c401f356c0",
|
||||
"0x5ba53eb789c7f017fe3cd8027fb01c5eeb81f697",
|
||||
"0x5bc989f38ec9b913b0fbd8b702858214d428a1bd",
|
||||
"0x5d1bcbde56db05bead0ff7c87c9dc85baf98ab32",
|
||||
"0x5d3f32f4b2e99fb79d2f6a1cbf3aa7390f8fc751",
|
||||
"0x5d82db63cf0c54d47006d416bdc7dab09ea2f3f1",
|
||||
"0x5d840db230c397acc22ab28053d1a1ff7f14583e",
|
||||
"0x5ddd20ac4bacff3f148af4c8c24194a1c102cfe5",
|
||||
"0x5e0f56a3e977318b69303c12369b2a797dfa2b0b",
|
||||
"0x5e5d6f6706420f932d796c0f28a83b26dabcfd8d",
|
||||
"0x5e6dcab4f8edbfc1537b804803d831e5f42d8f3b",
|
||||
"0x5efb7d2ab258b18c8166b0c74fc4117716e52515",
|
||||
"0x5f58fe612db5b3e97faf4a2e8f38b4ae295288aa",
|
||||
"0x5f6ab160206bc6a5d663ca5d0f237d82c572272b",
|
||||
"0x602026bd56bf9ca9d86926669e4353035aca2a88",
|
||||
"0x6122ee683dbee50fd432fe5bdd8ac055aa3d42b1",
|
||||
"0x619f18aec5f8eef483fbfe654a269f1186dda915",
|
||||
"0x62404bfb3e1c464f17e3af0c139e39d0703ae4a1",
|
||||
"0x629b2aa7fdda8f7527d6f8ea742c1d5774e567ea",
|
||||
"0x62e8aaffb7568cec94b0e15e7b4d859302d65ee9",
|
||||
"0x62ee4a3c690c9660762c52bf1a232365c86c879b",
|
||||
"0x636e5292882e2342aaf82d651322aea09a3e5392",
|
||||
"0x63cfa80bbbee233a4257857dcdc9d78cbc8efe37",
|
||||
"0x64c5971dd27ff063ee4bc5e4c231febd9fc228cd",
|
||||
"0x64f3502c4b6b7e7f106e7ab1f175a4e2c2fde45f",
|
||||
"0x6506827d91659e871fc7267160ba1c3407195270",
|
||||
"0x65af8c81291fb60a20235d9e4de80851f8f845d2",
|
||||
"0x660d30d1fbafdc88a1951370cbe2b3094dbf224b",
|
||||
"0x6642cec9d02e4e669103a3ed4f3505f437b8fe73",
|
||||
"0x6678bb2a94097f5046ff179a9dcec5be0985745b",
|
||||
"0x66817272d39da7fd4c552f430fc0b694e357c157",
|
||||
"0x66e88b42922916d01b9aec71dd334d7fa5fb526d",
|
||||
"0x6721b09f4fb6fe69a14add6d1f2c1b94562e7801",
|
||||
"0x6834d3096793d0731348f1581ae1b20c9b79e26a",
|
||||
"0x685445fe51b31790538890a6468851afbf7a0519",
|
||||
"0x68a91eba9c82b475091077e16357bb2dded479f4",
|
||||
"0x68b0e0db7918c0211ea1fb78292a879839137dd0",
|
||||
"0x68d41d0c11bf5536d6d8c186ccfaf3de1a022d67",
|
||||
"0x693d47204555361d4d51311f97102a1507559802",
|
||||
"0x6973c24fadd0bcab33ee5cb325c8a70e81c67c20",
|
||||
"0x6a14e385fff2f21abe425a07ce29842b7037a80d",
|
||||
"0x6a164122d5cf7c840d26e829b46dcc4ed6c0ae48",
|
||||
"0x6af114154a8850b1c54d48bd9103bdcdb420611b",
|
||||
"0x6b5c35d525d2d94c68ab5c5af9729092fc8771dd",
|
||||
"0x6cf481c7090d88ca6f1fa3c9ffd0911ef5359808",
|
||||
"0x6d0b90ea2951ca5ad3abdb606e4146e9765f1ee4",
|
||||
"0x6d64486a5c99139b53239297e0b653d196d05777",
|
||||
"0x6d8a1bc0ae09ae5cfd4a7a2a59194598734ceea5",
|
||||
"0x6ddfef85ecf643628254e5af7064e05b3c6b221e",
|
||||
"0x6e3e57e536aab05950774945d9cdbf506865c52f",
|
||||
"0x6fcf42fcd9c6a54b64d1b52083700142952a2805",
|
||||
"0x702d965332e3082dc976c3b4013cfe0e2c540bcb",
|
||||
"0x703f0116bf2ef4c80efac751a319f097fd2dfe6c",
|
||||
"0x7098c7113c2ecaf48baad07e598c74c2689a5795",
|
||||
"0x71108be9c232722dd6839a6fbad171cf44d3ffaf",
|
||||
"0x717d2041c516573a0e27f552cdb6c5c3ec7b4e09",
|
||||
"0x71b7767a9464ea1ad82db434f06d9330d34a9fe5",
|
||||
"0x72a66bba491f0c696c4c4e3154d07b241d371944",
|
||||
"0x72b59c7ff61130f4923e2da6af27d562dd64191c",
|
||||
"0x738a4daae8d4a640172fac4f45b41707bd2197be",
|
||||
"0x73bb594368ddb778972c6f30b41437c897419c37",
|
||||
"0x74104e8c7f546c7398d198f6678310ce9d1b8814",
|
||||
"0x75dbe6e21e38a05a82ad64281a9e28a627619273",
|
||||
"0x7613a475b7fe61775f579bc148300c8171eccae9",
|
||||
"0x76c88cd1ec2442c4f929b0f87280be006d7ba725",
|
||||
"0x774148e22f021972bfe082e1548e5d9dc6e1d76e",
|
||||
"0x7822b7b190604eaeb4dcaabd2dd5e1daafcb9d46",
|
||||
"0x784205acd9423a2044d09e41642a71e087162861",
|
||||
"0x785a751b2e36b2b0fdb80100b7ca14889a768a22",
|
||||
"0x788431a9fed9fae11871353cd6e92f3b724e7d63",
|
||||
"0x79a9e902cfbe87fa5065905293992c15de7f6095",
|
||||
"0x7a18cfc4a36e48163034e51a9ed19d4bdea05f6f",
|
||||
"0x7b3a132ad35b6138f2dd148bfac2e790e4869723",
|
||||
"0x7ba85e2e55c7598378fe927ad2aef2dac6c45218",
|
||||
"0x7bb386c33486fe345168d0af94bef03897e16022",
|
||||
"0x7c203685291149d5dad4308781f42a6b945df4e1",
|
||||
"0x7c57981af4cee87567774b53f9da1bfceb8b944b",
|
||||
"0x7cbc4e0d168744912c5afc081499145bbdc51e69",
|
||||
"0x7da6955457b72fdd0e80709d704520ff85d79e39",
|
||||
"0x7dc66f5b59b34df403b96fec7e749703c157ebf8",
|
||||
"0x7dcfd020ad161fbd4c45894ab352582018ea9197",
|
||||
"0x7e160f5cf87e44cbe6b1337bb883f453445391de",
|
||||
"0x7e3d7d8e31b3f472fcd3c1552a9f009131c50c6c",
|
||||
"0x7eb28833082eb28fd423ab30df20afde98c47dbf",
|
||||
"0x7f2b4801c338a7b3cc322bfaf151afea8708e8e0",
|
||||
"0x7f85a82a2da50540412f6e526f1d00a0690a77b8",
|
||||
"0x7f85d875eaf39525004e8ac2bc1e83786d7dfd77",
|
||||
"0x7fbf068316c5806a62d549441ae82b00fdb10de1",
|
||||
"0x801d03f4d053242afbc2949c141bab4270ca6707",
|
||||
"0x8202b590eca4662446102b3a97e3536aac8ab941",
|
||||
"0x82334551e71b48387a122ebb256b188bf5868f44",
|
||||
"0x8369f6723c4792b41d4af4190662269431ee5b0b",
|
||||
"0x8374aa52bf36eabca06e33c4163a081f53e39aa3",
|
||||
"0x8444173280e5fdc0525494638123b014cffcc521",
|
||||
"0x854b62b692ac8411c3a45463c44cbdabac2d6913",
|
||||
"0x85704b506e10b10d714ead28cde947baa58f0ea4",
|
||||
"0x858457daa7e087ad74cdeeceab8419079bc2ca03",
|
||||
"0x8645ec394f7af95316639dce6f99c01476b0d888",
|
||||
"0x8651e8e218597e781e9a6d8ceb53ec5a236ae75b",
|
||||
"0x8676f2dfd06ec780ea3f8fba65a29110a56dd830",
|
||||
"0x86d38dbde80fe6a947565967f41cf958cc271548",
|
||||
"0x86ddf5b305b9081fb5208e903edeb013510997cd",
|
||||
"0x86e00684ea92cb87f40d74c5ebde97ef9a17753e",
|
||||
"0x878cce43a3b9d8a872a33d2d6ccd561e033707f4",
|
||||
"0x88436c2a2f427f2aa641dfd8c6763facf2bad7bf",
|
||||
"0x88698a2ff09506596a88a1af9d103a420ba46a3e",
|
||||
"0x893676c4a94f6ecdc33a18438bbdcfe9e6c68a9a",
|
||||
"0x897757cba67eadb66d40e45c6748e27d0e67b52a",
|
||||
"0x89c98cc6d9917b615257e5704e83906402f0f91f",
|
||||
"0x89e5124b5162a0ceec512e8ba97cd5e6f065fd13",
|
||||
"0x8a46aa04725b2e2029bdcb924d671fd6a9c11dab",
|
||||
"0x8a6fcf189437928a6a07f6899b675d11f3d3f778",
|
||||
"0x8abe0a9b8a1c8a003354e61f3ed8befdeb7d2cec",
|
||||
"0x8b3b831d767fad1ab0ad52a38777acb98630f8a7",
|
||||
"0x8c38a4e5104a2925d9e23d5f269afd1c2e09b8f9",
|
||||
"0x8c9d299cc3c2111499416cf4e3677328486cfac2",
|
||||
"0x8cf893f11f6037b14f0f827b9ed6aeef38931fb4",
|
||||
"0x8dc2c980d25b586c5c110ec3c477e985b9acad8b",
|
||||
"0x8dcdb7fc9f541825ba57fb47d5204317fc609590",
|
||||
"0x8e6be4cc78557cf3087b15963bf7139b0154e0e0",
|
||||
"0x8ee2ba41ef59b5773e5909451e0b8bad4e59a81b",
|
||||
"0x8f0bca6b1b2b522082d46f3eec31340f113b029a",
|
||||
"0x902d0d5bb6a34307bbd1da33e61ae1654b6cbe1e",
|
||||
"0x905475cbca398e8fee6e35bcb2f530a3474b78ce",
|
||||
"0x90a16ebcf1bc0da0347134f707da93c40bb8a4c5",
|
||||
"0x915c95415d3449212fd0991ccf5eb42864118ec9",
|
||||
"0x91619a3456fdbac90bd93f51f2917981f0ed3097",
|
||||
"0x91ef0754d270e67f2ca92595f5a1c0459ec7df89",
|
||||
"0x920adc9a060cda345fdec2fdebad6ebf38edf83d",
|
||||
"0x9327cb34984c3992ec1ea0eae98ccf80a74f95b9",
|
||||
"0x93574d7c405717d80520944ee1cb72d327b01df5",
|
||||
"0x93aebe50a59dfd4c1f7ed56f5177c6ced54a33af",
|
||||
"0x93d8d5bb1f1e4822f3c614d9a09e7c5e3fabc13a",
|
||||
"0x943db403251105195f56ce69c7c48a6320475ab1",
|
||||
"0x9441a81fb67f44ce7b31c311317e136e7067f8ca",
|
||||
"0x944a3f5641d6faf7a6abde4ec31e40d0929955ed",
|
||||
"0x94763846b1fcb75fccfcb51a9636ddc26af281b1",
|
||||
"0x94b40ecc7b38f5a9316b03dac4fc663e4d10cd15",
|
||||
"0x94d55b6f8b53903026399ab45294140eafbfbf44",
|
||||
"0x9546748f47a77408dfbff0dc22505b2e9a75fda4",
|
||||
"0x955427a36b5c92edee90a1448bfc7e854e9caef5",
|
||||
"0x956729a9e9b2ff42a30c8bd8fbe380b2c714825b",
|
||||
"0x983bda798a24720bb4fe3dba287ec352e7b440fc",
|
||||
"0x99f93d05059f074e893ab369f71adb4569a3da12",
|
||||
"0x9a95f2ca24d1dcb01048e0623f63f9d174237deb",
|
||||
"0x9aa722c9b6e63325797e1b2f8ff6873e44dd17c1",
|
||||
"0x9b521529d04329c2b0a9f9b7db18ed775c6ca8fc",
|
||||
"0x9beb086842a6c61ad929995f7060e3ee2c4a94ce",
|
||||
"0x9cdfc5b0aca4527a0916412e9dbd6ad85556a494",
|
||||
"0x9d0b8447f16d6bc1de2b52d63e9c487bd778a91d",
|
||||
"0x9e009c57b36ac7e3382697b4c9d3e7092a1cdb42",
|
||||
"0x9eb041af96d44583110565abec79aedf22eb60b5",
|
||||
"0xa05554fa940043c7ba191b16cbbe404c3f898f48",
|
||||
"0xa0d67bf1ae91b6b705abd4f695cc13edaacd0d02",
|
||||
"0xa0db4acb24e92167341320fcd882bbfb641cd12d",
|
||||
"0xa153a6ef80fb5d60de18688bdc82684d48fc8de1",
|
||||
"0xa1b70dc70fb74767cd380985cf93c4fb132fc4f7",
|
||||
"0xa2896b45f8bd313b777f1027724da1b5f2205a58",
|
||||
"0xa2a3a8e4a1877da1c913df7591ac0d72f27d4510",
|
||||
"0xa2a6ceadcb7db611f618ebabfe6de5763953b7c7",
|
||||
"0xa35e3534917e471540345733b8f23e7bad54681b",
|
||||
"0xa3e52a23060ccdfe186822b52bf60a07451e094e",
|
||||
"0xa46311dc4d3bc52b66d45e74682042bb143a9aa3",
|
||||
"0xa490730ce2a97ec9f81f08fdb0eede36d6319bbd",
|
||||
"0xa4fcbc4a0508b11d5ef34d41d72020a5def1c712",
|
||||
"0xa5797ea738abf85db7b3f2e04a4a40a5180044a8",
|
||||
"0xa5b254aea2e59ab3ce3bec470fe1882403c41be0",
|
||||
"0xa62b5f23f4b3ddc20f879c3ff58d4b1ef2952d97",
|
||||
"0xa6b60dd3be491aafe5aba8622b35c0ead608d3fd",
|
||||
"0xa6ba0996684fcff6167128a13c8b0a1648310e6e",
|
||||
"0xa7a020ae798a0a026c57ed6cbe48b21d3dbbec5b",
|
||||
"0xa7ce02b8195fe8e3116a7e1248f2725eaac86fec",
|
||||
"0xa82c7c0ef05080463e4ac55db8b8531007f3a66c",
|
||||
"0xa8454096f4a18e0252b411f670b3dd9d21465e75",
|
||||
"0xa8eb559eeb38c6cb6a8bc6c39badd86b113cd875",
|
||||
"0xaa1886de3f70a3ef502ea1379a311c5b4e05f3fd",
|
||||
"0xaa2498d85ba7559006f90110a4bc33c10a06c1af",
|
||||
"0xab1c30cd2d9964b3b845ef744e2e4043739430e5",
|
||||
"0xab215957873deadd9512fbde29e6c12bea1dd1a1",
|
||||
"0xabc490af011c8e354b7d2112648883fe9e511695",
|
||||
"0xac1a4f4d49715e31f54cb8e0bf867bb9170c10cb",
|
||||
"0xac3800002e45ed2e1a55dedfa2aca137f6dba61e",
|
||||
"0xac513396ee50091972ee6fc07d120b6ad360b233",
|
||||
"0xac82537fae701b2046f62bb718c4857787b0b647",
|
||||
"0xac9093198de62e5289163e85bacb53ead596b9f3",
|
||||
"0xaca33c43bd8deac8e1d144baa51fe9c7dd7b010f",
|
||||
"0xad0c88f3313abbce2185597e87a15f764e948a46",
|
||||
"0xadf5b0c2103598fb66a61714152f1d1717d49fe0",
|
||||
"0xaf313b5cf52d7a2ad7785d008660ab68421db2d1",
|
||||
"0xaf31bf4fa017768e6426308cf17e16d633700265",
|
||||
"0xaf70168cdac454fa9ff94e5458d450ae7eeb7ae8",
|
||||
"0xaff9e40f9b245b15a1d1bb45516ca213e682fa81",
|
||||
"0xb0dba64e6a353a74cc78e8a98914c4dff517ba7d",
|
||||
"0xb113a2c20471ff1efdf2735206c630707263f41c",
|
||||
"0xb116d83c919d6661dc20246d312b702f0cdf297c",
|
||||
"0xb177fc9a7caaa9c50d82c5d2533750f1d72aac86",
|
||||
"0xb1f873cb2cd0c818ce8b0a7d971f062808a47425",
|
||||
"0xb2172027cb233198a3945a2c864f1ec5b7e3b3da",
|
||||
"0xb23fb6cc17026d1ce9cd543cb69a023569503e4c",
|
||||
"0xb2a3fcf38979898e695c88947e3373bf1c2e9b37",
|
||||
"0xb2ac8e363ea34201df532a01522a006fcaa389ee",
|
||||
"0xb3764761e297d6f121e79c32a65829cd1ddb4d32",
|
||||
"0xb37722e14fcfc78a56312a9a746c5474822002f2",
|
||||
"0xb37da5c9179345341fe50d37cfc961ba47c01f9a",
|
||||
"0xb4c9d8a5812a024bdb177991af256da144776033",
|
||||
"0xb5879bf4a37c6ed9d86a6f2d8aab7939b21687cd",
|
||||
"0xb65db9f684f3bfa45ad3fb4cdc4120618ad81f00",
|
||||
"0xb71df0dbbb9754c1aa9115253f4ebb7ef3f8a57c",
|
||||
"0xb76a4770587f76d6c644deec275a2c76069b5f14",
|
||||
"0xb7c4a4341c0a03460b6cec4fa997dd2d748ce281",
|
||||
"0xb82bfd79d5a8c0cc0d4c045633288b48a2beddcb",
|
||||
"0xb8689c29bdc7c84f33706ff0f96eafc222ba6d86",
|
||||
"0xb9ae74beafe4025cc0fcfb5e190169f2d7f0b563",
|
||||
"0xb9cfb36060785f6800b1ab9ccc9b4f341d097399",
|
||||
"0xba83e9ce38b10522e3d6061a12779b7526839eda",
|
||||
"0xbb53be0690ae7256833099a1f01125eb33445692",
|
||||
"0xbbdef8b12babd3ab6018566bc17ec3aa302b8348",
|
||||
"0xbbf84f9b823c42896c9723c0be4d5f5ede257b52",
|
||||
"0xbc210ec2efada9df4897dc9b23c58e96c01ef711",
|
||||
"0xbc66e774ce25000950786241b8c5ee3275311bd7",
|
||||
"0xbc83d48dd0cd9c3f47bab6436defeb334b563f4c",
|
||||
"0xbc85a12364c9e375801c00aad17b893fc4c8f5b6",
|
||||
"0xbc8b85b1515e45fb2d74333310a1d37b879732c0",
|
||||
"0xbca6294a6c80ee0f20173547b8d85d4948a0cb39",
|
||||
"0xbcc6c0fef89b87a12773db7a9a8ecbccccdb7aff",
|
||||
"0xbe11d0d38ef4857224032afc9c96647492f726ce",
|
||||
"0xbe3364dfb8158a3e452ff96aeb247bf3f5f019b5",
|
||||
"0xbeebe66b6a511dd2accbff7f258554dbe97f1294",
|
||||
"0xbf0c85867fcdd4064d22b0dfd91561a52134e035",
|
||||
"0xc0ded1d24c071ca13a905ec5e54a6ffdd0c4df68",
|
||||
"0xc0fed35b43f59c2bfb1eb544bd8921bfb18140c2",
|
||||
"0xc14777c94229582e5758c5a79b83dde876b9be98",
|
||||
"0xc169a0e826f22fc7d37a48aaa346ffb4521c35cd",
|
||||
"0xc1dd8ac971129c8c08333924f58ff40a50b8bb9a",
|
||||
"0xc28f50625cfe028ab1a3458c7cebcf9657ff1438",
|
||||
"0xc315f677f6a8f7b42d8fb32500e790cbf3dfbce8",
|
||||
"0xc31fb4c352cb68c847715d46d97c1fa2aa2d0f00",
|
||||
"0xc36454ed2b40adef7c75b9cef95b2f8010d3e0d2",
|
||||
"0xc38d14bf89e0001260bb349a006d7e491e5f43ad",
|
||||
"0xc4625787be3fccff6ac2971945806acc167c8cbd",
|
||||
"0xc4b51a247514901faf1b6b1da9f0836066e64407",
|
||||
"0xc4dca8f7d121ad79057a8382fc9fa9898727ddd8",
|
||||
"0xc57f1148855e67763a694f7f2c0e68230adc686e",
|
||||
"0xc593e92ed9fd3c2f9db972860047affd2df83ae7",
|
||||
"0xc5d65deff5d1373f8b19aa8be528e9c3599013ba",
|
||||
"0xc5f6690f7b60fe739908e02aec46ae07718cec5f",
|
||||
"0xc616d99df3bf92e3111090f94694bd662b72ab1d",
|
||||
"0xc7308d5a7220dc021ccf417445cb28cbb8fece66",
|
||||
"0xc8ac47854a3fed2b444beb83f4c95ba092a3a735",
|
||||
"0xc8c3234aea55a5f746b2ae585a849ba0bfa57785",
|
||||
"0xc8ce1c3ac9549d479a90a6a89155b9b94e54d9ba",
|
||||
"0xc915ec7f4cfd1c0a8aba090f03bfaab588aef9b4",
|
||||
"0xc94a6e7776bade5da316cf6fd8c751fb0d5c3c5e",
|
||||
"0xc9a08162b95915edf6570f0439757e1f655de576",
|
||||
"0xc9f32ce1127e44c51cbd182d6364f3d707fd0d47",
|
||||
"0xca4da1753336aa8340710e0e1a8c0bee2bfbf56c",
|
||||
"0xcae77a05ab518492144944fb50572ebfa3595870",
|
||||
"0xcb142defc16c9b409272447d87c74b722b767f1f",
|
||||
"0xcb89576d5e1627f4a0c64c2bb4d51798e92e8b8f",
|
||||
"0xcbcd4b518890429c0ffef3d782ed99b3adff009b",
|
||||
"0xcc02b920ae227f1be7d01fc241c27e5f74d40436",
|
||||
"0xcc49d1f23f01decd4e18b6aaacccb038c9648e30",
|
||||
"0xcc66ea7ef61a67df02afb18706c68a5f30b22300",
|
||||
"0xccdf72de615b5158bb37931bbce645aa69221520",
|
||||
"0xccffdb4bd0abb6fd105c1c4e03b4e919a5b57ab9",
|
||||
"0xcd63bb3586e871611cc60befcadf8e56bc7aeea3",
|
||||
"0xcda5dd8e13fdae006b270769b1a18fa6c5524ce0",
|
||||
"0xcdd1c19dcc3f473eaef6edb0a28e1e796d6e1767",
|
||||
"0xce52d38539e1e557f184f1073a59f69c9ba95f28",
|
||||
"0xce686d019e6f692af646a8df3bfe789da97a484f",
|
||||
"0xcec962222291e09a07c0bd0a110d2211e0358b28",
|
||||
"0xcee9ee01d48050415f1b104277bd493c5dbe645e",
|
||||
"0xcff5e190a3d92e480a8bc5b414362c0d1afeb54e",
|
||||
"0xd055610c2d5151adb3eaf994e08abe45dee936e0",
|
||||
"0xd06f80a4b932d7247aba4a85decce6c2458c0654",
|
||||
"0xd0ac32ab01d9d3ec145ef63f73bf4e222dbcc0fb",
|
||||
"0xd0b473271e9d38dfd11925d62ef8c0a2cf033a9c",
|
||||
"0xd0cc2b24980cbcca47ef755da88b220a82291407",
|
||||
"0xd1091f9c7bb48651edb17d255b2824de0ebd2074",
|
||||
"0xd1bdd067f5f1cbd358e2dde444f8d9f41de8ae76",
|
||||
"0xd22167d083a5cfc2f1ccadeb842a8093b2174c5f",
|
||||
"0xd2f4ea2f9d4c627c957305e28877081da9296d47",
|
||||
"0xd33441a44da0c1dcee596abb7ebdcdba77c7ddbd",
|
||||
"0xd354cf84a4cfd096120e2d4bf0a0cc8866d4efe1",
|
||||
"0xd362c189cb0056159d2fe22bd8203e26579f620d",
|
||||
"0xd3d26c61401924939bee67dffdb7aa7a0138844c",
|
||||
"0xd3d7c71e4c5b1ff2f42fbb9b4a21f3373aa8b3b0",
|
||||
"0xd43f2111e4055120196285ec094aa6e96998668b",
|
||||
"0xd50fcd07007255599a9a8cedd881f863bcd65eb1",
|
||||
"0xd5ce086a9d4987adf088889a520de98299e10bb5",
|
||||
"0xd5edb088b7382b397238f5010d14cf10dd395007",
|
||||
"0xd6f8668e96951e4108a79bc45ccef022544c73b3",
|
||||
"0xd72ebdf278c092d9cdaa12c58f8bd9438f96b83e",
|
||||
"0xd754b5bf41b84bcb49cb952f858318640abc60e0",
|
||||
"0xd77b95800f67deb52e0e0988dbf01a311a3ccd80",
|
||||
"0xd79eb898431ea62636f08f738d10eb00446403de",
|
||||
"0xd821dfb705333d2c16e0c0c0be75ce360cca566a",
|
||||
"0xd84af8766bd29b988f3426cc48cac5a6646f1f90",
|
||||
"0xd868a76a1dcc34854903376e734e3cfe461dd08c",
|
||||
"0xd912289c9f079b0655737a55fd5d745501ecefc7",
|
||||
"0xd9204db19a18e051e861576a462c0cf83a2b6237",
|
||||
"0xd92559e1f1d2e84f4964f45256693d03833d7d44",
|
||||
"0xd9932453997ddf36fe114c9f22bebb9ee77b2921",
|
||||
"0xd9cd7461f960e56364a294f124aac77b25e2b784",
|
||||
"0xd9d25dce4c3765855c76f3d2baccc0755c4d0bc5",
|
||||
"0xda1cc010259496d407a764c381d0e82182d68d89",
|
||||
"0xda657e9fa116900fab8178e5580a3a6cedd89f3c",
|
||||
"0xda917961872ae8e0c8b96f6925a4d7cc7b27aea3",
|
||||
"0xdaa29859836d97c810c7f9d350d4a1b3e8cafc9a",
|
||||
"0xdafc2a2d4e070f863cfcb5887bc2516e05e18877",
|
||||
"0xdb21509547c82b69e714bf3a761e6d64f0f91cd0",
|
||||
"0xdb82af76f9ccddfe9e8f7996492f4c5bd5f9d53d",
|
||||
"0xdbe6dba965afc52f5b3d51e4b15e372f45d4106a",
|
||||
"0xdc3fd5cce7b17e461c692ff34f22fbd4b780b151",
|
||||
"0xdcd2fb1c1b103c5a591e76798704cfaa27baf6b9",
|
||||
"0xddd6854a002a6fbcdf695385cd5ed630c9e27c3e",
|
||||
"0xddff022e4befa69cbb5262446a8ae564700bea24",
|
||||
"0xde5886e65cbf1a9d21267f5ef7d5ed444cc63938",
|
||||
"0xdef05b512d405f4fb930e252c6c11f054832c93b",
|
||||
"0xdefb014b9e2f3bd81cdb084821f99b681cfca695",
|
||||
"0xdf04e5007cb8fd65831310ceda40f5642c1b39c3",
|
||||
"0xdf1ec2e44a8b1774b068ecfc5ef1c937a86baf3e",
|
||||
"0xdf3e77cd5e563f93fc7eca905d3302e95f9bb150",
|
||||
"0xdf967ff95cd5ff35a27786dbd906fbb9ded116af",
|
||||
"0xe009321b26350c2cff5db607068c1f6813df40d7",
|
||||
"0xe02f2921742a6eec7ae44a18b1cca4277874bc74",
|
||||
"0xe051ee9bd6270ff52d85ffe09685ee3a9755f04a",
|
||||
"0xe06ae5c5ab3eda3a62918bf86532c7d87dbbc66d",
|
||||
"0xe0b13c073e8173b06062c69a160ebb54e2af86c3",
|
||||
"0xe10270bfb1ed82e120bfc392efb3c94a1604ded6",
|
||||
"0xe10c24ca7bf18640fcb35e059919348891922a3b",
|
||||
"0xe112784753273ebede055968ecb78dcad8ff6da2",
|
||||
"0xe1358ae1a9130bc458c8021fcbb7ef8aedd51487",
|
||||
"0xe1632e7e0dc135f3bc8991b917e8b682ab340fe1",
|
||||
"0xe276c66af8853cdd91c1a25608b4e8b599f4da0e",
|
||||
"0xe344e4b209e8eabaa2a6ddd1b0aa120b7599af25",
|
||||
"0xe350160e3c8a07e92ec58ddcb8df81a73aedc6f9",
|
||||
"0xe41031233301370491d47477e1171dab212d5352",
|
||||
"0xe4fa5149306b12d51dc0d04e5e95bc9704ccaad7",
|
||||
"0xe4faeef4002c200d9d4f1d381ccb5fb679d1c437",
|
||||
"0xe54659243f8542d6abfd15bbff69f62465786756",
|
||||
"0xe5b913f91f2b90c5cd04d711e1eb3214c56dba98",
|
||||
"0xe61df1f5b8dd4e4e2a874157c2c97daf7314b795",
|
||||
"0xe6b39dad6d7a50b233da23e510697422e9d6351a",
|
||||
"0xe6c51d563f92a23dee9a7093bb1be33bd35c05d8",
|
||||
"0xe6d3486a5fe2742e313a3266af8ff4f43e597d27",
|
||||
"0xe74b02131ed2184eb94fd357b4f303e6935367f5",
|
||||
"0xe7cc576611c2df800862db667140a90cf9ec4b72",
|
||||
"0xe824ec0f8384600f3187967f8b098014e31892f2",
|
||||
"0xe88379631857c0d8174efefdf8dca25b29610f08",
|
||||
"0xe977419ef28e71ed541ff6318cea9a6392709a48",
|
||||
"0xe9aa3a74e3d62274f221eca42736cadc14ccffaf",
|
||||
"0xe9ab68e4aa12bf290529626e5f32725cf5abfba8",
|
||||
"0xe9e837881c89e943c4c66e26031922bf8fc3f4f3",
|
||||
"0xe9ee84b3b818b2af67c4536248fbfc5c7a0ccfad",
|
||||
"0xea6e18fd3c301e4300bc99b6db792fcff376abb4",
|
||||
"0xea7380369af53598a55b4622909cd9633e0ae7fa",
|
||||
"0xeab1d82e96541718e645fdef4a5ee9df78605b76",
|
||||
"0xeaceb8e777dc8b1c11b8730904d13fbda070846f",
|
||||
"0xeb8b629df028f5353649460f1c06bf394de8641f",
|
||||
"0xec2d5cc008ba6d2237d33ca9cf74b684737fcae8",
|
||||
"0xec970bbf167beee6fb536f1839418f3d19ce2a69",
|
||||
"0xecb6ffac05d8b4660b99b475b359fe454c77d153",
|
||||
"0xed2d26eed06ecfbfd796d1ec551d2a649a31e576",
|
||||
"0xed44fc770eaa76db9ade24d86ce3b409f4aed009",
|
||||
"0xedf202629bb7e9f72d4c62c325d198513fa7a3d3",
|
||||
"0xee2c2c2dcd952429147b62fd4dcd7f565313e419",
|
||||
"0xeecc46a74cea6133a12672bd62d5167877b4d521",
|
||||
"0xeed48722238b98317d849fa591d96b7efbe9b06f",
|
||||
"0xeed7072fcf46733833249d1e979c44fe4f2a23a2",
|
||||
"0xeef2a09be2a136bba76f04cf056e36947dbf0b0c",
|
||||
"0xef0683bef79b7ad85573415c781edfde8bec65b1",
|
||||
"0xef57aa4b57587600fc209f345fe0a2687bc26985",
|
||||
"0xef6805af393c34fe772f8d827a5d26685215612a",
|
||||
"0xf021428381172ef96988b31f241f4000259488f7",
|
||||
"0xf0a924661b0263e5ce12756d07f45b8668c53380",
|
||||
"0xf0fc2d4d550253d8c165c599e0cccf221c7eb7b5",
|
||||
"0xf1014a29614b196d19d8ecd5ff05f3cef5efdbe2",
|
||||
"0xf193a9afb00715aacf7ca9ebffafe02c77517c2e",
|
||||
"0xf1e250f2a27ab7ec5b82b287f2799260448cd51d",
|
||||
"0xf23f9dda63ed0628609272dc0544c7a2f7189f51",
|
||||
"0xf245e09a1b42f847b120558f0c6e08f821be23f7",
|
||||
"0xf2601c5a063c6a6ca86d8b6bd0543158f83a10ce",
|
||||
"0xf2dcfa51f83e41c0e988477f939c7a5e5b9a6905",
|
||||
"0xf33068d5e798f6519349ce32669d1ec940db1193",
|
||||
"0xf394d807795ff57373f1fe903046596cb0f69acc",
|
||||
"0xf3ae45d5a0b8efb41444101267b56e6795051fac",
|
||||
"0xf4710562c804087af20b7396ce7cba38b43fb61f",
|
||||
"0xf4c87c851d772b0f9e72cca0690327f2bc505015",
|
||||
"0xf5c86c5ba5291da78a2b4119dd7aef99e3508362",
|
||||
"0xf689bb4b063683a9ffd7a9295106f1e47c095809",
|
||||
"0xf73ef0650415656b51be39bd5d37cf5ce03f4033",
|
||||
"0xf747726200c7fc14ef4ce267b1f070128c2260dd",
|
||||
"0xf855fee50a8915634a105385cb6cb9e442d15457",
|
||||
"0xf8e676094628776690dbf83fa31f08aa14fd3fb8",
|
||||
"0xf902aa3a62f9e28878129e1a8f1eb71e4fd7a88c",
|
||||
"0xf962933e44b1dfc771738a034c80d87bdcd96ecc",
|
||||
"0xf9a5139e42c3ca13d5b24d23ab2b18c278805dc4",
|
||||
"0xf9fe85e19bd533c69067c6e2ff02727d40a54100",
|
||||
"0xfa1f0b67b9b48b2e87467d72f09722e19ed601bd",
|
||||
"0xfa956f10da5e16f120eb299df963c1f7563bf66b",
|
||||
"0xfad17c9da2bebf758e3bc0c99d1abe8af7e96ed1",
|
||||
"0xfb1a7ccf5bcd436dcc0acb49ba1fb9f57bb4d064",
|
||||
"0xfb6e71e0800bccc0db8a9cf326fe3213ca1a0ea0",
|
||||
"0xfb990112f51931a2834fcf574a860b7419ecd76f",
|
||||
"0xfbc79a80ffa84253611e8f9a82f18e9e93ceee81",
|
||||
"0xfbf6f29c126382cf15795bb209ee506a174cc709",
|
||||
"0xfc74fb0d5df08ec546a3da18ccc7fbcbe031f5d8",
|
||||
"0xfcdd417b449c982fc9b6d7b117e417682e81b627",
|
||||
"0xfd477bf560e59941796b398cea662b393298abc0",
|
||||
"0xfddbfa1b0b93612b95e3296690b63b74d019370c",
|
||||
"0xfe68de56a07cd3af0ec40c22b0193115ecdd0501",
|
||||
"0xfe821f5509fdea3f72362d001697ad8c11f0c111",
|
||||
"0xfe9b7db8d9d57e9ad9341bcf51b110ba5d27b48b",
|
||||
"0xff35866acb80ce4b169d1460cd48108955c1c445",
|
||||
// Fake Uniswap phishing
|
||||
"0x0000000000000000000000000000000000000001",
|
||||
// Common address poisoning targets
|
||||
"0x0000000000000000000000000000000000000000",
|
||||
// Known drainer contracts (examples — expand as needed)
|
||||
"0x00000000a991c429ee2ec6df19d40fe0c80088b8",
|
||||
"0xae0ee0a63a2ce6baeeffe56e7714fb4efe48d419",
|
||||
"0x3ee18b2214aff97000d974cf647e7c347e8fa585",
|
||||
"0x55fe002aeff02f77364de339a1292923a15844b8",
|
||||
"0x7f268357a8c2552623316e2562d90e642bb538e5",
|
||||
]);
|
||||
|
||||
function isScamAddress(address) {
|
||||
|
||||
@@ -23,8 +23,10 @@ const DEFAULT_STATE = {
|
||||
hideFraudContracts: true,
|
||||
hideDustTransactions: true,
|
||||
dustThresholdGwei: 100000,
|
||||
utcTimestamps: false,
|
||||
fraudContracts: [],
|
||||
tokenHolderCache: {},
|
||||
theme: "system",
|
||||
};
|
||||
|
||||
const state = {
|
||||
@@ -53,8 +55,10 @@ async function saveState() {
|
||||
hideFraudContracts: state.hideFraudContracts,
|
||||
hideDustTransactions: state.hideDustTransactions,
|
||||
dustThresholdGwei: state.dustThresholdGwei,
|
||||
utcTimestamps: state.utcTimestamps,
|
||||
fraudContracts: state.fraudContracts,
|
||||
tokenHolderCache: state.tokenHolderCache,
|
||||
theme: state.theme,
|
||||
currentView: state.currentView,
|
||||
selectedWallet: state.selectedWallet,
|
||||
selectedAddress: state.selectedAddress,
|
||||
@@ -108,8 +112,11 @@ async function loadState() {
|
||||
saved.dustThresholdGwei !== undefined
|
||||
? saved.dustThresholdGwei
|
||||
: 100000;
|
||||
state.utcTimestamps =
|
||||
saved.utcTimestamps !== undefined ? saved.utcTimestamps : false;
|
||||
state.fraudContracts = saved.fraudContracts || [];
|
||||
state.tokenHolderCache = saved.tokenHolderCache || {};
|
||||
state.theme = saved.theme || "system";
|
||||
state.currentView = saved.currentView || null;
|
||||
state.selectedWallet =
|
||||
saved.selectedWallet !== undefined ? saved.selectedWallet : null;
|
||||
|
||||
@@ -153,24 +153,38 @@ async function fetchRecentTransactions(address, blockscoutUrl, count = 25) {
|
||||
|
||||
// When a token transfer shares a hash with a normal tx, the normal tx
|
||||
// is the contract call (0 ETH) and the token transfer has the real
|
||||
// amount and symbol. A single transaction (e.g. a swap) can produce
|
||||
// multiple token transfers (one per token involved), so we key token
|
||||
// transfers by hash + contract address to keep all of them. We also
|
||||
// preserve contract-call metadata (direction, label, method) from the
|
||||
// matching normal tx so swaps display correctly.
|
||||
// amount and symbol. For contract calls (swaps), a single transaction
|
||||
// can produce multiple token transfers (input, intermediates, output).
|
||||
// We consolidate these into the original tx entry using the token
|
||||
// transfer where the user *receives* tokens (the swap output), so
|
||||
// the transaction list shows the final result rather than confusing
|
||||
// intermediate hops. We preserve the original tx's from/to so the
|
||||
// user sees their own address, not a router or Permit2 contract.
|
||||
for (const tt of ttJson.items || []) {
|
||||
const parsed = parseTokenTransfer(tt, addrLower);
|
||||
const existing = txsByHash.get(parsed.hash);
|
||||
if (existing && existing.direction === "contract") {
|
||||
parsed.direction = "contract";
|
||||
parsed.directionLabel = existing.directionLabel;
|
||||
parsed.isContractCall = true;
|
||||
parsed.method = existing.method;
|
||||
// Remove the bare-hash normal tx so it doesn't appear as a
|
||||
// duplicate with empty value; token transfers replace it.
|
||||
txsByHash.delete(parsed.hash);
|
||||
// For contract calls (swaps), consolidate into the original
|
||||
// tx entry. Prefer the "received" transfer (swap output)
|
||||
// for the display amount. If no received transfer exists,
|
||||
// fall back to the first "sent" transfer (swap input).
|
||||
const isReceived = parsed.direction === "received";
|
||||
const needsAmount = !existing.exactValue;
|
||||
if (isReceived || needsAmount) {
|
||||
existing.value = parsed.value;
|
||||
existing.exactValue = parsed.exactValue;
|
||||
existing.rawAmount = parsed.rawAmount;
|
||||
existing.rawUnit = parsed.rawUnit;
|
||||
existing.symbol = parsed.symbol;
|
||||
existing.contractAddress = parsed.contractAddress;
|
||||
existing.holders = parsed.holders;
|
||||
}
|
||||
// Keep the original tx's from/to (the user's address and the
|
||||
// contract they called), not the token transfer's from/to
|
||||
// which may be a router or Permit2 contract.
|
||||
continue;
|
||||
}
|
||||
// Use composite key so multiple token transfers per tx are kept.
|
||||
// Non-contract token transfers get their own entries.
|
||||
const ttKey = parsed.hash + ":" + (parsed.contractAddress || "");
|
||||
txsByHash.set(ttKey, parsed);
|
||||
}
|
||||
|
||||
@@ -359,9 +359,12 @@ function decode(data, toAddress) {
|
||||
const s = decodeV3SwapExactIn(inputs[i]);
|
||||
if (s) {
|
||||
if (!inputToken) inputToken = s.tokenIn;
|
||||
if (!outputToken) outputToken = s.tokenOut;
|
||||
if (!inputAmount) inputAmount = s.amountIn;
|
||||
if (!minOutput) minOutput = s.amountOutMin;
|
||||
// Always update output: in multi-step swaps (V3 → V4),
|
||||
// the last swap step determines the final output token
|
||||
// and minimum received amount.
|
||||
outputToken = s.tokenOut;
|
||||
minOutput = s.amountOutMin;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -369,9 +372,9 @@ function decode(data, toAddress) {
|
||||
const s = decodeV2SwapExactIn(inputs[i]);
|
||||
if (s) {
|
||||
if (!inputToken) inputToken = s.tokenIn;
|
||||
if (!outputToken) outputToken = s.tokenOut;
|
||||
if (!inputAmount) inputAmount = s.amountIn;
|
||||
if (!minOutput) minOutput = s.amountOutMin;
|
||||
outputToken = s.tokenOut;
|
||||
minOutput = s.amountOutMin;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -388,12 +391,11 @@ function decode(data, toAddress) {
|
||||
const v4 = decodeV4Swap(inputs[i]);
|
||||
if (v4) {
|
||||
if (!inputToken && v4.tokenIn) inputToken = v4.tokenIn;
|
||||
if (!outputToken && v4.tokenOut)
|
||||
outputToken = v4.tokenOut;
|
||||
if (!inputAmount && v4.amountIn)
|
||||
inputAmount = v4.amountIn;
|
||||
if (!minOutput && v4.amountOutMin)
|
||||
minOutput = v4.amountOutMin;
|
||||
// Always update output: last swap step wins
|
||||
if (v4.tokenOut) outputToken = v4.tokenOut;
|
||||
if (v4.amountOutMin) minOutput = v4.amountOutMin;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user