Persist wallet state to extension storage
All checks were successful
check / check (push) Successful in 12s

State (wallets, RPC URL, setup flag) is saved to
browser.storage.local / chrome.storage.local after every
mutation and loaded on popup open. In DEBUG mode, the lock
screen is skipped since encryption is not yet implemented.
This commit is contained in:
2026-02-25 16:02:33 +07:00
parent 079541e84b
commit 88f57263fb

View File

@@ -28,21 +28,52 @@ function showView(name) {
} }
} }
// -- mock state (will be replaced by background messaging) -- // Browser-agnostic storage API
const storage =
typeof browser !== "undefined"
? browser.storage.local
: chrome.storage.local;
// A wallet is either { type: "hd", name, mnemonic, addresses: [...] } // A wallet is either { type: "hd", name, mnemonic, addresses: [...] }
// or { type: "key", name, privateKey, addresses: [single] }. // or { type: "key", name, privateKey, addresses: [single] }.
// Each address is { address, balance, tokens: [...] }. // Each address is { address, balance, tokens: [...] }.
const state = { const DEFAULT_STATE = {
locked: true,
hasWallet: false, hasWallet: false,
password: null,
wallets: [], wallets: [],
selectedWallet: null,
selectedAddress: null,
rpcUrl: "https://eth.llamarpc.com", rpcUrl: "https://eth.llamarpc.com",
isFirstSetup: true, isFirstSetup: true,
}; };
// Transient state (not persisted)
const state = {
...DEFAULT_STATE,
locked: true,
password: null,
selectedWallet: null,
selectedAddress: null,
};
async function saveState() {
const persisted = {
hasWallet: state.hasWallet,
wallets: state.wallets,
rpcUrl: state.rpcUrl,
isFirstSetup: state.isFirstSetup,
};
await storage.set({ autistmask: persisted });
}
async function loadState() {
const result = await storage.get("autistmask");
if (result.autistmask) {
const saved = result.autistmask;
state.hasWallet = saved.hasWallet;
state.wallets = saved.wallets || [];
state.rpcUrl = saved.rpcUrl || DEFAULT_STATE.rpcUrl;
state.isFirstSetup = saved.isFirstSetup;
}
}
// -- helpers -- // -- helpers --
function $(id) { function $(id) {
return document.getElementById(id); return document.getElementById(id);
@@ -121,11 +152,12 @@ function renderWalletList() {
}); });
container.querySelectorAll(".btn-add-address").forEach((btn) => { container.querySelectorAll(".btn-add-address").forEach((btn) => {
btn.addEventListener("click", (e) => { btn.addEventListener("click", async (e) => {
e.stopPropagation(); e.stopPropagation();
const wi = parseInt(btn.dataset.wallet, 10); const wi = parseInt(btn.dataset.wallet, 10);
// TODO: derive next address from seed via background // TODO: derive next address from seed via background
state.wallets[wi].addresses.push(makeStubAddress()); state.wallets[wi].addresses.push(makeStubAddress());
await saveState();
renderWalletList(); renderWalletList();
}); });
}); });
@@ -180,10 +212,11 @@ function currentAddress() {
return state.wallets[state.selectedWallet].addresses[state.selectedAddress]; return state.wallets[state.selectedWallet].addresses[state.selectedAddress];
} }
function addWalletAndGoToMain(wallet) { async function addWalletAndGoToMain(wallet) {
state.wallets.push(wallet); state.wallets.push(wallet);
state.hasWallet = true; state.hasWallet = true;
state.isFirstSetup = false; state.isFirstSetup = false;
await saveState();
renderWalletList(); renderWalletList();
showView("main"); showView("main");
} }
@@ -243,7 +276,7 @@ function backFromWalletAdd() {
} }
// -- init -- // -- init --
function init() { async function init() {
if (DEBUG) { if (DEBUG) {
const banner = document.createElement("div"); const banner = document.createElement("div");
banner.textContent = "DEBUG / INSECURE"; banner.textContent = "DEBUG / INSECURE";
@@ -252,6 +285,13 @@ function init() {
document.body.prepend(banner); document.body.prepend(banner);
} }
await loadState();
// In DEBUG mode, skip the lock screen (no encryption yet)
if (DEBUG && state.hasWallet) {
state.locked = false;
}
if (!state.hasWallet) { if (!state.hasWallet) {
showView("welcome"); showView("welcome");
} else if (state.locked) { } else if (state.locked) {
@@ -443,7 +483,7 @@ function init() {
}); });
// -- Add Token -- // -- Add Token --
$("btn-add-token-confirm").addEventListener("click", () => { $("btn-add-token-confirm").addEventListener("click", async () => {
const contractAddr = $("add-token-address").value.trim(); const contractAddr = $("add-token-address").value.trim();
if (!contractAddr || !contractAddr.startsWith("0x")) { if (!contractAddr || !contractAddr.startsWith("0x")) {
showError( showError(
@@ -462,6 +502,7 @@ function init() {
decimals: 18, decimals: 18,
balance: "0", balance: "0",
}); });
await saveState();
} }
showAddressDetail(); showAddressDetail();
}); });
@@ -471,9 +512,9 @@ function init() {
}); });
// -- Settings -- // -- Settings --
$("btn-save-rpc").addEventListener("click", () => { $("btn-save-rpc").addEventListener("click", async () => {
state.rpcUrl = $("settings-rpc").value.trim(); state.rpcUrl = $("settings-rpc").value.trim();
// TODO: persist via background await saveState();
}); });
$("btn-settings-back").addEventListener("click", () => { $("btn-settings-back").addEventListener("click", () => {