Second bundled wallet, same shape as bchwallet:
- keys: api.vault.derive("siawallet/mainnet/0") as the seed for walletd's
KeyFromSeed(seed, index) (blake2b(seed||index) -> ed25519); addresses are
standard unlock hashes, so a future walletd seed import yields the same
addresses. Seed and keys live in memory only.
- lib/sia.js: Sia binary encoder, StandardUnlockHash, address checksum,
v2 InputSigHash ("sia/sig/input|" + replay byte 2 + transaction
semantics), transaction weight, walletd JSON. Address hashing and the
sighash were verified against real mainnet v2 transactions (signatures
from block 591853 verify under this implementation).
- lib/walletd.js: address-scoped walletd HTTP client (tip, fee, balance,
outputs with proofs, events, broadcast). The node URL is a user setting
with no default; hosted providers embed the access key in the path, so
only the origin is ever displayed or logged.
- lib/wallet.js: gap-limit discovery via events, mature/immature balance,
history deltas from v1/v2/foundation/miner events, largest-first
selection with change to the current address, fee = walletd rate x
weight x 1-3 multiplier, broadcast with the outputs' basis. A signed tx
built here was accepted structurally by a live walletd (rejected only
for the stub key not owning the parent).
- panel: Receive (QR), Send, History, Settings (node URL, derivation info,
seed reveal behind approval, connected sites); gates for locked vault,
no vault, no node URL.
- window.siacoin dapp bridge: getAddress (rememberable), signAndSend with
100/1,000/10,000 SC allowances, signMessage (ed25519 over blake2b-256 of
the message) — same approval and permission rules as the BCH wallet.
The dapp send approval gains an "Afterwards" dropdown: ask every time, or
allow up to 0.001 / 0.01 / 0.1 BCH more without asking. The allowance is
stored as permissions[origin].sendTx {capSats, usedSats}; sends within the
remainder go through silently and draw it down, a larger request re-prompts
(showing what is left) and the choice made there replaces the allowance.
No unlimited option. Settings > Connected sites shows the remaining budget
and Revoke clears it. Message signing still asks every time.
Host: approvalModal accepts `select` {id, label, options}; a chosen value
comes back as "+<id>=<value>" and is validated against the offered options.
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.
Send tab: recipient (cashaddr or legacy, testnet rejected), amount with
BCH/sat toggle and Max, 1-5 sat/B fee slider, live fee/total preview via
planSend. Sending goes plan -> approval-modal (To/Amount/Fee/Total) ->
ECDSA DER + SIGHASH_ALL|FORKID -> blockchain.transaction.broadcast, then
shows the txid with an explorer link. Confirmed coins are spent before
unconfirmed; dust change folds into the fee. Verified end to end against a
fake Fulcrum: broadcast tx re-parsed, sighash recomputed, signature checks.
Manifest declaring sidebar-panel, vault-derive, page-inject (https://*.x)
and approval-modal; registers the Wallet sidebar panel. Shows up in
Settings > Extensions and opens from the sidebar.
New subsystem for extending Theseus with folders on disk. Each add-on
lives at <userData>/addons/<id>/ with an addon.json manifest and a
CommonJS entry that exports activate(api). Nothing about a private
add-on ships in the public installer - drop the folder, restart, it's
live. Bundled reference add-ons ride in the packaged app under
resources/bundled-addons/ and are seeded into <userData>/addons/ on
first boot; the framework treats seeded and drop-in add-ons the same.
Files:
- addons-host.js Loader + api.registerSidebarPanel() + per-
addon storage on <userData>/addons-data/.
Kept at the CommonJS-scoped top level (lib/
is ESM-scoped via its own package.json).
- sidebar-preload.js Runs in every sidebar panel. Exposes
window.silentmode.storage.{get,set,all} +
onVisibility. Main-side handlers derive the
add-on id from the sender file:// URL, so a
panel can only touch its own store.
- bundled-addons/notepad/ Reference add-on: addon.json, index.js,
note.html. Autosaving textarea with char /
word count.
main.js:
- Extension point: sidebar-panel. One right-anchored WebContentsView
(SIDEBAR_W=340) hosts the current panel; layout() shrinks the tab
views by the sidebar width when visible. First registered panel
wins for MVP; picker for multiple panels lands later.
- initAddons() at app.whenReady(): seedBundledAddons, then
AddonHost.discoverAndActivate.
- IPC surface: sidebar-toggle / sidebar-open / sidebar-close /
sidebar-state, addons-list / addons-set-enabled / addons-reveal /
addons-open-dir / addons-reload, and origin-gated
addon-storage-get/set/all.
- Settings gains `disabledAddons: []` — off-toggled ids persist and
the loader honours them without a restart (discoverAndActivate
runs again on toggle).
chrome.html: toolbar sidebar-toggle button, hidden until at least one
add-on has registered a sidebar panel.
settings.html: new "Add-ons" section under privacy. Lists installed
add-ons with icon / name / version / description / capabilities;
per-add-on enable/disable toggle + Show folder button; page-level
Reload and Open add-ons folder buttons; warning note about the trust
model.
package.json: build.files gains sidebar-preload.js + addons-host.js.
extraResources gains bundled-addons/ so the packaged app carries the
reference notepad for the first-boot seed.
Verified: `npm start` boots, addons-host discovers the notepad,
activates it, registers one sidebar panel. Log confirms
"1 installed, 1 enabled, 1 sidebar panels". Actual sidebar rendering
+ notepad UI need clicked-through validation on a real install.
Not shipped yet - deploy still blocked on the fail2ban VPS SSH ban.
Ships as 0.2.0 once SSH clears (this is a new subsystem, not a fix).