Setup 5d15508bba929f1f074c052ac933863eadf6eb8e56984ebd5a1af75e80626643 Portable a5d346b97f5a13d85fa3bd301a72075ddb82fe636d7b1a51840ffd5a16d879f4 Bundled since 0.3.27: 32d4b75 - Aegis (bchwallet) gains its own update card in Settings > General beside Ariadne. Check for updates hits the same signed OTA endpoint the boot timer uses; Restart to apply appears when a signed newer version is staged. Uses the existing addons-check-updates + a new app-restart IPC. New Aegis versions ship without a Theseus release. 32d4b75 (same commit) - DevTools (F12 / Ctrl+Shift+I) opens docked to the right of the tab (mode: 'right') instead of a detached window. Matches stock Chrome. Users who prefer detached can drag out via the DevTools own toolbar. b71c925 - Search-engine favicons in Settings > Search now use Google's /s2/favicons service — DuckDuckGo's ip3 source returned 404 for enough hosts (Brave, Bing, Yandex, etc.) that half the list was falling through to the emoji placeholder. Deployed. Verified LIVE 0.3.28.
42 lines
2.3 KiB
JavaScript
42 lines
2.3 KiB
JavaScript
// Thin client for the walletd HTTP API (go.sia.tech/walletd, index mode
|
|
// "full"). Only address-scoped reads plus txpool fee/broadcast are used, so
|
|
// any public or self-hosted walletd works; the URL is a user setting.
|
|
module.exports = function makeWalletd({ log = () => {} }) {
|
|
class Client {
|
|
constructor(baseUrl) { this.setBase(baseUrl); }
|
|
setBase(baseUrl) {
|
|
const u = String(baseUrl || "").trim().replace(/\/+$/, "");
|
|
this.base = u ? (u.endsWith("/api") ? u : u + "/api") : "";
|
|
}
|
|
// Everything after the host is the node's business; only the origin is
|
|
// ever logged or shown, since hosted providers key access on the path.
|
|
get displayUrl() { try { return new URL(this.base).origin; } catch { return this.base; } }
|
|
async _req(method, path, body) {
|
|
if (!this.base) throw new Error("no walletd URL configured");
|
|
const ctrl = new AbortController();
|
|
const timer = setTimeout(() => ctrl.abort(), 25000);
|
|
try {
|
|
const res = await fetch(this.base + path, {
|
|
method, signal: ctrl.signal,
|
|
headers: body !== undefined ? { "content-type": "application/json" } : {},
|
|
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
});
|
|
const text = await res.text();
|
|
if (!res.ok) throw new Error(`walletd ${res.status}: ${text.slice(0, 200).trim()}`);
|
|
try { return JSON.parse(text); } catch { return text; }
|
|
} finally { clearTimeout(timer); }
|
|
}
|
|
get(path) { return this._req("GET", path); }
|
|
post(path, body) { return this._req("POST", path, body); }
|
|
|
|
tip() { return this.get("/consensus/tip"); }
|
|
// Recommended fee in hastings per byte (JSON string).
|
|
async feePerByte() { return BigInt(String(await this.get("/txpool/fee")).replace(/"/g, "")); }
|
|
balance(addr) { return this.get(`/addresses/${addr}/balance`); }
|
|
// { basis, outputs: [SiacoinElement] } — proofs are valid at `basis`.
|
|
outputs(addr, limit = 100, offset = 0) { return this.get(`/addresses/${addr}/outputs/siacoin?limit=${limit}&offset=${offset}`); }
|
|
events(addr, limit = 25, offset = 0) { return this.get(`/addresses/${addr}/events?limit=${limit}&offset=${offset}`); }
|
|
broadcast(basis, v2tx) { return this.post("/txpool/broadcast", { basis, transactions: [], v2transactions: [v2tx] }); }
|
|
}
|
|
return { Client };
|
|
};
|