Some checks failed
check / check (push) Has been cancelled
The Allow/Deny buttons did nothing because approval.init(ctx) was called after the early return for approval mode, so listeners were never attached. Move it before the check. Rename view from "approve" to "approve-site" to avoid ambiguity with future transaction approval. Space Allow and Deny buttons apart with justify-between to prevent misclicks.
640 lines
27 KiB
HTML
640 lines
27 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<title>AutistMask</title>
|
|
<link rel="stylesheet" href="styles.css" />
|
|
</head>
|
|
<body class="bg-bg text-fg font-mono text-sm">
|
|
<div id="app" class="p-2 pr-5 overflow-x-hidden">
|
|
<!-- ============ GLOBAL TITLE BAR ============ -->
|
|
<div
|
|
class="flex justify-between items-center border-b border-border pb-1 mb-2"
|
|
>
|
|
<h1>
|
|
<span class="font-bold">AutistMask</span> by
|
|
<a
|
|
href="https://sneak.berlin"
|
|
target="_blank"
|
|
class="underline decoration-dashed"
|
|
>@sneak</a
|
|
>
|
|
</h1>
|
|
<button
|
|
id="btn-settings"
|
|
class="bg-transparent border-none text-fg cursor-pointer text-2xl p-0 leading-none"
|
|
title="Settings"
|
|
>
|
|
⚙
|
|
</button>
|
|
</div>
|
|
|
|
<!-- ============ FLASH MESSAGE AREA ============ -->
|
|
<div
|
|
id="flash-msg"
|
|
class="text-xs text-muted min-h-[1.25rem] mb-1"
|
|
></div>
|
|
|
|
<!-- ============ WELCOME / FIRST USE ============ -->
|
|
<div id="view-welcome" class="view hidden">
|
|
<p class="mb-3">Welcome! To get started, add a wallet.</p>
|
|
<button
|
|
id="btn-welcome-add"
|
|
class="border border-border px-2 py-1 hover:bg-fg hover:text-bg cursor-pointer"
|
|
>
|
|
Add wallet
|
|
</button>
|
|
</div>
|
|
|
|
<!-- ============ ADD WALLET (unified create/import) ============ -->
|
|
<div id="view-add-wallet" class="view hidden">
|
|
<button
|
|
id="btn-add-wallet-back"
|
|
class="border border-border px-2 py-1 hover:bg-fg hover:text-bg cursor-pointer mb-2"
|
|
>
|
|
< Back
|
|
</button>
|
|
<h2 class="font-bold mb-2">Add Wallet</h2>
|
|
<p class="mb-2">
|
|
Enter your 12 or 24 word recovery phrase below, or click the
|
|
button to roll the die for a new one.
|
|
</p>
|
|
<div class="mb-1 flex justify-end">
|
|
<button
|
|
id="btn-generate-phrase"
|
|
class="border border-border px-2 py-1 hover:bg-fg hover:text-bg cursor-pointer text-xs"
|
|
title="Generate a random recovery phrase"
|
|
>
|
|
[⚀]
|
|
</button>
|
|
</div>
|
|
<div class="mb-2">
|
|
<textarea
|
|
id="wallet-mnemonic"
|
|
rows="3"
|
|
class="border border-border p-1 w-full font-mono text-sm bg-bg text-fg resize-y"
|
|
placeholder="word word word ..."
|
|
></textarea>
|
|
</div>
|
|
<div
|
|
id="add-wallet-phrase-warning"
|
|
class="text-xs mb-2 border border-border border-dashed p-2 hidden"
|
|
>
|
|
Write these words down and keep them safe. Anyone with them
|
|
can take your funds; if you lose them, your wallet is gone.
|
|
</div>
|
|
<div class="mb-2" id="add-wallet-password-section">
|
|
<label class="block mb-1">Choose a password</label>
|
|
<p class="text-xs text-muted mb-1">
|
|
This password encrypts your recovery phrase on this
|
|
device. You will need it to send funds.
|
|
</p>
|
|
<input
|
|
type="password"
|
|
id="add-wallet-password"
|
|
class="border border-border p-1 w-full font-mono text-sm bg-bg text-fg"
|
|
/>
|
|
</div>
|
|
<div class="mb-2" id="add-wallet-password-confirm-section">
|
|
<label class="block mb-1">Confirm password</label>
|
|
<input
|
|
type="password"
|
|
id="add-wallet-password-confirm"
|
|
class="border border-border p-1 w-full font-mono text-sm bg-bg text-fg"
|
|
/>
|
|
</div>
|
|
<button
|
|
id="btn-add-wallet-confirm"
|
|
class="border border-border px-2 py-1 hover:bg-fg hover:text-bg cursor-pointer"
|
|
>
|
|
Add
|
|
</button>
|
|
<div class="mt-3 text-xs text-muted">
|
|
Have a private key instead?
|
|
<button
|
|
id="btn-add-wallet-import-key"
|
|
class="underline cursor-pointer bg-transparent border-none text-fg text-xs font-mono p-0"
|
|
>
|
|
Import private key
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ============ IMPORT PRIVATE KEY ============ -->
|
|
<div id="view-import-key" class="view hidden">
|
|
<button
|
|
id="btn-import-key-back"
|
|
class="border border-border px-2 py-1 hover:bg-fg hover:text-bg cursor-pointer mb-2"
|
|
>
|
|
< Back
|
|
</button>
|
|
<h2 class="font-bold mb-2">Import Private Key</h2>
|
|
<p class="mb-2">
|
|
Paste your private key below. This wallet will have a single
|
|
address.
|
|
</p>
|
|
<div class="mb-2">
|
|
<input
|
|
type="password"
|
|
id="import-private-key"
|
|
class="border border-border p-1 w-full font-mono text-sm bg-bg text-fg"
|
|
placeholder="0x..."
|
|
/>
|
|
</div>
|
|
<div class="mb-2" id="import-key-password-section">
|
|
<label class="block mb-1">Choose a password</label>
|
|
<p class="text-xs text-muted mb-1">
|
|
This password encrypts your private key on this device.
|
|
You will need it to send funds.
|
|
</p>
|
|
<input
|
|
type="password"
|
|
id="import-key-password"
|
|
class="border border-border p-1 w-full font-mono text-sm bg-bg text-fg"
|
|
/>
|
|
</div>
|
|
<div class="mb-2" id="import-key-password-confirm-section">
|
|
<label class="block mb-1">Confirm password</label>
|
|
<input
|
|
type="password"
|
|
id="import-key-password-confirm"
|
|
class="border border-border p-1 w-full font-mono text-sm bg-bg text-fg"
|
|
/>
|
|
</div>
|
|
<button
|
|
id="btn-import-key-confirm"
|
|
class="border border-border px-2 py-1 hover:bg-fg hover:text-bg cursor-pointer"
|
|
>
|
|
Import
|
|
</button>
|
|
</div>
|
|
|
|
<!-- ============ MAIN VIEW: ALL WALLETS & ADDRESSES ============ -->
|
|
<div id="view-main" class="view hidden">
|
|
<!-- total portfolio value -->
|
|
<div
|
|
id="total-value"
|
|
class="text-2xl font-bold mb-2 min-h-[2rem]"
|
|
></div>
|
|
|
|
<!-- quick actions for active address -->
|
|
<div class="flex gap-2 mb-3">
|
|
<button
|
|
id="btn-main-send"
|
|
class="border border-border px-2 py-1 hover:bg-fg hover:text-bg cursor-pointer flex-1"
|
|
>
|
|
Send
|
|
</button>
|
|
<button
|
|
id="btn-main-receive"
|
|
class="border border-border px-2 py-1 hover:bg-fg hover:text-bg cursor-pointer flex-1"
|
|
>
|
|
Receive
|
|
</button>
|
|
</div>
|
|
|
|
<!-- wallet list -->
|
|
<div id="wallet-list"></div>
|
|
</div>
|
|
|
|
<!-- ============ ADDRESS DETAIL VIEW ============ -->
|
|
<div id="view-address" class="view hidden">
|
|
<button
|
|
id="btn-address-back"
|
|
class="border border-border px-2 py-1 hover:bg-fg hover:text-bg cursor-pointer mb-2"
|
|
>
|
|
< Back
|
|
</button>
|
|
<div
|
|
class="flex justify-between items-center border-b border-border pb-1 mb-2"
|
|
>
|
|
<h2 class="font-bold" id="address-title">Address</h2>
|
|
</div>
|
|
|
|
<div
|
|
id="address-ens"
|
|
class="font-bold mb-1 hidden flex items-center"
|
|
></div>
|
|
<div
|
|
class="flex text-xs mb-3 cursor-pointer items-center"
|
|
title="Click to copy"
|
|
>
|
|
<span id="address-dot"></span>
|
|
<span
|
|
id="address-full"
|
|
style="width: 40ch; max-width: 100%"
|
|
></span>
|
|
<span
|
|
id="address-usd-total"
|
|
class="text-right text-muted flex-1"
|
|
></span>
|
|
</div>
|
|
<!-- balances -->
|
|
<div class="border-b border-border-light pb-2 mb-2">
|
|
<div id="address-balances"></div>
|
|
</div>
|
|
|
|
<!-- actions -->
|
|
<div class="flex gap-2 mb-3">
|
|
<button
|
|
id="btn-send"
|
|
class="border border-border px-2 py-1 hover:bg-fg hover:text-bg cursor-pointer flex-1"
|
|
>
|
|
Send
|
|
</button>
|
|
<button
|
|
id="btn-receive"
|
|
class="border border-border px-2 py-1 hover:bg-fg hover:text-bg cursor-pointer flex-1"
|
|
>
|
|
Receive
|
|
</button>
|
|
<button
|
|
id="btn-add-token"
|
|
class="border border-border px-2 py-1 hover:bg-fg hover:text-bg cursor-pointer flex-1"
|
|
>
|
|
+ Token
|
|
</button>
|
|
</div>
|
|
|
|
<!-- transactions -->
|
|
<div class="mt-3">
|
|
<div class="border-b border-border pb-1 mb-1">
|
|
<h2 class="font-bold">Transactions</h2>
|
|
</div>
|
|
<div id="tx-list" class="overflow-hidden">
|
|
<div class="text-muted text-xs py-1">Loading...</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ============ SEND ============ -->
|
|
<div id="view-send" class="view hidden">
|
|
<button
|
|
id="btn-send-back"
|
|
class="border border-border px-2 py-1 hover:bg-fg hover:text-bg cursor-pointer mb-2"
|
|
>
|
|
< Back
|
|
</button>
|
|
<h2 class="font-bold mb-2">Send</h2>
|
|
<div class="mb-2">
|
|
<label class="block mb-1 text-xs text-muted">From</label>
|
|
<div id="send-from" class="text-xs mb-1"></div>
|
|
</div>
|
|
<div class="mb-2">
|
|
<label class="block mb-1">What to send</label>
|
|
<select
|
|
id="send-token"
|
|
class="border border-border p-1 w-full font-mono text-sm bg-bg text-fg"
|
|
>
|
|
<option value="ETH">ETH</option>
|
|
</select>
|
|
</div>
|
|
<div class="mb-2">
|
|
<label class="block mb-1">To</label>
|
|
<input
|
|
type="text"
|
|
id="send-to"
|
|
class="border border-border p-1 w-full font-mono text-sm bg-bg text-fg"
|
|
placeholder="Address (0x...) or ENS name"
|
|
/>
|
|
</div>
|
|
<div class="mb-2">
|
|
<div class="flex justify-between mb-1">
|
|
<label>Amount</label>
|
|
<span
|
|
id="send-balance"
|
|
class="text-xs text-muted"
|
|
></span>
|
|
</div>
|
|
<input
|
|
type="text"
|
|
id="send-amount"
|
|
class="border border-border p-1 w-full font-mono text-sm bg-bg text-fg"
|
|
placeholder="0.0"
|
|
/>
|
|
</div>
|
|
<button
|
|
id="btn-send-review"
|
|
class="border border-border px-2 py-1 hover:bg-fg hover:text-bg cursor-pointer"
|
|
>
|
|
Review
|
|
</button>
|
|
</div>
|
|
|
|
<!-- ============ CONFIRM TRANSACTION ============ -->
|
|
<div id="view-confirm-tx" class="view hidden">
|
|
<button
|
|
id="btn-confirm-back"
|
|
class="border border-border px-2 py-1 hover:bg-fg hover:text-bg cursor-pointer mb-2"
|
|
>
|
|
< Back
|
|
</button>
|
|
<h2 class="font-bold mb-2">Confirm Transaction</h2>
|
|
<div class="mb-2">
|
|
<div class="text-xs text-muted">From</div>
|
|
<div id="confirm-from" class="text-xs break-all"></div>
|
|
</div>
|
|
<div class="mb-2">
|
|
<div class="text-xs text-muted">To</div>
|
|
<div id="confirm-to" class="text-xs break-all"></div>
|
|
<div
|
|
id="confirm-to-ens"
|
|
class="text-xs text-muted hidden"
|
|
></div>
|
|
</div>
|
|
<div class="mb-2">
|
|
<div class="text-xs text-muted">Amount</div>
|
|
<div id="confirm-amount" class="font-bold"></div>
|
|
<div
|
|
id="confirm-amount-usd"
|
|
class="text-xs text-muted"
|
|
></div>
|
|
</div>
|
|
<div
|
|
id="confirm-fee"
|
|
class="mb-2 text-xs text-muted hidden"
|
|
></div>
|
|
<div id="confirm-warnings" class="mb-2 hidden"></div>
|
|
<div
|
|
id="confirm-errors"
|
|
class="mb-2 border border-border border-dashed p-2 hidden"
|
|
></div>
|
|
<button
|
|
id="btn-confirm-send"
|
|
class="border border-border px-2 py-1 hover:bg-fg hover:text-bg cursor-pointer"
|
|
>
|
|
Send
|
|
</button>
|
|
<div
|
|
id="confirm-status"
|
|
class="mt-2 border border-border p-1 hidden"
|
|
></div>
|
|
</div>
|
|
|
|
<!-- ============ PASSWORD MODAL ============ -->
|
|
<div
|
|
id="password-modal"
|
|
class="hidden fixed inset-0 bg-bg flex items-center justify-center z-50"
|
|
>
|
|
<div class="border border-border p-4 bg-bg w-80">
|
|
<h2 class="font-bold mb-2">Enter Password</h2>
|
|
<p class="text-xs text-muted mb-2">
|
|
Your password is needed to authorize this transaction.
|
|
</p>
|
|
<input
|
|
type="password"
|
|
id="modal-password"
|
|
class="border border-border p-1 w-full font-mono text-sm bg-bg text-fg mb-2"
|
|
/>
|
|
<div
|
|
id="modal-password-error"
|
|
class="text-xs mb-2 border border-border border-dashed p-1 hidden"
|
|
></div>
|
|
<div class="flex gap-2">
|
|
<button
|
|
id="btn-modal-confirm"
|
|
class="border border-border px-2 py-1 hover:bg-fg hover:text-bg cursor-pointer"
|
|
>
|
|
Confirm
|
|
</button>
|
|
<button
|
|
id="btn-modal-cancel"
|
|
class="border border-border px-2 py-1 hover:bg-fg hover:text-bg cursor-pointer"
|
|
>
|
|
Cancel
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ============ RECEIVE ============ -->
|
|
<div id="view-receive" class="view hidden">
|
|
<button
|
|
id="btn-receive-back"
|
|
class="border border-border px-2 py-1 hover:bg-fg hover:text-bg cursor-pointer mb-2"
|
|
>
|
|
< Back
|
|
</button>
|
|
<h2 class="font-bold mb-2">Receive</h2>
|
|
<p class="mb-2">
|
|
Share this address with the sender. Make sure you only use
|
|
this address to receive Ethereum tokens.
|
|
</p>
|
|
<div class="flex justify-center mb-3">
|
|
<canvas id="receive-qr"></canvas>
|
|
</div>
|
|
<div
|
|
id="receive-address"
|
|
class="border border-border p-2 break-all select-all mb-3"
|
|
></div>
|
|
<button
|
|
id="btn-receive-copy"
|
|
class="border border-border px-2 py-1 hover:bg-fg hover:text-bg cursor-pointer"
|
|
>
|
|
Copy address
|
|
</button>
|
|
</div>
|
|
|
|
<!-- ============ ADD TOKEN ============ -->
|
|
<div id="view-add-token" class="view hidden">
|
|
<button
|
|
id="btn-add-token-back"
|
|
class="border border-border px-2 py-1 hover:bg-fg hover:text-bg cursor-pointer mb-2"
|
|
>
|
|
< Back
|
|
</button>
|
|
<h2 class="font-bold mb-2">Add Token</h2>
|
|
<p class="mb-2">
|
|
Enter the contract address of the token you want to track.
|
|
You can find this on the token's page on Etherscan.
|
|
</p>
|
|
<div class="mb-2">
|
|
<label class="block mb-1">Contract address</label>
|
|
<input
|
|
type="text"
|
|
id="add-token-address"
|
|
class="border border-border p-1 w-full font-mono text-sm bg-bg text-fg"
|
|
placeholder="0x..."
|
|
/>
|
|
</div>
|
|
<div
|
|
id="add-token-info"
|
|
class="text-xs text-muted mb-2 hidden"
|
|
></div>
|
|
<div class="mb-2">
|
|
<label class="block mb-1 text-xs text-muted"
|
|
>Or pick a common token:</label
|
|
>
|
|
<div
|
|
id="common-token-list"
|
|
class="flex flex-wrap gap-1"
|
|
></div>
|
|
</div>
|
|
<button
|
|
id="btn-add-token-confirm"
|
|
class="border border-border px-2 py-1 hover:bg-fg hover:text-bg cursor-pointer"
|
|
>
|
|
Add
|
|
</button>
|
|
</div>
|
|
|
|
<!-- ============ SETTINGS ============ -->
|
|
<div id="view-settings" class="view hidden">
|
|
<button
|
|
id="btn-settings-back"
|
|
class="border border-border px-2 py-1 hover:bg-fg hover:text-bg cursor-pointer mb-2"
|
|
>
|
|
< Back
|
|
</button>
|
|
<h2 class="font-bold mb-3">Settings</h2>
|
|
|
|
<div class="bg-well p-3 mx-1 mb-3">
|
|
<h3 class="font-bold mb-1">Wallets</h3>
|
|
<p class="text-xs text-muted mb-2">
|
|
Add a new wallet from a recovery phrase or private key.
|
|
</p>
|
|
<button
|
|
id="btn-main-add-wallet"
|
|
class="border border-border px-2 py-1 hover:bg-fg hover:text-bg cursor-pointer"
|
|
>
|
|
+ Add wallet
|
|
</button>
|
|
</div>
|
|
|
|
<div class="bg-well p-3 mx-1 mb-3">
|
|
<h3 class="font-bold mb-1">Ethereum RPC</h3>
|
|
<p class="text-xs text-muted mb-1">
|
|
The server used to talk to the Ethereum network. Change
|
|
this if you run your own node or prefer a different
|
|
provider.
|
|
</p>
|
|
<input
|
|
type="text"
|
|
id="settings-rpc"
|
|
class="border border-border p-1 w-full font-mono text-sm bg-bg text-fg"
|
|
/>
|
|
<button
|
|
id="btn-save-rpc"
|
|
class="border border-border px-2 py-1 mt-1 hover:bg-fg hover:text-bg cursor-pointer"
|
|
>
|
|
Save
|
|
</button>
|
|
</div>
|
|
|
|
<div class="bg-well p-3 mx-1 mb-3">
|
|
<h3 class="font-bold mb-1">Blockscout API</h3>
|
|
<p class="text-xs text-muted mb-1">
|
|
Used to fetch token balances and transaction history.
|
|
Change this if you run your own Blockscout instance.
|
|
</p>
|
|
<input
|
|
type="text"
|
|
id="settings-blockscout"
|
|
class="border border-border p-1 w-full font-mono text-sm bg-bg text-fg"
|
|
/>
|
|
<button
|
|
id="btn-save-blockscout"
|
|
class="border border-border px-2 py-1 mt-1 hover:bg-fg hover:text-bg cursor-pointer"
|
|
>
|
|
Save
|
|
</button>
|
|
</div>
|
|
|
|
<div class="bg-well p-3 mx-1 mb-3">
|
|
<h3 class="font-bold mb-1">Allowed Sites</h3>
|
|
<p class="text-xs text-muted mb-2">
|
|
Sites that can connect to your wallet without asking.
|
|
</p>
|
|
<div id="settings-allowed-sites"></div>
|
|
</div>
|
|
|
|
<div class="bg-well p-3 mx-1 mb-3">
|
|
<h3 class="font-bold mb-1">Denied Sites</h3>
|
|
<p class="text-xs text-muted mb-2">
|
|
Sites that are blocked from connecting to your wallet.
|
|
</p>
|
|
<div id="settings-denied-sites"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ============ TRANSACTION DETAIL ============ -->
|
|
<div id="view-transaction" class="view hidden">
|
|
<button
|
|
id="btn-tx-back"
|
|
class="border border-border px-2 py-1 hover:bg-fg hover:text-bg cursor-pointer mb-2"
|
|
>
|
|
< Back
|
|
</button>
|
|
<h2 class="font-bold mb-2">Transaction</h2>
|
|
<div class="mb-2">
|
|
<div class="text-xs text-muted">Status</div>
|
|
<div id="tx-detail-status" class="text-xs"></div>
|
|
</div>
|
|
<div class="mb-2">
|
|
<div class="text-xs text-muted">Time</div>
|
|
<div id="tx-detail-time" class="text-xs"></div>
|
|
</div>
|
|
<div class="mb-2">
|
|
<div class="text-xs text-muted">Amount</div>
|
|
<div id="tx-detail-value" class="text-xs font-bold"></div>
|
|
</div>
|
|
<div class="mb-2">
|
|
<div class="text-xs text-muted">From</div>
|
|
<div id="tx-detail-from" class="text-xs break-all"></div>
|
|
</div>
|
|
<div class="mb-2">
|
|
<div class="text-xs text-muted">To</div>
|
|
<div id="tx-detail-to" class="text-xs break-all"></div>
|
|
</div>
|
|
<div class="mb-2">
|
|
<div class="text-xs text-muted">Transaction hash</div>
|
|
<div id="tx-detail-hash" class="text-xs break-all"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ============ SITE APPROVAL ============ -->
|
|
<div id="view-approve-site" class="view hidden">
|
|
<h2 class="font-bold mb-2">Connection Request</h2>
|
|
<div class="mb-3">
|
|
<p class="mb-2">
|
|
<span id="approve-hostname" class="font-bold"></span>
|
|
wants to connect to your wallet.
|
|
</p>
|
|
<div class="text-xs text-muted mb-1">
|
|
Address that will be shared:
|
|
</div>
|
|
<div
|
|
id="approve-address"
|
|
class="text-xs flex items-center mb-2"
|
|
></div>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label
|
|
class="text-xs flex items-center gap-1 cursor-pointer"
|
|
>
|
|
<input type="checkbox" id="approve-remember" checked />
|
|
Remember my choice for this site
|
|
</label>
|
|
</div>
|
|
<div class="flex justify-between">
|
|
<button
|
|
id="btn-approve"
|
|
class="border border-border px-2 py-1 hover:bg-fg hover:text-bg cursor-pointer"
|
|
>
|
|
Allow
|
|
</button>
|
|
<button
|
|
id="btn-reject"
|
|
class="border border-border px-2 py-1 hover:bg-fg hover:text-bg cursor-pointer"
|
|
>
|
|
Deny
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="index.js"></script>
|
|
</body>
|
|
</html>
|