Commit graph

7 commits

Author SHA1 Message Date
Local Dev
2e54bf5e5a Ship Theseus 0.3.28 5d15508b (Aegis update card + DevTools in tab sidebar + real favicons)
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.
2026-09-08 18:17:25 +02:00
Local Dev
1b29706ba4 feat(theseus/aegis): EIP-3085 wallet_addEthereumChain + EIP-3326 switchChain
Aegis now handles the standard MetaMask try-switch-then-add flow. A dapp
that wants to route through Polygon (or Base, or Arbitrum, or any other
EVM the Silent Mode user hasn't added yet) calls the pair the industry
already wrote for it — Aegis registers the chain, provisions a wallet on
it under the same vault seed, auto-connects the origin, fires
chainChanged, and hands the dapp back a provider pointed at the new
chain. No sidebar detour, no Custom RPC copy-paste. Users still see
every chain in the picker post-add and can revoke sites in Settings.

- lib/chain-eth.js: EthWallet accepts a customNetwork override
  ({id, label, chainId, defaultRpc, explorerTx, explorerAddr, ticker}).
  When present it replaces the NETWORKS lookup so mainnet+Sepolia
  ship built-in and every EIP-3085 chain is a runtime override the
  addon persists. The ticker flows into snapshot() so the send
  approval reads MATIC / BNB / whatever the chain's native currency is,
  not a hardcoded ETH.
- index.js customEthChains storage: `{[chainId]: {chainName, rpcUrl,
  explorerTx, explorerAddr, ticker, addedAt, addedByOrigin}}`.
  Persisted under api.storage.customEthChains, so an added chain
  survives Theseus restarts. chainMeta("eth", "custom-<chainId>")
  synthesizes the meta from storage so the panel renders custom
  chains without needing them in COINS at module-load time.
- eth.addChain handler (EIP-3085): approval overlay shows chain
  name, decimal + hex chain id, native ticker, RPC and explorer
  URLs (the phishing-signal quartet). On approval, persist config +
  create wallet with a custom-<chainId> network + auto-grant the
  origin readAddress on this chain. No-op success if the chain is
  already added.
- eth.switchChain rewritten to be EIP-3326 correct: look up any
  ready ETH wallet whose adapter reports the requested chainId,
  make it the selected wallet, fire chainChanged. When no wallet
  matches, throw with .code = 4902 (the standard 'chain not
  added' code) so wagmi / RainbowKit / any 3326-aware dapp does
  the fallback wallet_addEthereumChain call in the same click.
- eth.state handler: cheap {address, chainIdHex, networkVersion}
  peek for the origin's currently-connected wallet (no approval,
  no key access). The main-world bridge calls it after every
  switch/add to emit chainChanged + accountsChanged locally — the
  events MetaMask fires and RainbowKit listens for.
- wallet-inject.js: routes wallet_addEthereumChain via
  eth.addChain, preserves the 4902 code across the postMessage
  boundary on switch failures, calls pullEthStateAndEmit() to fire
  the post-switch/add events.
2026-09-07 22:26:27 +02:00
Local Dev
8fcc0e2433 feat(theseus/aegis): EIP-712 signTypedData_v4 + Solana multi-signer send
Two follow-ups to the dapp bridges. Both change wire shape only — no new
UI, existing wallets keep signing byte-identically for the flows they
already covered.

- lib/eip712.js: full EIP-712 typed-data encoder — encodeType with
  alphabetically-sorted transitive sub-types, typeHash, encodeValue for
  string / address / bool / uint*/int* (any width) / bytes / bytesN /
  nested structs / dynamic and fixed arrays, hashStruct recursion,
  digest = keccak256(0x19 || 0x01 || domainSeparator || hashStruct).
  Verified against the spec §"Ether Mail" test vector — hashStruct on
  both the domain and the message plus the final digest all match the
  canonical values byte-for-byte (see scratchpad/verify-eip712.mjs).
- chain-eth.js: exposes signTypedDataDigest(digest32) that signs the
  precomputed digest with r||s||v (v = 27+recid), the same envelope
  personal_sign uses. Aegis computes the digest server-side (in the
  addon) so a bug in the encoder can't be tricked by a malicious dapp
  into signing over data the user never saw.
- index.js: eth.signTypedData handler shows domain (name · version ·
  chainId), primary type, and a truncated JSON preview of the message
  in the approval overlay — every classic phishing signal (mismatched
  domain, unexpected primary type) is in front of the user before they
  hit Sign. Accepts either an already-parsed typedData object or the
  JSON-string form older MetaMask specs used.
- wallet-inject.js router: eth_signTypedData_v4 (and _v3 for the same
  payload shape) route to eth.signTypedData. v1's flat "type[]" form
  is unwired — dapps that still use v1 should upgrade.
- Solana signAndSend: bridge now passes the FULL wire (from
  tx.serialize({requireAllSignatures:false, verifySignatures:false}))
  instead of just the message. The addon parses compact-u16 signature
  count, finds this wallet's pubkey in the message's account-key list,
  signs the message, and patches ONLY its own slot in the signature
  array — any partial signatures the dapp had already filled with
  tx.partialSign() (session keys, escrow co-signers, permissioned
  authorities) are preserved. Multi-signer flows work now; single-signer
  is the degenerate case of sigCount=1.
- Approval overlay for sol.signAndSend now shows required-signer count
  and the wallet's slot index so multi-signer requests are visibly
  distinct from a plain single-signer send.
2026-09-07 22:19:51 +02:00
Local Dev
5880ba3507 feat(theseus/aegis): EIP-1193 + Solana wallet-adapter bridges; BTC signet
Aegis now integrates with the two dapp-wallet APIs the wider ecosystem
actually uses — MetaMask-style window.ethereum for Ethereum, Phantom-style
window.solana for Solana — plus BTC signet as a third Bitcoin network
alongside mainnet + testnet3.

- wallet-inject.js: adds a main-world bridge, installed via a one-shot
  <script textContent=…> appended to <head> and immediately removed.
  Electron's contextBridge shallow-copies args and strips methods, which
  means BCH- and Tron-shaped params (plain data) work in the isolated
  world but Solana's wallet-adapter dapps — which pass @solana/web3.js
  Transaction objects and expect .serializeMessage()/.addSignature() to
  fire on them — need code that lives in the same world as the dapp.
  Bridge talks back to the isolated world via window.postMessage on a
  namespaced envelope (aegisTag = "aegis-" + addonId), which forwards to
  theseus.invoke. Same pattern MetaMask + Phantom use.
- window.ethereum (EIP-1193): request({method, params}), on(),
  removeListener(), chainId, networkVersion, selectedAddress. Handles
  eth_requestAccounts, eth_accounts, eth_chainId, net_version,
  personal_sign, eth_sign, eth_sendTransaction, wallet_switchEthereumChain
  (rejects with "use the Aegis picker"), wallet_addEthereumChain
  (rejects, chains come from Settings), wallet_get/requestPermissions.
  Every other eth_*/net_*/web3_* method passes through to the wallet's
  configured RPC via a new eth.rpc handler. EIP-6963 announceProvider
  event fires so wagmi / RainbowKit / any 6963-aware dapp discovers
  Aegis alongside MetaMask instead of racing for window.ethereum.
- window.solana (wallet-adapter shape): connect(), disconnect(),
  publicKey (with toString/toBase58/toBytes/equals — the PublicKey
  interface dapps check), signMessage(u8) → {publicKey, signature: u8},
  signTransaction(tx) → mutates + returns the same tx with the
  signature added, signAndSendTransaction(tx) → returns {signature: txid},
  signAllTransactions([tx]), request({method, params}). isPhantom flag
  set true so dapps that gate on it pick us. on/off events for connect
  / disconnect / accountChanged.
- Handlers in index.js registerPageMessages: eth.requestAccounts,
  eth.personalSign, eth.sendTransaction, eth.switchChain, eth.rpc,
  sol.connect, sol.signMessage, sol.signAndSend. Every write path is
  per-origin gated + goes through api.approvalModal with the wallet
  label + network in the row list so the user always knows which
  Aegis wallet is about to sign.
- Signet added to chain-btc.js — signet shares testnet3's address
  format and SLIP-44 coin type (BIP-325 only changed consensus/signing),
  so bitcoinjs-lib.networks.testnet handles derivation unchanged. Only
  the electrum pool (aranguren + wakiyamap) + explorer (mempool.space
  /signet) + faucet (signetfaucet.com) differ. Registered as
  btc:signet in COINS with per-network coinType lookup.

Known limits (follow-ups in the same shape as existing chains):
- SOL signAndSendTransaction is single-signer only; dapps that combine
  the wallet's sig with co-signer sigs need the wire assembled on the
  dapp side.
- ETH eth_signTypedData_v4 (EIP-712) is not wired — the handler set
  covers personal_sign only.
2026-09-07 22:08:56 +02:00
Local Dev
5574641fb9 feat(theseus/aegis): multi-wallet + Tron mainnet + Tron Nile in the bundled addon
Turns the single-account BCH addon into Aegis: a chain-agnostic wallet manager
with a wallet picker in the sidebar header, per-wallet sub-accounts, and Tron
mainnet + Nile alongside BCH. Add-on id stays "bchwallet" so vault-derive paths
stay in the same namespace and the legacy BCH default wallet uses PURPOSE
"bchwallet/mainnet/0" byte-identical to before — funds are untouched.

- lib/chain-bch.js wraps the existing keys/tx/wallet/electrum stack with the
  common adapter shape and scopes each wallet's storage under wallets/<id>/…
- lib/chain-tron.js: m/44'/195'/0'/0/0 → secp256k1 → keccak256 → 0x41 || h20
  → base58check. Balance + history via TronGrid v1, send via createtransaction
  + sha256(raw_data_hex) sign + broadcasttransaction. Mainnet and Nile share
  the address format; different vault paths mean different keys so a mainnet
  wallet can never accidentally sign against Nile.
- lib/base58check.js: bitcoin-alphabet base58 with sha256d checksum. k=1
  derivation verified against Ethereum's canonical k=1 H160 in a scratchpad
  harness (correct-by-construction for Tron address).
- Combined wallet-inject.js: window.bitcoincash on .x pages (unchanged gate),
  window.tronWeb + window.tronLink on any https page. tron_requestAccounts
  triggers the approval overlay; sign / sendRawTransaction / signMessageV2
  route to the currently-selected Tron wallet. Emits accountsChanged /
  setNode messages TronLink dapps listen for; chain ids 0x2b6653dc /
  0xcd8690dc match what TronLink itself uses.
- New panel: chain-aware wallet picker in the header (badges 🟨 BCH,
  🔴 Tron, 🔵 Nile), Add-wallet dropdown per chain, per-chain unit picker
  (BCH/sat, TRX/sun), per-wallet rename + remove (isLegacy default is
  protected). Sends show the chosen wallet in the approval overlay so the
  user can never mistake sub-account.
- Migration on first launch: pre-multi-wallet storage (top-level
  receiveCursor / txCache) is rehomed under wallets/bch-default/… and the
  legacy account path is preserved.

Not shipped: user is bundling into the next release. Live Nile broadcast +
real dapp connect need a set-up vault; the code paths are unit-verified end
to end but a testnet send + tronscan.io/nile connect are user-side steps.
2026-09-06 22:00:27 +02:00
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
Local Dev
dcab5c10ec feat(theseus/bchwallet): bundled Bitcoin Cash wallet add-on skeleton
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.
2026-09-06 02:33:27 +02:00