theseus/bundled-addons/bchwallet/wallet-inject.js
Local Dev 67939b1493 feat(theseus/bchwallet): window.bitcoincash dapp bridge with per-origin permissions
wallet-inject.js runs in the isolated world of https://*.x pages and exposes
window.bitcoincash { isTheseus, version, network, getAddress, signAndSend,
signMessage }. Every call is routed page -> addon-page-msg -> activate()
handler -> approval overlay showing the requesting origin:
- getAddress: approval with an "always allow" checkbox; grants persist in
  api.storage.permissions and are listed/revocable under Settings.
- signAndSend / signMessage: approval on every call, never remembered.
  signMessage returns a BIP-137 recoverable signature (verified offline).
- one pending approval per origin; page-facing errors never echo balance.
Host fix: the inject IPC assigned event.returnValue twice, so pages always
got an empty script list.
2026-09-06 02:56:34 +02:00

28 lines
1.4 KiB
JavaScript

// Dapp bridge, run by Theseus in the isolated world of every tab whose URL
// matches addon.json "page-inject".origins. Exposes window.bitcoincash to the
// page. Every call crosses into the wallet's activate() context in main,
// which shows the approval overlay and enforces per-origin permissions —
// nothing here can sign or read anything on its own.
//
// `theseus` is provided by the host: { id, origin, contextBridge, invoke }.
const call = (msg, payload) =>
theseus.invoke(msg, payload).catch((e) => {
// Strip Electron's IPC wrapper so the page sees the wallet's own message.
const text = String(e && e.message || e).replace(/^Error invoking remote method '[^']+': (Error: )?/, "");
throw new Error(text);
});
theseus.contextBridge.exposeInMainWorld("bitcoincash", {
isTheseus: true,
version: "0.1.0",
network: "mainnet",
// Current receiving address (cashaddr). First call per origin asks the
// user; "always allow" makes later calls silent.
getAddress: () => call("getAddress"),
// txSpec: { to, amount } (sats) or { outputs: [{ to, amount }], feeRate }.
// Always approval-gated; resolves { txid }.
signAndSend: (txSpec) => call("signAndSend", txSpec && typeof txSpec === "object" ? txSpec : {}),
// BIP-137 signature over the message with the current address's key.
// Always approval-gated; resolves { address, signature (base64) }.
signMessage: (message) => call("signMessage", { message: String(message ?? "") }),
});