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
// Aegis — multi-chain wallet bundled with Theseus. activate() runs in the
// main process; every wallet's key material lives here, in memory, and is
// re-derived from the password vault on every launch. Nothing secret is ever
// written to disk or logged.
//
// A single addon can hold many wallets — one per {chain, network}, or several
// sub-accounts of the same chain — and each wallet is backed by its own
// vault-derived 32-byte HKDF root. Chains today: BCH, Tron mainnet, Tron
// Nile testnet. Adding a fourth chain is a new adapter file under lib/ and
// an entry in the CHAIN_REGISTRY below.
//
// Back-compat: the addon id stays "bchwallet" (the manifest label became
// Aegis, but the id gates the vault-derive namespace and older vaults have
// funds against it). The legacy BCH default wallet uses purpose
// "bchwallet/mainnet/0" — byte-identical to the pre-multi-wallet build —
// so on-disk funds are untouched. See memory bchwallet-vault-root-derivation.
feat(theseus/bchwallet): receive + history — vault-derived keys, cashaddr, QR, electrum
Wallet core on mainnet:
- keys from api.vault.derive("bchwallet/mainnet/0") -> BIP32 m/44'/145'/0'
(@scure/bip32), never persisted; wiped on deactivate.
- lib/cashaddr.js (encode/decode + legacy Base58Check, spec vectors pass),
lib/keys.js (hash160, p2pkh, electrum scripthash, ECDSA DER + BIP-137
recoverable signing), lib/tx.js (serialization, SIGHASH_ALL|FORKID
digest, coin selection, fee estimate), lib/electrum.js (Fulcrum WSS
client with failover + subscriptions), lib/wallet.js (gap-limit scan,
balance, UTXOs, 25-tx history with per-tx deltas, cached public txs).
- qr.js: dependency-free QR encoder (byte mode, v1-10, EC M/L; verified
against jsQR).
- panel: balance header, Receive (QR, copy, next unused address, explorer),
History (deltas, confirmations, explorer links), Settings (derivation
path, electrum server list, xpub / approval-gated xprv reveal). Locked
and not-set-up vault states explained in-panel.
- host: api.import for ESM-only deps, api.openTab for explorer links; an
add-on whose activate() throws is no longer listed twice.
2026-09-06 02:46:41 +02:00
const path = require ( "node:path" ) ;
const fs = require ( "node:fs" ) ;
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
const LEGACY _BCH _PURPOSE = "bchwallet/mainnet/0" ;
const LEGACY _BCH _WALLET _ID = "bch-default" ;
feat(theseus/bchwallet): receive + history — vault-derived keys, cashaddr, QR, electrum
Wallet core on mainnet:
- keys from api.vault.derive("bchwallet/mainnet/0") -> BIP32 m/44'/145'/0'
(@scure/bip32), never persisted; wiped on deactivate.
- lib/cashaddr.js (encode/decode + legacy Base58Check, spec vectors pass),
lib/keys.js (hash160, p2pkh, electrum scripthash, ECDSA DER + BIP-137
recoverable signing), lib/tx.js (serialization, SIGHASH_ALL|FORKID
digest, coin selection, fee estimate), lib/electrum.js (Fulcrum WSS
client with failover + subscriptions), lib/wallet.js (gap-limit scan,
balance, UTXOs, 25-tx history with per-tx deltas, cached public txs).
- qr.js: dependency-free QR encoder (byte mode, v1-10, EC M/L; verified
against jsQR).
- panel: balance header, Receive (QR, copy, next unused address, explorer),
History (deltas, confirmations, explorer links), Settings (derivation
path, electrum server list, xpub / approval-gated xprv reveal). Locked
and not-set-up vault states explained in-panel.
- host: api.import for ESM-only deps, api.openTab for explorer links; an
add-on whose activate() throws is no longer listed twice.
2026-09-06 02:46:41 +02:00
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
let ctx = null ;
feat(theseus/bchwallet): receive + history — vault-derived keys, cashaddr, QR, electrum
Wallet core on mainnet:
- keys from api.vault.derive("bchwallet/mainnet/0") -> BIP32 m/44'/145'/0'
(@scure/bip32), never persisted; wiped on deactivate.
- lib/cashaddr.js (encode/decode + legacy Base58Check, spec vectors pass),
lib/keys.js (hash160, p2pkh, electrum scripthash, ECDSA DER + BIP-137
recoverable signing), lib/tx.js (serialization, SIGHASH_ALL|FORKID
digest, coin selection, fee estimate), lib/electrum.js (Fulcrum WSS
client with failover + subscriptions), lib/wallet.js (gap-limit scan,
balance, UTXOs, 25-tx history with per-tx deltas, cached public txs).
- qr.js: dependency-free QR encoder (byte mode, v1-10, EC M/L; verified
against jsQR).
- panel: balance header, Receive (QR, copy, next unused address, explorer),
History (deltas, confirmations, explorer links), Settings (derivation
path, electrum server list, xpub / approval-gated xprv reveal). Locked
and not-set-up vault states explained in-panel.
- host: api.import for ESM-only deps, api.openTab for explorer links; an
add-on whose activate() throws is no longer listed twice.
2026-09-06 02:46:41 +02:00
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
// ---- deps -------------------------------------------------------------------
feat(theseus/bchwallet): receive + history — vault-derived keys, cashaddr, QR, electrum
Wallet core on mainnet:
- keys from api.vault.derive("bchwallet/mainnet/0") -> BIP32 m/44'/145'/0'
(@scure/bip32), never persisted; wiped on deactivate.
- lib/cashaddr.js (encode/decode + legacy Base58Check, spec vectors pass),
lib/keys.js (hash160, p2pkh, electrum scripthash, ECDSA DER + BIP-137
recoverable signing), lib/tx.js (serialization, SIGHASH_ALL|FORKID
digest, coin selection, fee estimate), lib/electrum.js (Fulcrum WSS
client with failover + subscriptions), lib/wallet.js (gap-limit scan,
balance, UTXOs, 25-tx history with per-tx deltas, cached public txs).
- qr.js: dependency-free QR encoder (byte mode, v1-10, EC M/L; verified
against jsQR).
- panel: balance header, Receive (QR, copy, next unused address, explorer),
History (deltas, confirmations, explorer links), Settings (derivation
path, electrum server list, xpub / approval-gated xprv reveal). Locked
and not-set-up vault states explained in-panel.
- host: api.import for ESM-only deps, api.openTab for explorer links; an
add-on whose activate() throws is no longer listed twice.
2026-09-06 02:46:41 +02:00
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
async function loadDeps ( api ) {
feat(theseus/bchwallet): receive + history — vault-derived keys, cashaddr, QR, electrum
Wallet core on mainnet:
- keys from api.vault.derive("bchwallet/mainnet/0") -> BIP32 m/44'/145'/0'
(@scure/bip32), never persisted; wiped on deactivate.
- lib/cashaddr.js (encode/decode + legacy Base58Check, spec vectors pass),
lib/keys.js (hash160, p2pkh, electrum scripthash, ECDSA DER + BIP-137
recoverable signing), lib/tx.js (serialization, SIGHASH_ALL|FORKID
digest, coin selection, fee estimate), lib/electrum.js (Fulcrum WSS
client with failover + subscriptions), lib/wallet.js (gap-limit scan,
balance, UTXOs, 25-tx history with per-tx deltas, cached public txs).
- qr.js: dependency-free QR encoder (byte mode, v1-10, EC M/L; verified
against jsQR).
- panel: balance header, Receive (QR, copy, next unused address, explorer),
History (deltas, confirmations, explorer links), Settings (derivation
path, electrum server list, xpub / approval-gated xprv reveal). Locked
and not-set-up vault states explained in-panel.
- host: api.import for ESM-only deps, api.openTab for explorer links; an
add-on whose activate() throws is no longer listed twice.
2026-09-06 02:46:41 +02:00
const { secp256k1 } = await api . import ( "@noble/curves/secp256k1.js" ) ;
feat(theseus/aegis): fold Sia into the addon; add DGB (BIP84 native SegWit)
Aegis now covers four coins across two-step coin+network picks: BCH
(mainnet + chipnet), TRX (mainnet + Nile), SC (mainnet), DGB (mainnet).
- Sia (SC): pulled the standalone siawallet's lib into
bundled-addons/bchwallet/lib/sia/ and wrote lib/chain-sia.js exposing
the common adapter shape. The very first SC wallet the user adds in
Aegis reuses purpose "siawallet/mainnet/0" so pre-Aegis funds carry
over automatically; subsequent SC sub-accounts start at
"bchwallet/sc/mainnet/1". Per-wallet walletd URL setting; empty URL
shows a "Point Aegis at a walletd node" gate in the panel.
- Vault-derive gate now honors a manifest-declared `absorbs` list, so
Aegis's addon.json can list `absorbs: ["siawallet"]` and the derive()
guard accepts paths under either the current id or the absorbed one —
the mechanism a superseding add-on uses to inherit an older add-on's
keyspace without orphaning funds.
- DigiByte (DGB): lib/chain-dgb.js ports the relevant bits of the
SilentCode Digibyte design — SLIP-44 coin type 20, BIP84 native SegWit
(m/84'/20'/0'/0/x → dgb1q…) via ripemd160(sha256(pubkey)) + bech32.
ElectrumX-DGB backend reuses lib/electrum.js (public wss:50022 pool).
BIP143 P2WPKH sighash + witness-tx serialize implemented inline (no
FORKID — DGB uses standard Bitcoin sighash). Derivation cross-checked
against a known BIP39 vector in scratchpad/verify-dgb.mjs — the address
for "abandon×11 about, m/84'/20'/0'/0/0" is
dgb1q9gmf0pv8jdymcly6lz6fl7lf6mhslsd72e2jq8, matching iancoleman.io/bip39.
- Panel: SVG coin logos for SC (green disc with S) and DGB (blue
octagon with D) alongside the BCH/TRX marks. Chain-specific settings
block per coin (walletd URL for SC; derivation path for DGB). Balance
render uses BigInt-safe arithmetic so 24-decimal SC amounts don't
lose precision on the way through the panel; amount input on SC
returns a hastings string.
- Every chain adapter's snapshot fits the panel's shared shape
(address/balance/history/etc.), so future chains only need a new
chain-<x>.js file, a COINS registry entry, a matching case in
mountWallet, and an SVG logo.
Standalone siawallet addon stays as-is on disk; users can delete it once
they've confirmed Aegis shows the same balance. Nothing here disables it.
2026-09-07 01:56:25 +02:00
const { ed25519 } = await api . import ( "@noble/curves/ed25519.js" ) ;
feat(theseus/bchwallet): receive + history — vault-derived keys, cashaddr, QR, electrum
Wallet core on mainnet:
- keys from api.vault.derive("bchwallet/mainnet/0") -> BIP32 m/44'/145'/0'
(@scure/bip32), never persisted; wiped on deactivate.
- lib/cashaddr.js (encode/decode + legacy Base58Check, spec vectors pass),
lib/keys.js (hash160, p2pkh, electrum scripthash, ECDSA DER + BIP-137
recoverable signing), lib/tx.js (serialization, SIGHASH_ALL|FORKID
digest, coin selection, fee estimate), lib/electrum.js (Fulcrum WSS
client with failover + subscriptions), lib/wallet.js (gap-limit scan,
balance, UTXOs, 25-tx history with per-tx deltas, cached public txs).
- qr.js: dependency-free QR encoder (byte mode, v1-10, EC M/L; verified
against jsQR).
- panel: balance header, Receive (QR, copy, next unused address, explorer),
History (deltas, confirmations, explorer links), Settings (derivation
path, electrum server list, xpub / approval-gated xprv reveal). Locked
and not-set-up vault states explained in-panel.
- host: api.import for ESM-only deps, api.openTab for explorer links; an
add-on whose activate() throws is no longer listed twice.
2026-09-06 02:46:41 +02:00
const { sha256 } = await api . import ( "@noble/hashes/sha2.js" ) ;
const { ripemd160 } = await api . import ( "@noble/hashes/legacy.js" ) ;
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
const { keccak _256 } = await api . import ( "@noble/hashes/sha3.js" ) ;
feat(theseus/aegis): fold Sia into the addon; add DGB (BIP84 native SegWit)
Aegis now covers four coins across two-step coin+network picks: BCH
(mainnet + chipnet), TRX (mainnet + Nile), SC (mainnet), DGB (mainnet).
- Sia (SC): pulled the standalone siawallet's lib into
bundled-addons/bchwallet/lib/sia/ and wrote lib/chain-sia.js exposing
the common adapter shape. The very first SC wallet the user adds in
Aegis reuses purpose "siawallet/mainnet/0" so pre-Aegis funds carry
over automatically; subsequent SC sub-accounts start at
"bchwallet/sc/mainnet/1". Per-wallet walletd URL setting; empty URL
shows a "Point Aegis at a walletd node" gate in the panel.
- Vault-derive gate now honors a manifest-declared `absorbs` list, so
Aegis's addon.json can list `absorbs: ["siawallet"]` and the derive()
guard accepts paths under either the current id or the absorbed one —
the mechanism a superseding add-on uses to inherit an older add-on's
keyspace without orphaning funds.
- DigiByte (DGB): lib/chain-dgb.js ports the relevant bits of the
SilentCode Digibyte design — SLIP-44 coin type 20, BIP84 native SegWit
(m/84'/20'/0'/0/x → dgb1q…) via ripemd160(sha256(pubkey)) + bech32.
ElectrumX-DGB backend reuses lib/electrum.js (public wss:50022 pool).
BIP143 P2WPKH sighash + witness-tx serialize implemented inline (no
FORKID — DGB uses standard Bitcoin sighash). Derivation cross-checked
against a known BIP39 vector in scratchpad/verify-dgb.mjs — the address
for "abandon×11 about, m/84'/20'/0'/0/0" is
dgb1q9gmf0pv8jdymcly6lz6fl7lf6mhslsd72e2jq8, matching iancoleman.io/bip39.
- Panel: SVG coin logos for SC (green disc with S) and DGB (blue
octagon with D) alongside the BCH/TRX marks. Chain-specific settings
block per coin (walletd URL for SC; derivation path for DGB). Balance
render uses BigInt-safe arithmetic so 24-decimal SC amounts don't
lose precision on the way through the panel; amount input on SC
returns a hastings string.
- Every chain adapter's snapshot fits the panel's shared shape
(address/balance/history/etc.), so future chains only need a new
chain-<x>.js file, a COINS registry entry, a matching case in
mountWallet, and an SVG logo.
Standalone siawallet addon stays as-is on disk; users can delete it once
they've confirmed Aegis shows the same balance. Nothing here disables it.
2026-09-07 01:56:25 +02:00
const { blake2b } = await api . import ( "@noble/hashes/blake2.js" ) ;
feat(theseus/bchwallet): receive + history — vault-derived keys, cashaddr, QR, electrum
Wallet core on mainnet:
- keys from api.vault.derive("bchwallet/mainnet/0") -> BIP32 m/44'/145'/0'
(@scure/bip32), never persisted; wiped on deactivate.
- lib/cashaddr.js (encode/decode + legacy Base58Check, spec vectors pass),
lib/keys.js (hash160, p2pkh, electrum scripthash, ECDSA DER + BIP-137
recoverable signing), lib/tx.js (serialization, SIGHASH_ALL|FORKID
digest, coin selection, fee estimate), lib/electrum.js (Fulcrum WSS
client with failover + subscriptions), lib/wallet.js (gap-limit scan,
balance, UTXOs, 25-tx history with per-tx deltas, cached public txs).
- qr.js: dependency-free QR encoder (byte mode, v1-10, EC M/L; verified
against jsQR).
- panel: balance header, Receive (QR, copy, next unused address, explorer),
History (deltas, confirmations, explorer links), Settings (derivation
path, electrum server list, xpub / approval-gated xprv reveal). Locked
and not-set-up vault states explained in-panel.
- host: api.import for ESM-only deps, api.openTab for explorer links; an
add-on whose activate() throws is no longer listed twice.
2026-09-06 02:46:41 +02:00
const { HDKey } = await api . import ( "@scure/bip32" ) ;
const WebSocket = api . require ( "ws" ) ;
const cashaddr = require ( "./lib/cashaddr.js" ) ;
const keysLib = require ( "./lib/keys.js" ) ( { HDKey , secp256k1 , sha256 , ripemd160 , cashaddr } ) ;
const tx = require ( "./lib/tx.js" ) ( { sha256 } ) ;
const electrum = require ( "./lib/electrum.js" ) ( { WebSocket , log : ( ... a ) => api . log ( "electrum" , ... a ) } ) ;
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
const base58check = require ( "./lib/base58check.js" ) ( { sha256 } ) ;
const bchAdapter = require ( "./lib/chain-bch.js" ) ( {
HDKey , secp256k1 , sha256 , ripemd160 , cashaddr , keysLib , tx , electrum , WebSocket ,
} ) ;
const tronAdapter = require ( "./lib/chain-tron.js" ) ( {
HDKey , secp256k1 , sha256 , keccak _256 , base58check ,
} ) ;
feat(theseus/aegis): fold Sia into the addon; add DGB (BIP84 native SegWit)
Aegis now covers four coins across two-step coin+network picks: BCH
(mainnet + chipnet), TRX (mainnet + Nile), SC (mainnet), DGB (mainnet).
- Sia (SC): pulled the standalone siawallet's lib into
bundled-addons/bchwallet/lib/sia/ and wrote lib/chain-sia.js exposing
the common adapter shape. The very first SC wallet the user adds in
Aegis reuses purpose "siawallet/mainnet/0" so pre-Aegis funds carry
over automatically; subsequent SC sub-accounts start at
"bchwallet/sc/mainnet/1". Per-wallet walletd URL setting; empty URL
shows a "Point Aegis at a walletd node" gate in the panel.
- Vault-derive gate now honors a manifest-declared `absorbs` list, so
Aegis's addon.json can list `absorbs: ["siawallet"]` and the derive()
guard accepts paths under either the current id or the absorbed one —
the mechanism a superseding add-on uses to inherit an older add-on's
keyspace without orphaning funds.
- DigiByte (DGB): lib/chain-dgb.js ports the relevant bits of the
SilentCode Digibyte design — SLIP-44 coin type 20, BIP84 native SegWit
(m/84'/20'/0'/0/x → dgb1q…) via ripemd160(sha256(pubkey)) + bech32.
ElectrumX-DGB backend reuses lib/electrum.js (public wss:50022 pool).
BIP143 P2WPKH sighash + witness-tx serialize implemented inline (no
FORKID — DGB uses standard Bitcoin sighash). Derivation cross-checked
against a known BIP39 vector in scratchpad/verify-dgb.mjs — the address
for "abandon×11 about, m/84'/20'/0'/0/0" is
dgb1q9gmf0pv8jdymcly6lz6fl7lf6mhslsd72e2jq8, matching iancoleman.io/bip39.
- Panel: SVG coin logos for SC (green disc with S) and DGB (blue
octagon with D) alongside the BCH/TRX marks. Chain-specific settings
block per coin (walletd URL for SC; derivation path for DGB). Balance
render uses BigInt-safe arithmetic so 24-decimal SC amounts don't
lose precision on the way through the panel; amount input on SC
returns a hastings string.
- Every chain adapter's snapshot fits the panel's shared shape
(address/balance/history/etc.), so future chains only need a new
chain-<x>.js file, a COINS registry entry, a matching case in
mountWallet, and an SVG logo.
Standalone siawallet addon stays as-is on disk; users can delete it once
they've confirmed Aegis shows the same balance. Nothing here disables it.
2026-09-07 01:56:25 +02:00
const siaAdapter = require ( "./lib/chain-sia.js" ) ( { ed25519 , blake2b } ) ;
feat(theseus/aegis): Ethereum + Solana adapters, DGB address-family picker, Aegis-branded shield
Multi-currency coverage matches what aegis.x has been advertising: BCH,
TRX, SC, DGB, ETH, SOL — six coins, two-step coin/network picker for
each. Panel logos, favicon and fallback all read as Aegis.
- Ethereum (lib/chain-eth.js): mainnet + Sepolia. BIP44 m/44'/60'/0'/0/0
→ secp256k1 → EIP-55 checksummed hex address (verified against
MetaMask's canonical abandon×11 vector 0x9858EfFD23…4EcaEda94). JSON-RPC
backend (Cloudflare mainnet, PublicNode Sepolia by default; per-wallet
override). EIP-1559 send with an inline RLP encoder + secp256k1
recoverable sign; broadcast via eth_sendRawTransaction. personal_sign
message signing follows the \x19Ethereum Signed Message:\n prefix.
- Solana (lib/chain-sol.js): mainnet-beta + devnet. SLIP-0010 ed25519
derivation at m/44'/501'/0'/0' (all-hardened), base58 address (@noble
ed25519). SLIP-0010 layer verified against spec Test Vector 1 in
scratchpad/verify-slip10.mjs. Native SOL transfer via the system
program with compact-u16 message serialization + ed25519 sign +
sendTransaction. Devnet gets a faucet.solana.com link in Receive; the
panel appends ?cluster=devnet when opening the explorer.
- DGB address family selector (lib/chain-dgb.js already carried the
paths): the Settings block now shows a Native SegWit / Taproot /
Wrapped SegWit / Legacy P2PKH picker. Selecting a family auto-fills
the derivation-path input with that family's default; Apply
rebuilds the wallet against the new path. Address families exposed
via chainMeta.addressFamilies so the panel can render them from data.
- Panel branding: inline SVG shield (hexagonal aspis, same silhouette
as the aegis.x hero) replaces the "?" fallback in logoSvg() and is
what the header shows before a wallet is selected. Data-URI favicon
wired into panel.html so the Theseus sidebar tab icon reads as Aegis
rather than a chain-specific coin mark.
- QR payloads now follow each chain's own URI scheme (BIP21 for BCH/DGB,
EIP-681 for ETH, Solana Pay for SOL) so external scanners route the
scan to the right wallet.
Not shipped: EIP-1193 provider (window.ethereum) and wallet-adapter
protocol (window.solana). The signing paths exist; only the page-inject
bridge glue is missing. History for ETH/SOL is also empty in this rev —
both need indexer plumbing (Etherscan V2 for ETH, getSignaturesForAddress
+ getTransaction pagination for SOL).
2026-09-07 20:31:27 +02:00
const ethAdapter = require ( "./lib/chain-eth.js" ) ( { HDKey , secp256k1 , keccak _256 } ) ;
// Solana uses the raw base58 alphabet (no checksum), which lives inside
// base58check as encodeBase58 / decodeBase58 — expose them under a
// `{encode, decode}` shape the SOL adapter reads from.
const solBase58 = { encode : base58check . encodeBase58 , decode : base58check . decodeBase58 } ;
const solAdapter = require ( "./lib/chain-sol.js" ) ( { ed25519 , base58 : solBase58 } ) ;
feat(theseus/aegis): DGB adapter on @dgb-wallet/{core,psbt} vendored packages
Aegis now shares its DGB code with the standalone DigiByte web-wallet at
D:\Dev\SilentCode\Digibyte. Address derivation and PSBT construction come
from that project's @dgb-wallet/core and @dgb-wallet/psbt packages instead
of Aegis-local reimplementations. Any bugfix upstream flows in via a
re-vendor of dist/*.
- lib/dgb/{core,psbt}/ — vendored dist/ output of the two packages plus
a tiny package.json shim marking them as ESM. @dgb-wallet/core's own
import specifier "@dgb-wallet/core" inside psbt/*.js is rewritten to
"../core/index.js" so the sibling module resolves without a workspace.
- New Theseus deps: bitcoinjs-lib, bip32, bip39, @bitcoinerlab/secp256k1,
ecpair — the peer deps the vendored packages need. Loaded via
api.require in index.js's loadDeps().
- chain-dgb.js is a thin adapter now: BIP32 tree via bip32 + DGB
Network object, addresses via core.p2wpkhAddress, tx via
psbt.buildPsbt + PSBT.signInput (per-input, since each UTXO's key
differs) + psbt.finalizeAndExtract. Runtime backend stays the same —
Theseus's lib/electrum.js against the DGB ElectrumX pool.
- Verified end-to-end in scratchpad: abandon×11 mnemonic derives
dgb1q9gmf0pv8jdymcly6lz6fl7lf6mhslsd72e2jq8 (matches iancoleman.io/bip39
and the previous inline implementation, so no on-chain address change
for anyone who was already using Aegis's DGB slot). PSBT build+sign+
finalize on a mock UTXO produces a valid 223-byte witness tx.
BIP44 (D…) and BIP49 (S…) address families are implemented in the
vendored core but not yet exposed in Aegis's picker — the panel needs
an "address family" selector inside the DGB settings block first. Left
for a follow-up; today's DGB pick uses BIP84 native SegWit only.
2026-09-07 02:19:44 +02:00
// DGB delegates address derivation + PSBT to the vendored @dgb-wallet/*
// packages under lib/dgb/. Those are ESM; the peer deps (bitcoinjs-lib,
// bip32, ecpair, @bitcoinerlab/secp256k1) are CommonJS and reachable via
// api.require from the Theseus dependency tree.
const { pathToFileURL } = require ( "node:url" ) ;
const dgbCore = await import ( pathToFileURL ( path . join ( api . folder , "lib/dgb/core/index.js" ) ) . href ) ;
const dgbPsbt = await import ( pathToFileURL ( path . join ( api . folder , "lib/dgb/psbt/index.js" ) ) . href ) ;
const bitcoinjs = api . require ( "bitcoinjs-lib" ) ;
const { BIP32Factory } = api . require ( "bip32" ) ;
const { ECPairFactory } = api . require ( "ecpair" ) ;
const ecc = api . require ( "@bitcoinerlab/secp256k1" ) ;
feat(theseus/aegis): fold Sia into the addon; add DGB (BIP84 native SegWit)
Aegis now covers four coins across two-step coin+network picks: BCH
(mainnet + chipnet), TRX (mainnet + Nile), SC (mainnet), DGB (mainnet).
- Sia (SC): pulled the standalone siawallet's lib into
bundled-addons/bchwallet/lib/sia/ and wrote lib/chain-sia.js exposing
the common adapter shape. The very first SC wallet the user adds in
Aegis reuses purpose "siawallet/mainnet/0" so pre-Aegis funds carry
over automatically; subsequent SC sub-accounts start at
"bchwallet/sc/mainnet/1". Per-wallet walletd URL setting; empty URL
shows a "Point Aegis at a walletd node" gate in the panel.
- Vault-derive gate now honors a manifest-declared `absorbs` list, so
Aegis's addon.json can list `absorbs: ["siawallet"]` and the derive()
guard accepts paths under either the current id or the absorbed one —
the mechanism a superseding add-on uses to inherit an older add-on's
keyspace without orphaning funds.
- DigiByte (DGB): lib/chain-dgb.js ports the relevant bits of the
SilentCode Digibyte design — SLIP-44 coin type 20, BIP84 native SegWit
(m/84'/20'/0'/0/x → dgb1q…) via ripemd160(sha256(pubkey)) + bech32.
ElectrumX-DGB backend reuses lib/electrum.js (public wss:50022 pool).
BIP143 P2WPKH sighash + witness-tx serialize implemented inline (no
FORKID — DGB uses standard Bitcoin sighash). Derivation cross-checked
against a known BIP39 vector in scratchpad/verify-dgb.mjs — the address
for "abandon×11 about, m/84'/20'/0'/0/0" is
dgb1q9gmf0pv8jdymcly6lz6fl7lf6mhslsd72e2jq8, matching iancoleman.io/bip39.
- Panel: SVG coin logos for SC (green disc with S) and DGB (blue
octagon with D) alongside the BCH/TRX marks. Chain-specific settings
block per coin (walletd URL for SC; derivation path for DGB). Balance
render uses BigInt-safe arithmetic so 24-decimal SC amounts don't
lose precision on the way through the panel; amount input on SC
returns a hastings string.
- Every chain adapter's snapshot fits the panel's shared shape
(address/balance/history/etc.), so future chains only need a new
chain-<x>.js file, a COINS registry entry, a matching case in
mountWallet, and an SVG logo.
Standalone siawallet addon stays as-is on disk; users can delete it once
they've confirmed Aegis shows the same balance. Nothing here disables it.
2026-09-07 01:56:25 +02:00
const dgbAdapter = require ( "./lib/chain-dgb.js" ) ( {
feat(theseus/aegis): DGB adapter on @dgb-wallet/{core,psbt} vendored packages
Aegis now shares its DGB code with the standalone DigiByte web-wallet at
D:\Dev\SilentCode\Digibyte. Address derivation and PSBT construction come
from that project's @dgb-wallet/core and @dgb-wallet/psbt packages instead
of Aegis-local reimplementations. Any bugfix upstream flows in via a
re-vendor of dist/*.
- lib/dgb/{core,psbt}/ — vendored dist/ output of the two packages plus
a tiny package.json shim marking them as ESM. @dgb-wallet/core's own
import specifier "@dgb-wallet/core" inside psbt/*.js is rewritten to
"../core/index.js" so the sibling module resolves without a workspace.
- New Theseus deps: bitcoinjs-lib, bip32, bip39, @bitcoinerlab/secp256k1,
ecpair — the peer deps the vendored packages need. Loaded via
api.require in index.js's loadDeps().
- chain-dgb.js is a thin adapter now: BIP32 tree via bip32 + DGB
Network object, addresses via core.p2wpkhAddress, tx via
psbt.buildPsbt + PSBT.signInput (per-input, since each UTXO's key
differs) + psbt.finalizeAndExtract. Runtime backend stays the same —
Theseus's lib/electrum.js against the DGB ElectrumX pool.
- Verified end-to-end in scratchpad: abandon×11 mnemonic derives
dgb1q9gmf0pv8jdymcly6lz6fl7lf6mhslsd72e2jq8 (matches iancoleman.io/bip39
and the previous inline implementation, so no on-chain address change
for anyone who was already using Aegis's DGB slot). PSBT build+sign+
finalize on a mock UTXO produces a valid 223-byte witness tx.
BIP44 (D…) and BIP49 (S…) address families are implemented in the
vendored core but not yet exposed in Aegis's picker — the panel needs
an "address family" selector inside the DGB settings block first. Left
for a follow-up; today's DGB pick uses BIP84 native SegWit only.
2026-09-07 02:19:44 +02:00
dgbCore , dgbPsbt , bitcoinjs ,
bip32Factory : BIP32Factory , ecpairFactory : ECPairFactory , ecc ,
sha256 , electrum ,
feat(theseus/aegis): fold Sia into the addon; add DGB (BIP84 native SegWit)
Aegis now covers four coins across two-step coin+network picks: BCH
(mainnet + chipnet), TRX (mainnet + Nile), SC (mainnet), DGB (mainnet).
- Sia (SC): pulled the standalone siawallet's lib into
bundled-addons/bchwallet/lib/sia/ and wrote lib/chain-sia.js exposing
the common adapter shape. The very first SC wallet the user adds in
Aegis reuses purpose "siawallet/mainnet/0" so pre-Aegis funds carry
over automatically; subsequent SC sub-accounts start at
"bchwallet/sc/mainnet/1". Per-wallet walletd URL setting; empty URL
shows a "Point Aegis at a walletd node" gate in the panel.
- Vault-derive gate now honors a manifest-declared `absorbs` list, so
Aegis's addon.json can list `absorbs: ["siawallet"]` and the derive()
guard accepts paths under either the current id or the absorbed one —
the mechanism a superseding add-on uses to inherit an older add-on's
keyspace without orphaning funds.
- DigiByte (DGB): lib/chain-dgb.js ports the relevant bits of the
SilentCode Digibyte design — SLIP-44 coin type 20, BIP84 native SegWit
(m/84'/20'/0'/0/x → dgb1q…) via ripemd160(sha256(pubkey)) + bech32.
ElectrumX-DGB backend reuses lib/electrum.js (public wss:50022 pool).
BIP143 P2WPKH sighash + witness-tx serialize implemented inline (no
FORKID — DGB uses standard Bitcoin sighash). Derivation cross-checked
against a known BIP39 vector in scratchpad/verify-dgb.mjs — the address
for "abandon×11 about, m/84'/20'/0'/0/0" is
dgb1q9gmf0pv8jdymcly6lz6fl7lf6mhslsd72e2jq8, matching iancoleman.io/bip39.
- Panel: SVG coin logos for SC (green disc with S) and DGB (blue
octagon with D) alongside the BCH/TRX marks. Chain-specific settings
block per coin (walletd URL for SC; derivation path for DGB). Balance
render uses BigInt-safe arithmetic so 24-decimal SC amounts don't
lose precision on the way through the panel; amount input on SC
returns a hastings string.
- Every chain adapter's snapshot fits the panel's shared shape
(address/balance/history/etc.), so future chains only need a new
chain-<x>.js file, a COINS registry entry, a matching case in
mountWallet, and an SVG logo.
Standalone siawallet addon stays as-is on disk; users can delete it once
they've confirmed Aegis shows the same balance. Nothing here disables it.
2026-09-07 01:56:25 +02:00
} ) ;
feat(theseus/aegis): Bitcoin adapter (mainnet + testnet3, BIP84 native SegWit)
Seven coins across twelve networks now — BTC joins the shipping roster.
- lib/chain-btc.js: BIP84 native SegWit — m/84'/0'/0'/0/x → bc1q…
(mainnet), m/84'/1'/0'/0/x → tb1q… (testnet3). Reuses the exact same
stack the DGB adapter already pulls in: bitcoinjs-lib for network
params + payments.p2wpkh + PSBT, bip32 for HD derivation, ecpair for
the Signer interface, ecc (@bitcoinerlab/secp256k1) for message-sign
recoverable sigs. No new npm deps.
- Backend: same lib/electrum.js Aegis uses for BCH and DGB — plugged
into a public Bitcoin ElectrumX pool (blockstream.info, lu.ke,
grey.pw) for mainnet and aranguren.org / blockstream.info:993 for
testnet3. Send flow: PSBT build + per-input signInput +
finalizeAllInputs + broadcast. BIP-137 recoverable message signing.
- Registered as btc:mainnet + btc:testnet in COINS with the orange
Bitcoin disc SVG logo. Mount case mirrors DGB (accountPath honored,
so switching to m/44'/0'/0' or m/49'/0'/0' via the setAccountPath
message gives legacy 1… or wrapped-segwit 3… — same one-line UI plumb
as the DGB address-family selector, deferred to a follow-up).
- Panel: sat as the small-unit label, bitcoin: BIP21 QR payload,
chain-aware send placeholder ("bc1q…" mainnet / "tb1q…" testnet).
- Verified: BIP84 spec test vector — abandon×11 mnemonic derives
bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu at m/84'/0'/0'/0/0
(byte-identical to the vector in the BIP text). Testnet variant
produces tb1q6rz28mcfaxtmd6v789l9rrlrusdprr9pqcpvkl at m/84'/1'/0'/0/0
(cross-checkable on iancoleman.io/bip39 with coin BTC Testnet).
2026-09-07 21:15:45 +02:00
const btcAdapter = require ( "./lib/chain-btc.js" ) ( {
bitcoinjs , bip32Factory : BIP32Factory , ecpairFactory : ECPairFactory , ecc ,
sha256 , electrum ,
} ) ;
feat(theseus/aegis): DGB adapter on @dgb-wallet/{core,psbt} vendored packages
Aegis now shares its DGB code with the standalone DigiByte web-wallet at
D:\Dev\SilentCode\Digibyte. Address derivation and PSBT construction come
from that project's @dgb-wallet/core and @dgb-wallet/psbt packages instead
of Aegis-local reimplementations. Any bugfix upstream flows in via a
re-vendor of dist/*.
- lib/dgb/{core,psbt}/ — vendored dist/ output of the two packages plus
a tiny package.json shim marking them as ESM. @dgb-wallet/core's own
import specifier "@dgb-wallet/core" inside psbt/*.js is rewritten to
"../core/index.js" so the sibling module resolves without a workspace.
- New Theseus deps: bitcoinjs-lib, bip32, bip39, @bitcoinerlab/secp256k1,
ecpair — the peer deps the vendored packages need. Loaded via
api.require in index.js's loadDeps().
- chain-dgb.js is a thin adapter now: BIP32 tree via bip32 + DGB
Network object, addresses via core.p2wpkhAddress, tx via
psbt.buildPsbt + PSBT.signInput (per-input, since each UTXO's key
differs) + psbt.finalizeAndExtract. Runtime backend stays the same —
Theseus's lib/electrum.js against the DGB ElectrumX pool.
- Verified end-to-end in scratchpad: abandon×11 mnemonic derives
dgb1q9gmf0pv8jdymcly6lz6fl7lf6mhslsd72e2jq8 (matches iancoleman.io/bip39
and the previous inline implementation, so no on-chain address change
for anyone who was already using Aegis's DGB slot). PSBT build+sign+
finalize on a mock UTXO produces a valid 223-byte witness tx.
BIP44 (D…) and BIP49 (S…) address families are implemented in the
vendored core but not yet exposed in Aegis's picker — the panel needs
an "address family" selector inside the DGB settings block first. Left
for a follow-up; today's DGB pick uses BIP84 native SegWit only.
2026-09-07 02:19:44 +02:00
return { HDKey , secp256k1 , ed25519 , sha256 , ripemd160 , keccak _256 , blake2b ,
feat(theseus/aegis): fold Sia into the addon; add DGB (BIP84 native SegWit)
Aegis now covers four coins across two-step coin+network picks: BCH
(mainnet + chipnet), TRX (mainnet + Nile), SC (mainnet), DGB (mainnet).
- Sia (SC): pulled the standalone siawallet's lib into
bundled-addons/bchwallet/lib/sia/ and wrote lib/chain-sia.js exposing
the common adapter shape. The very first SC wallet the user adds in
Aegis reuses purpose "siawallet/mainnet/0" so pre-Aegis funds carry
over automatically; subsequent SC sub-accounts start at
"bchwallet/sc/mainnet/1". Per-wallet walletd URL setting; empty URL
shows a "Point Aegis at a walletd node" gate in the panel.
- Vault-derive gate now honors a manifest-declared `absorbs` list, so
Aegis's addon.json can list `absorbs: ["siawallet"]` and the derive()
guard accepts paths under either the current id or the absorbed one —
the mechanism a superseding add-on uses to inherit an older add-on's
keyspace without orphaning funds.
- DigiByte (DGB): lib/chain-dgb.js ports the relevant bits of the
SilentCode Digibyte design — SLIP-44 coin type 20, BIP84 native SegWit
(m/84'/20'/0'/0/x → dgb1q…) via ripemd160(sha256(pubkey)) + bech32.
ElectrumX-DGB backend reuses lib/electrum.js (public wss:50022 pool).
BIP143 P2WPKH sighash + witness-tx serialize implemented inline (no
FORKID — DGB uses standard Bitcoin sighash). Derivation cross-checked
against a known BIP39 vector in scratchpad/verify-dgb.mjs — the address
for "abandon×11 about, m/84'/20'/0'/0/0" is
dgb1q9gmf0pv8jdymcly6lz6fl7lf6mhslsd72e2jq8, matching iancoleman.io/bip39.
- Panel: SVG coin logos for SC (green disc with S) and DGB (blue
octagon with D) alongside the BCH/TRX marks. Chain-specific settings
block per coin (walletd URL for SC; derivation path for DGB). Balance
render uses BigInt-safe arithmetic so 24-decimal SC amounts don't
lose precision on the way through the panel; amount input on SC
returns a hastings string.
- Every chain adapter's snapshot fits the panel's shared shape
(address/balance/history/etc.), so future chains only need a new
chain-<x>.js file, a COINS registry entry, a matching case in
mountWallet, and an SVG logo.
Standalone siawallet addon stays as-is on disk; users can delete it once
they've confirmed Aegis shows the same balance. Nothing here disables it.
2026-09-07 01:56:25 +02:00
cashaddr , keysLib , tx , electrum , base58check ,
feat(theseus/aegis): Bitcoin adapter (mainnet + testnet3, BIP84 native SegWit)
Seven coins across twelve networks now — BTC joins the shipping roster.
- lib/chain-btc.js: BIP84 native SegWit — m/84'/0'/0'/0/x → bc1q…
(mainnet), m/84'/1'/0'/0/x → tb1q… (testnet3). Reuses the exact same
stack the DGB adapter already pulls in: bitcoinjs-lib for network
params + payments.p2wpkh + PSBT, bip32 for HD derivation, ecpair for
the Signer interface, ecc (@bitcoinerlab/secp256k1) for message-sign
recoverable sigs. No new npm deps.
- Backend: same lib/electrum.js Aegis uses for BCH and DGB — plugged
into a public Bitcoin ElectrumX pool (blockstream.info, lu.ke,
grey.pw) for mainnet and aranguren.org / blockstream.info:993 for
testnet3. Send flow: PSBT build + per-input signInput +
finalizeAllInputs + broadcast. BIP-137 recoverable message signing.
- Registered as btc:mainnet + btc:testnet in COINS with the orange
Bitcoin disc SVG logo. Mount case mirrors DGB (accountPath honored,
so switching to m/44'/0'/0' or m/49'/0'/0' via the setAccountPath
message gives legacy 1… or wrapped-segwit 3… — same one-line UI plumb
as the DGB address-family selector, deferred to a follow-up).
- Panel: sat as the small-unit label, bitcoin: BIP21 QR payload,
chain-aware send placeholder ("bc1q…" mainnet / "tb1q…" testnet).
- Verified: BIP84 spec test vector — abandon×11 mnemonic derives
bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu at m/84'/0'/0'/0/0
(byte-identical to the vector in the BIP text). Testnet variant
produces tb1q6rz28mcfaxtmd6v789l9rrlrusdprr9pqcpvkl at m/84'/1'/0'/0/0
(cross-checkable on iancoleman.io/bip39 with coin BTC Testnet).
2026-09-07 21:15:45 +02:00
bchAdapter , tronAdapter , siaAdapter , dgbAdapter , ethAdapter , solAdapter , btcAdapter ,
feat(theseus/aegis): DGB adapter on @dgb-wallet/{core,psbt} vendored packages
Aegis now shares its DGB code with the standalone DigiByte web-wallet at
D:\Dev\SilentCode\Digibyte. Address derivation and PSBT construction come
from that project's @dgb-wallet/core and @dgb-wallet/psbt packages instead
of Aegis-local reimplementations. Any bugfix upstream flows in via a
re-vendor of dist/*.
- lib/dgb/{core,psbt}/ — vendored dist/ output of the two packages plus
a tiny package.json shim marking them as ESM. @dgb-wallet/core's own
import specifier "@dgb-wallet/core" inside psbt/*.js is rewritten to
"../core/index.js" so the sibling module resolves without a workspace.
- New Theseus deps: bitcoinjs-lib, bip32, bip39, @bitcoinerlab/secp256k1,
ecpair — the peer deps the vendored packages need. Loaded via
api.require in index.js's loadDeps().
- chain-dgb.js is a thin adapter now: BIP32 tree via bip32 + DGB
Network object, addresses via core.p2wpkhAddress, tx via
psbt.buildPsbt + PSBT.signInput (per-input, since each UTXO's key
differs) + psbt.finalizeAndExtract. Runtime backend stays the same —
Theseus's lib/electrum.js against the DGB ElectrumX pool.
- Verified end-to-end in scratchpad: abandon×11 mnemonic derives
dgb1q9gmf0pv8jdymcly6lz6fl7lf6mhslsd72e2jq8 (matches iancoleman.io/bip39
and the previous inline implementation, so no on-chain address change
for anyone who was already using Aegis's DGB slot). PSBT build+sign+
finalize on a mock UTXO produces a valid 223-byte witness tx.
BIP44 (D…) and BIP49 (S…) address families are implemented in the
vendored core but not yet exposed in Aegis's picker — the panel needs
an "address family" selector inside the DGB settings block first. Left
for a follow-up; today's DGB pick uses BIP84 native SegWit only.
2026-09-07 02:19:44 +02:00
dgbCore , dgbPsbt , bitcoinjs , ecc } ;
feat(theseus/bchwallet): receive + history — vault-derived keys, cashaddr, QR, electrum
Wallet core on mainnet:
- keys from api.vault.derive("bchwallet/mainnet/0") -> BIP32 m/44'/145'/0'
(@scure/bip32), never persisted; wiped on deactivate.
- lib/cashaddr.js (encode/decode + legacy Base58Check, spec vectors pass),
lib/keys.js (hash160, p2pkh, electrum scripthash, ECDSA DER + BIP-137
recoverable signing), lib/tx.js (serialization, SIGHASH_ALL|FORKID
digest, coin selection, fee estimate), lib/electrum.js (Fulcrum WSS
client with failover + subscriptions), lib/wallet.js (gap-limit scan,
balance, UTXOs, 25-tx history with per-tx deltas, cached public txs).
- qr.js: dependency-free QR encoder (byte mode, v1-10, EC M/L; verified
against jsQR).
- panel: balance header, Receive (QR, copy, next unused address, explorer),
History (deltas, confirmations, explorer links), Settings (derivation
path, electrum server list, xpub / approval-gated xprv reveal). Locked
and not-set-up vault states explained in-panel.
- host: api.import for ESM-only deps, api.openTab for explorer links; an
add-on whose activate() throws is no longer listed twice.
2026-09-06 02:46:41 +02:00
}
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
// ---- servers ---------------------------------------------------------------
function bchDefaultServers ( api ) {
try { return JSON . parse ( fs . readFileSync ( path . join ( api . folder , "electrum-servers.json" ) , "utf8" ) ) ; }
catch { return [ ] ; }
}
function bchServerList ( api ) {
const custom = api . storage . get ( "servers" , null ) ;
return Array . isArray ( custom ) && custom . length ? custom : bchDefaultServers ( api ) ;
}
// ---- chain registry --------------------------------------------------------
feat(theseus/aegis): SVG coin logos, two-step coin/network picker, BCH Chipnet
- Inline SVG logos for BCH (green disc + ₿) and TRX (red disc + geometric T)
replace the 🟨/🔴/🔵 emoji in the sidebar header and wallet picker rows.
The approval overlay stays text-only ("Wallet: <name> — BCH · Mainnet")
because that surface renders plain rows, not HTML.
- Wallet picker's "Add wallet" is now two-step: click a coin to expand its
networks, then click a network to create the wallet. The flat list is gone.
- BCH Chipnet is a real chain option now: bchtest cashaddr prefix,
m/44'/1'/0' derivation (BIP44 testnet coin type), bundled Chipnet electrum
defaults, chipnet.imaginary.cash explorer, tbch.googol.cash faucet link
in Receive. The shared electrum-servers setting stays mainnet-only in
this rev; Chipnet uses adapter-embedded defaults.
- lib/chain-bch.js gained a BCH_NETWORKS table so mainnet vs chipnet
differences (prefix, path, servers, explorer, faucet) live in one place.
- Registry is grouped by coin ({networks:{…}}) instead of a flat
chain:network map — snapshot exposes coins[] for the panel and adds
coinLabel/networkLabel/testnet fields per wallet.
- Testnet wallets get a small "TEST" tag next to the network name so the
user can never mistake a chipnet or Nile balance for real money.
Legacy BCH mainnet index 0 derivation unchanged (bchwallet/mainnet/0 →
m/44'/145'/0' → bitcoincash prefix); the network parameter defaults to
"mainnet" and BCH_NETWORKS.mainnet reproduces the pre-change constants.
2026-09-07 01:07:31 +02:00
// Two-level structure so the panel can present coin-then-network as separate
// picks. `coin` fields are chain-wide; `networks[<id>]` fields override or
// add to them per-network. `logo` is the SVG key panel.js draws from.
const COINS = {
bch : {
chain : "bch" ,
label : "Bitcoin Cash" ,
short : "BCH" ,
ticker : "BCH" ,
decimals : 8 ,
color : "#0ac18e" ,
logo : "bch" ,
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
supportsMessageSign : true ,
supportsPageInject : true , // window.bitcoincash on *.x pages
feat(theseus/aegis): SVG coin logos, two-step coin/network picker, BCH Chipnet
- Inline SVG logos for BCH (green disc + ₿) and TRX (red disc + geometric T)
replace the 🟨/🔴/🔵 emoji in the sidebar header and wallet picker rows.
The approval overlay stays text-only ("Wallet: <name> — BCH · Mainnet")
because that surface renders plain rows, not HTML.
- Wallet picker's "Add wallet" is now two-step: click a coin to expand its
networks, then click a network to create the wallet. The flat list is gone.
- BCH Chipnet is a real chain option now: bchtest cashaddr prefix,
m/44'/1'/0' derivation (BIP44 testnet coin type), bundled Chipnet electrum
defaults, chipnet.imaginary.cash explorer, tbch.googol.cash faucet link
in Receive. The shared electrum-servers setting stays mainnet-only in
this rev; Chipnet uses adapter-embedded defaults.
- lib/chain-bch.js gained a BCH_NETWORKS table so mainnet vs chipnet
differences (prefix, path, servers, explorer, faucet) live in one place.
- Registry is grouped by coin ({networks:{…}}) instead of a flat
chain:network map — snapshot exposes coins[] for the panel and adds
coinLabel/networkLabel/testnet fields per wallet.
- Testnet wallets get a small "TEST" tag next to the network name so the
user can never mistake a chipnet or Nile balance for real money.
Legacy BCH mainnet index 0 derivation unchanged (bchwallet/mainnet/0 →
m/44'/145'/0' → bitcoincash prefix); the network parameter defaults to
"mainnet" and BCH_NETWORKS.mainnet reproduces the pre-change constants.
2026-09-07 01:07:31 +02:00
networks : {
mainnet : {
id : "mainnet" , label : "Mainnet" , testnet : false ,
// Legacy default wallet uses the flat "bchwallet/mainnet/0" purpose;
// new BCH mainnet sub-accounts start at index 1 under the /bch/ prefix.
purposePrefix : "bchwallet/bch/" ,
startIndex : 1 ,
} ,
chipnet : {
id : "chipnet" , label : "Chipnet testnet" , testnet : true ,
purposePrefix : "bchwallet/bch/chipnet/" ,
startIndex : 0 ,
} ,
} ,
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
} ,
feat(theseus/aegis): SVG coin logos, two-step coin/network picker, BCH Chipnet
- Inline SVG logos for BCH (green disc + ₿) and TRX (red disc + geometric T)
replace the 🟨/🔴/🔵 emoji in the sidebar header and wallet picker rows.
The approval overlay stays text-only ("Wallet: <name> — BCH · Mainnet")
because that surface renders plain rows, not HTML.
- Wallet picker's "Add wallet" is now two-step: click a coin to expand its
networks, then click a network to create the wallet. The flat list is gone.
- BCH Chipnet is a real chain option now: bchtest cashaddr prefix,
m/44'/1'/0' derivation (BIP44 testnet coin type), bundled Chipnet electrum
defaults, chipnet.imaginary.cash explorer, tbch.googol.cash faucet link
in Receive. The shared electrum-servers setting stays mainnet-only in
this rev; Chipnet uses adapter-embedded defaults.
- lib/chain-bch.js gained a BCH_NETWORKS table so mainnet vs chipnet
differences (prefix, path, servers, explorer, faucet) live in one place.
- Registry is grouped by coin ({networks:{…}}) instead of a flat
chain:network map — snapshot exposes coins[] for the panel and adds
coinLabel/networkLabel/testnet fields per wallet.
- Testnet wallets get a small "TEST" tag next to the network name so the
user can never mistake a chipnet or Nile balance for real money.
Legacy BCH mainnet index 0 derivation unchanged (bchwallet/mainnet/0 →
m/44'/145'/0' → bitcoincash prefix); the network parameter defaults to
"mainnet" and BCH_NETWORKS.mainnet reproduces the pre-change constants.
2026-09-07 01:07:31 +02:00
trx : {
chain : "trx" ,
label : "Tron" ,
short : "TRX" ,
ticker : "TRX" ,
decimals : 6 ,
color : "#ff060a" ,
logo : "trx" ,
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
supportsMessageSign : true ,
supportsPageInject : true , // window.tronWeb everywhere
feat(theseus/aegis): SVG coin logos, two-step coin/network picker, BCH Chipnet
- Inline SVG logos for BCH (green disc + ₿) and TRX (red disc + geometric T)
replace the 🟨/🔴/🔵 emoji in the sidebar header and wallet picker rows.
The approval overlay stays text-only ("Wallet: <name> — BCH · Mainnet")
because that surface renders plain rows, not HTML.
- Wallet picker's "Add wallet" is now two-step: click a coin to expand its
networks, then click a network to create the wallet. The flat list is gone.
- BCH Chipnet is a real chain option now: bchtest cashaddr prefix,
m/44'/1'/0' derivation (BIP44 testnet coin type), bundled Chipnet electrum
defaults, chipnet.imaginary.cash explorer, tbch.googol.cash faucet link
in Receive. The shared electrum-servers setting stays mainnet-only in
this rev; Chipnet uses adapter-embedded defaults.
- lib/chain-bch.js gained a BCH_NETWORKS table so mainnet vs chipnet
differences (prefix, path, servers, explorer, faucet) live in one place.
- Registry is grouped by coin ({networks:{…}}) instead of a flat
chain:network map — snapshot exposes coins[] for the panel and adds
coinLabel/networkLabel/testnet fields per wallet.
- Testnet wallets get a small "TEST" tag next to the network name so the
user can never mistake a chipnet or Nile balance for real money.
Legacy BCH mainnet index 0 derivation unchanged (bchwallet/mainnet/0 →
m/44'/145'/0' → bitcoincash prefix); the network parameter defaults to
"mainnet" and BCH_NETWORKS.mainnet reproduces the pre-change constants.
2026-09-07 01:07:31 +02:00
networks : {
mainnet : {
id : "mainnet" , label : "Mainnet" , testnet : false ,
purposePrefix : "bchwallet/trx/mainnet/" , startIndex : 0 ,
} ,
nile : {
id : "nile" , label : "Nile testnet" , testnet : true ,
purposePrefix : "bchwallet/trx/nile/" , startIndex : 0 ,
} ,
} ,
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
} ,
feat(theseus/aegis): fold Sia into the addon; add DGB (BIP84 native SegWit)
Aegis now covers four coins across two-step coin+network picks: BCH
(mainnet + chipnet), TRX (mainnet + Nile), SC (mainnet), DGB (mainnet).
- Sia (SC): pulled the standalone siawallet's lib into
bundled-addons/bchwallet/lib/sia/ and wrote lib/chain-sia.js exposing
the common adapter shape. The very first SC wallet the user adds in
Aegis reuses purpose "siawallet/mainnet/0" so pre-Aegis funds carry
over automatically; subsequent SC sub-accounts start at
"bchwallet/sc/mainnet/1". Per-wallet walletd URL setting; empty URL
shows a "Point Aegis at a walletd node" gate in the panel.
- Vault-derive gate now honors a manifest-declared `absorbs` list, so
Aegis's addon.json can list `absorbs: ["siawallet"]` and the derive()
guard accepts paths under either the current id or the absorbed one —
the mechanism a superseding add-on uses to inherit an older add-on's
keyspace without orphaning funds.
- DigiByte (DGB): lib/chain-dgb.js ports the relevant bits of the
SilentCode Digibyte design — SLIP-44 coin type 20, BIP84 native SegWit
(m/84'/20'/0'/0/x → dgb1q…) via ripemd160(sha256(pubkey)) + bech32.
ElectrumX-DGB backend reuses lib/electrum.js (public wss:50022 pool).
BIP143 P2WPKH sighash + witness-tx serialize implemented inline (no
FORKID — DGB uses standard Bitcoin sighash). Derivation cross-checked
against a known BIP39 vector in scratchpad/verify-dgb.mjs — the address
for "abandon×11 about, m/84'/20'/0'/0/0" is
dgb1q9gmf0pv8jdymcly6lz6fl7lf6mhslsd72e2jq8, matching iancoleman.io/bip39.
- Panel: SVG coin logos for SC (green disc with S) and DGB (blue
octagon with D) alongside the BCH/TRX marks. Chain-specific settings
block per coin (walletd URL for SC; derivation path for DGB). Balance
render uses BigInt-safe arithmetic so 24-decimal SC amounts don't
lose precision on the way through the panel; amount input on SC
returns a hastings string.
- Every chain adapter's snapshot fits the panel's shared shape
(address/balance/history/etc.), so future chains only need a new
chain-<x>.js file, a COINS registry entry, a matching case in
mountWallet, and an SVG logo.
Standalone siawallet addon stays as-is on disk; users can delete it once
they've confirmed Aegis shows the same balance. Nothing here disables it.
2026-09-07 01:56:25 +02:00
sc : {
chain : "sc" ,
label : "Siacoin" ,
short : "SC" ,
ticker : "SC" ,
decimals : 24 ,
color : "#20be82" ,
logo : "sc" ,
supportsMessageSign : true ,
supportsPageInject : false ,
// First SC wallet in Aegis reuses the legacy standalone-siawallet purpose
// so pre-Aegis funds carry over automatically (addon.json declares
// `absorbs: ["siawallet"]` to allow the derivation). Second+ use the new
// Aegis-namespaced prefix.
networks : {
mainnet : {
id : "mainnet" , label : "Mainnet" , testnet : false ,
purposePrefix : "bchwallet/sc/mainnet/" , startIndex : 1 ,
legacyFirstPurpose : "siawallet/mainnet/0" ,
} ,
} ,
} ,
dgb : {
chain : "dgb" ,
label : "DigiByte" ,
short : "DGB" ,
ticker : "DGB" ,
decimals : 8 ,
color : "#0066cc" ,
logo : "dgb" ,
supportsMessageSign : true ,
supportsPageInject : false ,
feat(theseus/aegis): Ethereum + Solana adapters, DGB address-family picker, Aegis-branded shield
Multi-currency coverage matches what aegis.x has been advertising: BCH,
TRX, SC, DGB, ETH, SOL — six coins, two-step coin/network picker for
each. Panel logos, favicon and fallback all read as Aegis.
- Ethereum (lib/chain-eth.js): mainnet + Sepolia. BIP44 m/44'/60'/0'/0/0
→ secp256k1 → EIP-55 checksummed hex address (verified against
MetaMask's canonical abandon×11 vector 0x9858EfFD23…4EcaEda94). JSON-RPC
backend (Cloudflare mainnet, PublicNode Sepolia by default; per-wallet
override). EIP-1559 send with an inline RLP encoder + secp256k1
recoverable sign; broadcast via eth_sendRawTransaction. personal_sign
message signing follows the \x19Ethereum Signed Message:\n prefix.
- Solana (lib/chain-sol.js): mainnet-beta + devnet. SLIP-0010 ed25519
derivation at m/44'/501'/0'/0' (all-hardened), base58 address (@noble
ed25519). SLIP-0010 layer verified against spec Test Vector 1 in
scratchpad/verify-slip10.mjs. Native SOL transfer via the system
program with compact-u16 message serialization + ed25519 sign +
sendTransaction. Devnet gets a faucet.solana.com link in Receive; the
panel appends ?cluster=devnet when opening the explorer.
- DGB address family selector (lib/chain-dgb.js already carried the
paths): the Settings block now shows a Native SegWit / Taproot /
Wrapped SegWit / Legacy P2PKH picker. Selecting a family auto-fills
the derivation-path input with that family's default; Apply
rebuilds the wallet against the new path. Address families exposed
via chainMeta.addressFamilies so the panel can render them from data.
- Panel branding: inline SVG shield (hexagonal aspis, same silhouette
as the aegis.x hero) replaces the "?" fallback in logoSvg() and is
what the header shows before a wallet is selected. Data-URI favicon
wired into panel.html so the Theseus sidebar tab icon reads as Aegis
rather than a chain-specific coin mark.
- QR payloads now follow each chain's own URI scheme (BIP21 for BCH/DGB,
EIP-681 for ETH, Solana Pay for SOL) so external scanners route the
scan to the right wallet.
Not shipped: EIP-1193 provider (window.ethereum) and wallet-adapter
protocol (window.solana). The signing paths exist; only the page-inject
bridge glue is missing. History for ETH/SOL is also empty in this rev —
both need indexer plumbing (Etherscan V2 for ETH, getSignaturesForAddress
+ getTransaction pagination for SOL).
2026-09-07 20:31:27 +02:00
// BIP44/49/84/86 address families — the picker lives in the DGB
// settings block. Default is BIP84 (dgb1q…), which matches modern
feat(theseus/aegis): BTC address-family picker (BIP44/49/84/86 + Taproot)
BTC now matches DGB's family selector: pick BIP44 (1…), BIP49 (3…),
BIP84 (bc1q…, default) or BIP86 Taproot (bc1p…) from Settings, on
mainnet or testnet3 (paths shift coin type 0 → 1 automatically).
- lib/chain-btc.js: paymentFor(purpose, node, network) returns the
right bitcoinjs-lib payment (p2pkh / p2sh(p2wpkh) / p2wpkh / p2tr)
keyed off the derivation path's purpose. WalletKeys.entry captures
the family, redeem script (BIP49) and internal x-only pubkey
(BIP86) alongside the standard script/address fields.
bitcoinjs.initEccLib(ecc) is called once at load so p2tr resolves.
- Registry: BTC + DGB address families are purpose-only now; a
helper (addressFamiliesFor / defaultAccountPathFor) computes the
concrete m/PURPOSE'/COIN'/0' per (chain, network) — coin type
{mainnet:0, testnet:1} for BTC, always 20 for DGB. chainMeta
expands the list so the panel doesn't need per-chain knowledge.
- Panel: #btcSettings block mirrors #dgbSettings (family select →
path input auto-fill → Apply). The family-select listener + the
fillFamilyPicker() helper are shared between DGB and BTC — the
DOM prefix is the only per-chain input.
- Send is wired for BIP84 (default) and BIP49 (adds redeemScript to
the PSBT input). BIP44 (needs nonWitnessUtxo prev-tx fetch) and
BIP86 (needs tap-tweaked signer) throw a clear "not yet in this
rev — sweep to BIP84" error so users hit it at plan time, not at
broadcast time. Receive works on all four families today.
- Verified all four families derive the canonical BIP44/49/84/86
spec test vectors for the standard abandon×11 mnemonic — see
scratchpad/verify-btc-families.mjs. Byte-identical to the BIPs.
2026-09-07 21:23:15 +02:00
// DGB Core, DigiByte-Go, and the SilentCode web-wallet. `coinType`
// per chain feeds the path builder below.
feat(theseus/aegis): Ethereum + Solana adapters, DGB address-family picker, Aegis-branded shield
Multi-currency coverage matches what aegis.x has been advertising: BCH,
TRX, SC, DGB, ETH, SOL — six coins, two-step coin/network picker for
each. Panel logos, favicon and fallback all read as Aegis.
- Ethereum (lib/chain-eth.js): mainnet + Sepolia. BIP44 m/44'/60'/0'/0/0
→ secp256k1 → EIP-55 checksummed hex address (verified against
MetaMask's canonical abandon×11 vector 0x9858EfFD23…4EcaEda94). JSON-RPC
backend (Cloudflare mainnet, PublicNode Sepolia by default; per-wallet
override). EIP-1559 send with an inline RLP encoder + secp256k1
recoverable sign; broadcast via eth_sendRawTransaction. personal_sign
message signing follows the \x19Ethereum Signed Message:\n prefix.
- Solana (lib/chain-sol.js): mainnet-beta + devnet. SLIP-0010 ed25519
derivation at m/44'/501'/0'/0' (all-hardened), base58 address (@noble
ed25519). SLIP-0010 layer verified against spec Test Vector 1 in
scratchpad/verify-slip10.mjs. Native SOL transfer via the system
program with compact-u16 message serialization + ed25519 sign +
sendTransaction. Devnet gets a faucet.solana.com link in Receive; the
panel appends ?cluster=devnet when opening the explorer.
- DGB address family selector (lib/chain-dgb.js already carried the
paths): the Settings block now shows a Native SegWit / Taproot /
Wrapped SegWit / Legacy P2PKH picker. Selecting a family auto-fills
the derivation-path input with that family's default; Apply
rebuilds the wallet against the new path. Address families exposed
via chainMeta.addressFamilies so the panel can render them from data.
- Panel branding: inline SVG shield (hexagonal aspis, same silhouette
as the aegis.x hero) replaces the "?" fallback in logoSvg() and is
what the header shows before a wallet is selected. Data-URI favicon
wired into panel.html so the Theseus sidebar tab icon reads as Aegis
rather than a chain-specific coin mark.
- QR payloads now follow each chain's own URI scheme (BIP21 for BCH/DGB,
EIP-681 for ETH, Solana Pay for SOL) so external scanners route the
scan to the right wallet.
Not shipped: EIP-1193 provider (window.ethereum) and wallet-adapter
protocol (window.solana). The signing paths exist; only the page-inject
bridge glue is missing. History for ETH/SOL is also empty in this rev —
both need indexer plumbing (Etherscan V2 for ETH, getSignaturesForAddress
+ getTransaction pagination for SOL).
2026-09-07 20:31:27 +02:00
addressFamilies : [
feat(theseus/aegis): BTC address-family picker (BIP44/49/84/86 + Taproot)
BTC now matches DGB's family selector: pick BIP44 (1…), BIP49 (3…),
BIP84 (bc1q…, default) or BIP86 Taproot (bc1p…) from Settings, on
mainnet or testnet3 (paths shift coin type 0 → 1 automatically).
- lib/chain-btc.js: paymentFor(purpose, node, network) returns the
right bitcoinjs-lib payment (p2pkh / p2sh(p2wpkh) / p2wpkh / p2tr)
keyed off the derivation path's purpose. WalletKeys.entry captures
the family, redeem script (BIP49) and internal x-only pubkey
(BIP86) alongside the standard script/address fields.
bitcoinjs.initEccLib(ecc) is called once at load so p2tr resolves.
- Registry: BTC + DGB address families are purpose-only now; a
helper (addressFamiliesFor / defaultAccountPathFor) computes the
concrete m/PURPOSE'/COIN'/0' per (chain, network) — coin type
{mainnet:0, testnet:1} for BTC, always 20 for DGB. chainMeta
expands the list so the panel doesn't need per-chain knowledge.
- Panel: #btcSettings block mirrors #dgbSettings (family select →
path input auto-fill → Apply). The family-select listener + the
fillFamilyPicker() helper are shared between DGB and BTC — the
DOM prefix is the only per-chain input.
- Send is wired for BIP84 (default) and BIP49 (adds redeemScript to
the PSBT input). BIP44 (needs nonWitnessUtxo prev-tx fetch) and
BIP86 (needs tap-tweaked signer) throw a clear "not yet in this
rev — sweep to BIP84" error so users hit it at plan time, not at
broadcast time. Receive works on all four families today.
- Verified all four families derive the canonical BIP44/49/84/86
spec test vectors for the standard abandon×11 mnemonic — see
scratchpad/verify-btc-families.mjs. Byte-identical to the BIPs.
2026-09-07 21:23:15 +02:00
{ id : "bip84" , purpose : 84 , label : "Native SegWit (dgb1q…)" } ,
{ id : "bip86" , purpose : 86 , label : "Taproot (dgb1p…)" } ,
{ id : "bip49" , purpose : 49 , label : "Wrapped SegWit (S…)" } ,
{ id : "bip44" , purpose : 44 , label : "Legacy P2PKH (D…)" } ,
feat(theseus/aegis): Ethereum + Solana adapters, DGB address-family picker, Aegis-branded shield
Multi-currency coverage matches what aegis.x has been advertising: BCH,
TRX, SC, DGB, ETH, SOL — six coins, two-step coin/network picker for
each. Panel logos, favicon and fallback all read as Aegis.
- Ethereum (lib/chain-eth.js): mainnet + Sepolia. BIP44 m/44'/60'/0'/0/0
→ secp256k1 → EIP-55 checksummed hex address (verified against
MetaMask's canonical abandon×11 vector 0x9858EfFD23…4EcaEda94). JSON-RPC
backend (Cloudflare mainnet, PublicNode Sepolia by default; per-wallet
override). EIP-1559 send with an inline RLP encoder + secp256k1
recoverable sign; broadcast via eth_sendRawTransaction. personal_sign
message signing follows the \x19Ethereum Signed Message:\n prefix.
- Solana (lib/chain-sol.js): mainnet-beta + devnet. SLIP-0010 ed25519
derivation at m/44'/501'/0'/0' (all-hardened), base58 address (@noble
ed25519). SLIP-0010 layer verified against spec Test Vector 1 in
scratchpad/verify-slip10.mjs. Native SOL transfer via the system
program with compact-u16 message serialization + ed25519 sign +
sendTransaction. Devnet gets a faucet.solana.com link in Receive; the
panel appends ?cluster=devnet when opening the explorer.
- DGB address family selector (lib/chain-dgb.js already carried the
paths): the Settings block now shows a Native SegWit / Taproot /
Wrapped SegWit / Legacy P2PKH picker. Selecting a family auto-fills
the derivation-path input with that family's default; Apply
rebuilds the wallet against the new path. Address families exposed
via chainMeta.addressFamilies so the panel can render them from data.
- Panel branding: inline SVG shield (hexagonal aspis, same silhouette
as the aegis.x hero) replaces the "?" fallback in logoSvg() and is
what the header shows before a wallet is selected. Data-URI favicon
wired into panel.html so the Theseus sidebar tab icon reads as Aegis
rather than a chain-specific coin mark.
- QR payloads now follow each chain's own URI scheme (BIP21 for BCH/DGB,
EIP-681 for ETH, Solana Pay for SOL) so external scanners route the
scan to the right wallet.
Not shipped: EIP-1193 provider (window.ethereum) and wallet-adapter
protocol (window.solana). The signing paths exist; only the page-inject
bridge glue is missing. History for ETH/SOL is also empty in this rev —
both need indexer plumbing (Etherscan V2 for ETH, getSignaturesForAddress
+ getTransaction pagination for SOL).
2026-09-07 20:31:27 +02:00
] ,
feat(theseus/aegis): BTC address-family picker (BIP44/49/84/86 + Taproot)
BTC now matches DGB's family selector: pick BIP44 (1…), BIP49 (3…),
BIP84 (bc1q…, default) or BIP86 Taproot (bc1p…) from Settings, on
mainnet or testnet3 (paths shift coin type 0 → 1 automatically).
- lib/chain-btc.js: paymentFor(purpose, node, network) returns the
right bitcoinjs-lib payment (p2pkh / p2sh(p2wpkh) / p2wpkh / p2tr)
keyed off the derivation path's purpose. WalletKeys.entry captures
the family, redeem script (BIP49) and internal x-only pubkey
(BIP86) alongside the standard script/address fields.
bitcoinjs.initEccLib(ecc) is called once at load so p2tr resolves.
- Registry: BTC + DGB address families are purpose-only now; a
helper (addressFamiliesFor / defaultAccountPathFor) computes the
concrete m/PURPOSE'/COIN'/0' per (chain, network) — coin type
{mainnet:0, testnet:1} for BTC, always 20 for DGB. chainMeta
expands the list so the panel doesn't need per-chain knowledge.
- Panel: #btcSettings block mirrors #dgbSettings (family select →
path input auto-fill → Apply). The family-select listener + the
fillFamilyPicker() helper are shared between DGB and BTC — the
DOM prefix is the only per-chain input.
- Send is wired for BIP84 (default) and BIP49 (adds redeemScript to
the PSBT input). BIP44 (needs nonWitnessUtxo prev-tx fetch) and
BIP86 (needs tap-tweaked signer) throw a clear "not yet in this
rev — sweep to BIP84" error so users hit it at plan time, not at
broadcast time. Receive works on all four families today.
- Verified all four families derive the canonical BIP44/49/84/86
spec test vectors for the standard abandon×11 mnemonic — see
scratchpad/verify-btc-families.mjs. Byte-identical to the BIPs.
2026-09-07 21:23:15 +02:00
coinType : 20 ,
defaultPurpose : 84 ,
feat(theseus/aegis): fold Sia into the addon; add DGB (BIP84 native SegWit)
Aegis now covers four coins across two-step coin+network picks: BCH
(mainnet + chipnet), TRX (mainnet + Nile), SC (mainnet), DGB (mainnet).
- Sia (SC): pulled the standalone siawallet's lib into
bundled-addons/bchwallet/lib/sia/ and wrote lib/chain-sia.js exposing
the common adapter shape. The very first SC wallet the user adds in
Aegis reuses purpose "siawallet/mainnet/0" so pre-Aegis funds carry
over automatically; subsequent SC sub-accounts start at
"bchwallet/sc/mainnet/1". Per-wallet walletd URL setting; empty URL
shows a "Point Aegis at a walletd node" gate in the panel.
- Vault-derive gate now honors a manifest-declared `absorbs` list, so
Aegis's addon.json can list `absorbs: ["siawallet"]` and the derive()
guard accepts paths under either the current id or the absorbed one —
the mechanism a superseding add-on uses to inherit an older add-on's
keyspace without orphaning funds.
- DigiByte (DGB): lib/chain-dgb.js ports the relevant bits of the
SilentCode Digibyte design — SLIP-44 coin type 20, BIP84 native SegWit
(m/84'/20'/0'/0/x → dgb1q…) via ripemd160(sha256(pubkey)) + bech32.
ElectrumX-DGB backend reuses lib/electrum.js (public wss:50022 pool).
BIP143 P2WPKH sighash + witness-tx serialize implemented inline (no
FORKID — DGB uses standard Bitcoin sighash). Derivation cross-checked
against a known BIP39 vector in scratchpad/verify-dgb.mjs — the address
for "abandon×11 about, m/84'/20'/0'/0/0" is
dgb1q9gmf0pv8jdymcly6lz6fl7lf6mhslsd72e2jq8, matching iancoleman.io/bip39.
- Panel: SVG coin logos for SC (green disc with S) and DGB (blue
octagon with D) alongside the BCH/TRX marks. Chain-specific settings
block per coin (walletd URL for SC; derivation path for DGB). Balance
render uses BigInt-safe arithmetic so 24-decimal SC amounts don't
lose precision on the way through the panel; amount input on SC
returns a hastings string.
- Every chain adapter's snapshot fits the panel's shared shape
(address/balance/history/etc.), so future chains only need a new
chain-<x>.js file, a COINS registry entry, a matching case in
mountWallet, and an SVG logo.
Standalone siawallet addon stays as-is on disk; users can delete it once
they've confirmed Aegis shows the same balance. Nothing here disables it.
2026-09-07 01:56:25 +02:00
networks : {
mainnet : {
id : "mainnet" , label : "Mainnet" , testnet : false ,
purposePrefix : "bchwallet/dgb/mainnet/" , startIndex : 0 ,
} ,
} ,
} ,
feat(theseus/aegis): Ethereum + Solana adapters, DGB address-family picker, Aegis-branded shield
Multi-currency coverage matches what aegis.x has been advertising: BCH,
TRX, SC, DGB, ETH, SOL — six coins, two-step coin/network picker for
each. Panel logos, favicon and fallback all read as Aegis.
- Ethereum (lib/chain-eth.js): mainnet + Sepolia. BIP44 m/44'/60'/0'/0/0
→ secp256k1 → EIP-55 checksummed hex address (verified against
MetaMask's canonical abandon×11 vector 0x9858EfFD23…4EcaEda94). JSON-RPC
backend (Cloudflare mainnet, PublicNode Sepolia by default; per-wallet
override). EIP-1559 send with an inline RLP encoder + secp256k1
recoverable sign; broadcast via eth_sendRawTransaction. personal_sign
message signing follows the \x19Ethereum Signed Message:\n prefix.
- Solana (lib/chain-sol.js): mainnet-beta + devnet. SLIP-0010 ed25519
derivation at m/44'/501'/0'/0' (all-hardened), base58 address (@noble
ed25519). SLIP-0010 layer verified against spec Test Vector 1 in
scratchpad/verify-slip10.mjs. Native SOL transfer via the system
program with compact-u16 message serialization + ed25519 sign +
sendTransaction. Devnet gets a faucet.solana.com link in Receive; the
panel appends ?cluster=devnet when opening the explorer.
- DGB address family selector (lib/chain-dgb.js already carried the
paths): the Settings block now shows a Native SegWit / Taproot /
Wrapped SegWit / Legacy P2PKH picker. Selecting a family auto-fills
the derivation-path input with that family's default; Apply
rebuilds the wallet against the new path. Address families exposed
via chainMeta.addressFamilies so the panel can render them from data.
- Panel branding: inline SVG shield (hexagonal aspis, same silhouette
as the aegis.x hero) replaces the "?" fallback in logoSvg() and is
what the header shows before a wallet is selected. Data-URI favicon
wired into panel.html so the Theseus sidebar tab icon reads as Aegis
rather than a chain-specific coin mark.
- QR payloads now follow each chain's own URI scheme (BIP21 for BCH/DGB,
EIP-681 for ETH, Solana Pay for SOL) so external scanners route the
scan to the right wallet.
Not shipped: EIP-1193 provider (window.ethereum) and wallet-adapter
protocol (window.solana). The signing paths exist; only the page-inject
bridge glue is missing. History for ETH/SOL is also empty in this rev —
both need indexer plumbing (Etherscan V2 for ETH, getSignaturesForAddress
+ getTransaction pagination for SOL).
2026-09-07 20:31:27 +02:00
eth : {
chain : "eth" ,
label : "Ethereum" ,
short : "ETH" ,
ticker : "ETH" ,
decimals : 18 ,
color : "#627eea" ,
logo : "eth" ,
supportsMessageSign : true ,
supportsPageInject : false , // EIP-1193 provider is a follow-up
networks : {
mainnet : {
id : "mainnet" , label : "Mainnet" , testnet : false ,
purposePrefix : "bchwallet/eth/mainnet/" , startIndex : 0 ,
} ,
sepolia : {
id : "sepolia" , label : "Sepolia testnet" , testnet : true ,
purposePrefix : "bchwallet/eth/sepolia/" , startIndex : 0 ,
} ,
} ,
} ,
sol : {
chain : "sol" ,
label : "Solana" ,
short : "SOL" ,
ticker : "SOL" ,
decimals : 9 ,
color : "#9945ff" ,
logo : "sol" ,
supportsMessageSign : true ,
supportsPageInject : false ,
networks : {
mainnet : {
id : "mainnet" , label : "Mainnet-beta" , testnet : false ,
purposePrefix : "bchwallet/sol/mainnet/" , startIndex : 0 ,
} ,
devnet : {
id : "devnet" , label : "Devnet" , testnet : true ,
purposePrefix : "bchwallet/sol/devnet/" , startIndex : 0 ,
} ,
} ,
} ,
feat(theseus/aegis): Bitcoin adapter (mainnet + testnet3, BIP84 native SegWit)
Seven coins across twelve networks now — BTC joins the shipping roster.
- lib/chain-btc.js: BIP84 native SegWit — m/84'/0'/0'/0/x → bc1q…
(mainnet), m/84'/1'/0'/0/x → tb1q… (testnet3). Reuses the exact same
stack the DGB adapter already pulls in: bitcoinjs-lib for network
params + payments.p2wpkh + PSBT, bip32 for HD derivation, ecpair for
the Signer interface, ecc (@bitcoinerlab/secp256k1) for message-sign
recoverable sigs. No new npm deps.
- Backend: same lib/electrum.js Aegis uses for BCH and DGB — plugged
into a public Bitcoin ElectrumX pool (blockstream.info, lu.ke,
grey.pw) for mainnet and aranguren.org / blockstream.info:993 for
testnet3. Send flow: PSBT build + per-input signInput +
finalizeAllInputs + broadcast. BIP-137 recoverable message signing.
- Registered as btc:mainnet + btc:testnet in COINS with the orange
Bitcoin disc SVG logo. Mount case mirrors DGB (accountPath honored,
so switching to m/44'/0'/0' or m/49'/0'/0' via the setAccountPath
message gives legacy 1… or wrapped-segwit 3… — same one-line UI plumb
as the DGB address-family selector, deferred to a follow-up).
- Panel: sat as the small-unit label, bitcoin: BIP21 QR payload,
chain-aware send placeholder ("bc1q…" mainnet / "tb1q…" testnet).
- Verified: BIP84 spec test vector — abandon×11 mnemonic derives
bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu at m/84'/0'/0'/0/0
(byte-identical to the vector in the BIP text). Testnet variant
produces tb1q6rz28mcfaxtmd6v789l9rrlrusdprr9pqcpvkl at m/84'/1'/0'/0/0
(cross-checkable on iancoleman.io/bip39 with coin BTC Testnet).
2026-09-07 21:15:45 +02:00
btc : {
chain : "btc" ,
label : "Bitcoin" ,
short : "BTC" ,
ticker : "BTC" ,
decimals : 8 ,
color : "#f7931a" ,
logo : "btc" ,
supportsMessageSign : true ,
supportsPageInject : false ,
feat(theseus/aegis): BTC address-family picker (BIP44/49/84/86 + Taproot)
BTC now matches DGB's family selector: pick BIP44 (1…), BIP49 (3…),
BIP84 (bc1q…, default) or BIP86 Taproot (bc1p…) from Settings, on
mainnet or testnet3 (paths shift coin type 0 → 1 automatically).
- lib/chain-btc.js: paymentFor(purpose, node, network) returns the
right bitcoinjs-lib payment (p2pkh / p2sh(p2wpkh) / p2wpkh / p2tr)
keyed off the derivation path's purpose. WalletKeys.entry captures
the family, redeem script (BIP49) and internal x-only pubkey
(BIP86) alongside the standard script/address fields.
bitcoinjs.initEccLib(ecc) is called once at load so p2tr resolves.
- Registry: BTC + DGB address families are purpose-only now; a
helper (addressFamiliesFor / defaultAccountPathFor) computes the
concrete m/PURPOSE'/COIN'/0' per (chain, network) — coin type
{mainnet:0, testnet:1} for BTC, always 20 for DGB. chainMeta
expands the list so the panel doesn't need per-chain knowledge.
- Panel: #btcSettings block mirrors #dgbSettings (family select →
path input auto-fill → Apply). The family-select listener + the
fillFamilyPicker() helper are shared between DGB and BTC — the
DOM prefix is the only per-chain input.
- Send is wired for BIP84 (default) and BIP49 (adds redeemScript to
the PSBT input). BIP44 (needs nonWitnessUtxo prev-tx fetch) and
BIP86 (needs tap-tweaked signer) throw a clear "not yet in this
rev — sweep to BIP84" error so users hit it at plan time, not at
broadcast time. Receive works on all four families today.
- Verified all four families derive the canonical BIP44/49/84/86
spec test vectors for the standard abandon×11 mnemonic — see
scratchpad/verify-btc-families.mjs. Byte-identical to the BIPs.
2026-09-07 21:23:15 +02:00
// BIP44/49/84/86 across bc1q… / bc1p… / 3… / 1… on mainnet and
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
// tb1q… / tb1p… / 2… / m/n… on testnet3 + signet. Coin type shifts
// per network (0 for mainnet, 1 for both testnet3 and signet — SLIP-44
// treats every Bitcoin testnet as coin type 1).
feat(theseus/aegis): BTC address-family picker (BIP44/49/84/86 + Taproot)
BTC now matches DGB's family selector: pick BIP44 (1…), BIP49 (3…),
BIP84 (bc1q…, default) or BIP86 Taproot (bc1p…) from Settings, on
mainnet or testnet3 (paths shift coin type 0 → 1 automatically).
- lib/chain-btc.js: paymentFor(purpose, node, network) returns the
right bitcoinjs-lib payment (p2pkh / p2sh(p2wpkh) / p2wpkh / p2tr)
keyed off the derivation path's purpose. WalletKeys.entry captures
the family, redeem script (BIP49) and internal x-only pubkey
(BIP86) alongside the standard script/address fields.
bitcoinjs.initEccLib(ecc) is called once at load so p2tr resolves.
- Registry: BTC + DGB address families are purpose-only now; a
helper (addressFamiliesFor / defaultAccountPathFor) computes the
concrete m/PURPOSE'/COIN'/0' per (chain, network) — coin type
{mainnet:0, testnet:1} for BTC, always 20 for DGB. chainMeta
expands the list so the panel doesn't need per-chain knowledge.
- Panel: #btcSettings block mirrors #dgbSettings (family select →
path input auto-fill → Apply). The family-select listener + the
fillFamilyPicker() helper are shared between DGB and BTC — the
DOM prefix is the only per-chain input.
- Send is wired for BIP84 (default) and BIP49 (adds redeemScript to
the PSBT input). BIP44 (needs nonWitnessUtxo prev-tx fetch) and
BIP86 (needs tap-tweaked signer) throw a clear "not yet in this
rev — sweep to BIP84" error so users hit it at plan time, not at
broadcast time. Receive works on all four families today.
- Verified all four families derive the canonical BIP44/49/84/86
spec test vectors for the standard abandon×11 mnemonic — see
scratchpad/verify-btc-families.mjs. Byte-identical to the BIPs.
2026-09-07 21:23:15 +02:00
addressFamilies : [
{ id : "bip84" , purpose : 84 , label : "Native SegWit (bc1q… / tb1q…)" } ,
{ id : "bip86" , purpose : 86 , label : "Taproot (bc1p… / tb1p…)" } ,
{ id : "bip49" , purpose : 49 , label : "Wrapped SegWit (3… / 2…)" } ,
{ id : "bip44" , purpose : 44 , label : "Legacy P2PKH (1… / m…, n…)" } ,
] ,
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
coinType : { mainnet : 0 , testnet : 1 , signet : 1 } ,
feat(theseus/aegis): BTC address-family picker (BIP44/49/84/86 + Taproot)
BTC now matches DGB's family selector: pick BIP44 (1…), BIP49 (3…),
BIP84 (bc1q…, default) or BIP86 Taproot (bc1p…) from Settings, on
mainnet or testnet3 (paths shift coin type 0 → 1 automatically).
- lib/chain-btc.js: paymentFor(purpose, node, network) returns the
right bitcoinjs-lib payment (p2pkh / p2sh(p2wpkh) / p2wpkh / p2tr)
keyed off the derivation path's purpose. WalletKeys.entry captures
the family, redeem script (BIP49) and internal x-only pubkey
(BIP86) alongside the standard script/address fields.
bitcoinjs.initEccLib(ecc) is called once at load so p2tr resolves.
- Registry: BTC + DGB address families are purpose-only now; a
helper (addressFamiliesFor / defaultAccountPathFor) computes the
concrete m/PURPOSE'/COIN'/0' per (chain, network) — coin type
{mainnet:0, testnet:1} for BTC, always 20 for DGB. chainMeta
expands the list so the panel doesn't need per-chain knowledge.
- Panel: #btcSettings block mirrors #dgbSettings (family select →
path input auto-fill → Apply). The family-select listener + the
fillFamilyPicker() helper are shared between DGB and BTC — the
DOM prefix is the only per-chain input.
- Send is wired for BIP84 (default) and BIP49 (adds redeemScript to
the PSBT input). BIP44 (needs nonWitnessUtxo prev-tx fetch) and
BIP86 (needs tap-tweaked signer) throw a clear "not yet in this
rev — sweep to BIP84" error so users hit it at plan time, not at
broadcast time. Receive works on all four families today.
- Verified all four families derive the canonical BIP44/49/84/86
spec test vectors for the standard abandon×11 mnemonic — see
scratchpad/verify-btc-families.mjs. Byte-identical to the BIPs.
2026-09-07 21:23:15 +02:00
defaultPurpose : 84 ,
feat(theseus/aegis): Bitcoin adapter (mainnet + testnet3, BIP84 native SegWit)
Seven coins across twelve networks now — BTC joins the shipping roster.
- lib/chain-btc.js: BIP84 native SegWit — m/84'/0'/0'/0/x → bc1q…
(mainnet), m/84'/1'/0'/0/x → tb1q… (testnet3). Reuses the exact same
stack the DGB adapter already pulls in: bitcoinjs-lib for network
params + payments.p2wpkh + PSBT, bip32 for HD derivation, ecpair for
the Signer interface, ecc (@bitcoinerlab/secp256k1) for message-sign
recoverable sigs. No new npm deps.
- Backend: same lib/electrum.js Aegis uses for BCH and DGB — plugged
into a public Bitcoin ElectrumX pool (blockstream.info, lu.ke,
grey.pw) for mainnet and aranguren.org / blockstream.info:993 for
testnet3. Send flow: PSBT build + per-input signInput +
finalizeAllInputs + broadcast. BIP-137 recoverable message signing.
- Registered as btc:mainnet + btc:testnet in COINS with the orange
Bitcoin disc SVG logo. Mount case mirrors DGB (accountPath honored,
so switching to m/44'/0'/0' or m/49'/0'/0' via the setAccountPath
message gives legacy 1… or wrapped-segwit 3… — same one-line UI plumb
as the DGB address-family selector, deferred to a follow-up).
- Panel: sat as the small-unit label, bitcoin: BIP21 QR payload,
chain-aware send placeholder ("bc1q…" mainnet / "tb1q…" testnet).
- Verified: BIP84 spec test vector — abandon×11 mnemonic derives
bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu at m/84'/0'/0'/0/0
(byte-identical to the vector in the BIP text). Testnet variant
produces tb1q6rz28mcfaxtmd6v789l9rrlrusdprr9pqcpvkl at m/84'/1'/0'/0/0
(cross-checkable on iancoleman.io/bip39 with coin BTC Testnet).
2026-09-07 21:15:45 +02:00
networks : {
mainnet : {
id : "mainnet" , label : "Mainnet" , testnet : false ,
purposePrefix : "bchwallet/btc/mainnet/" , startIndex : 0 ,
} ,
testnet : {
id : "testnet" , label : "Testnet3" , testnet : true ,
purposePrefix : "bchwallet/btc/testnet/" , startIndex : 0 ,
} ,
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
signet : {
id : "signet" , label : "Signet" , testnet : true ,
purposePrefix : "bchwallet/btc/signet/" , startIndex : 0 ,
} ,
feat(theseus/aegis): Bitcoin adapter (mainnet + testnet3, BIP84 native SegWit)
Seven coins across twelve networks now — BTC joins the shipping roster.
- lib/chain-btc.js: BIP84 native SegWit — m/84'/0'/0'/0/x → bc1q…
(mainnet), m/84'/1'/0'/0/x → tb1q… (testnet3). Reuses the exact same
stack the DGB adapter already pulls in: bitcoinjs-lib for network
params + payments.p2wpkh + PSBT, bip32 for HD derivation, ecpair for
the Signer interface, ecc (@bitcoinerlab/secp256k1) for message-sign
recoverable sigs. No new npm deps.
- Backend: same lib/electrum.js Aegis uses for BCH and DGB — plugged
into a public Bitcoin ElectrumX pool (blockstream.info, lu.ke,
grey.pw) for mainnet and aranguren.org / blockstream.info:993 for
testnet3. Send flow: PSBT build + per-input signInput +
finalizeAllInputs + broadcast. BIP-137 recoverable message signing.
- Registered as btc:mainnet + btc:testnet in COINS with the orange
Bitcoin disc SVG logo. Mount case mirrors DGB (accountPath honored,
so switching to m/44'/0'/0' or m/49'/0'/0' via the setAccountPath
message gives legacy 1… or wrapped-segwit 3… — same one-line UI plumb
as the DGB address-family selector, deferred to a follow-up).
- Panel: sat as the small-unit label, bitcoin: BIP21 QR payload,
chain-aware send placeholder ("bc1q…" mainnet / "tb1q…" testnet).
- Verified: BIP84 spec test vector — abandon×11 mnemonic derives
bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu at m/84'/0'/0'/0/0
(byte-identical to the vector in the BIP text). Testnet variant
produces tb1q6rz28mcfaxtmd6v789l9rrlrusdprr9pqcpvkl at m/84'/1'/0'/0/0
(cross-checkable on iancoleman.io/bip39 with coin BTC Testnet).
2026-09-07 21:15:45 +02:00
} ,
} ,
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
} ;
function chainKey ( chain , network ) { return ` ${ chain } : ${ network } ` ; }
feat(theseus/aegis): BTC address-family picker (BIP44/49/84/86 + Taproot)
BTC now matches DGB's family selector: pick BIP44 (1…), BIP49 (3…),
BIP84 (bc1q…, default) or BIP86 Taproot (bc1p…) from Settings, on
mainnet or testnet3 (paths shift coin type 0 → 1 automatically).
- lib/chain-btc.js: paymentFor(purpose, node, network) returns the
right bitcoinjs-lib payment (p2pkh / p2sh(p2wpkh) / p2wpkh / p2tr)
keyed off the derivation path's purpose. WalletKeys.entry captures
the family, redeem script (BIP49) and internal x-only pubkey
(BIP86) alongside the standard script/address fields.
bitcoinjs.initEccLib(ecc) is called once at load so p2tr resolves.
- Registry: BTC + DGB address families are purpose-only now; a
helper (addressFamiliesFor / defaultAccountPathFor) computes the
concrete m/PURPOSE'/COIN'/0' per (chain, network) — coin type
{mainnet:0, testnet:1} for BTC, always 20 for DGB. chainMeta
expands the list so the panel doesn't need per-chain knowledge.
- Panel: #btcSettings block mirrors #dgbSettings (family select →
path input auto-fill → Apply). The family-select listener + the
fillFamilyPicker() helper are shared between DGB and BTC — the
DOM prefix is the only per-chain input.
- Send is wired for BIP84 (default) and BIP49 (adds redeemScript to
the PSBT input). BIP44 (needs nonWitnessUtxo prev-tx fetch) and
BIP86 (needs tap-tweaked signer) throw a clear "not yet in this
rev — sweep to BIP84" error so users hit it at plan time, not at
broadcast time. Receive works on all four families today.
- Verified all four families derive the canonical BIP44/49/84/86
spec test vectors for the standard abandon×11 mnemonic — see
scratchpad/verify-btc-families.mjs. Byte-identical to the BIPs.
2026-09-07 21:23:15 +02:00
// Coin type per (chain, network). A number literal on the COINS entry
// (DGB uses a single 20) or a per-network object ({mainnet: 0, testnet: 1}
// for BTC). Returns null when the chain doesn't declare a family picker.
function coinTypeFor ( c , network ) {
if ( ! c || c . coinType == null ) return null ;
return typeof c . coinType === "number" ? c . coinType : ( c . coinType [ network ] ? ? null ) ;
}
// Full derivation paths per family for a given (chain, network) — expands
// the family list on the fly so each picker knows exactly which path a
// pick would produce.
function addressFamiliesFor ( c , network ) {
if ( ! c || ! c . addressFamilies ) return null ;
const ct = coinTypeFor ( c , network ) ;
if ( ct == null ) return c . addressFamilies ;
return c . addressFamilies . map ( ( f ) => ( {
... f ,
defaultAccountPath : ` m/ ${ f . purpose } '/ ${ ct } '/0' ` ,
} ) ) ;
}
function defaultAccountPathFor ( c , network ) {
const ct = coinTypeFor ( c , network ) ;
if ( ct == null || c . defaultPurpose == null ) return null ;
return ` m/ ${ c . defaultPurpose } '/ ${ ct } '/0' ` ;
}
feat(theseus/aegis): SVG coin logos, two-step coin/network picker, BCH Chipnet
- Inline SVG logos for BCH (green disc + ₿) and TRX (red disc + geometric T)
replace the 🟨/🔴/🔵 emoji in the sidebar header and wallet picker rows.
The approval overlay stays text-only ("Wallet: <name> — BCH · Mainnet")
because that surface renders plain rows, not HTML.
- Wallet picker's "Add wallet" is now two-step: click a coin to expand its
networks, then click a network to create the wallet. The flat list is gone.
- BCH Chipnet is a real chain option now: bchtest cashaddr prefix,
m/44'/1'/0' derivation (BIP44 testnet coin type), bundled Chipnet electrum
defaults, chipnet.imaginary.cash explorer, tbch.googol.cash faucet link
in Receive. The shared electrum-servers setting stays mainnet-only in
this rev; Chipnet uses adapter-embedded defaults.
- lib/chain-bch.js gained a BCH_NETWORKS table so mainnet vs chipnet
differences (prefix, path, servers, explorer, faucet) live in one place.
- Registry is grouped by coin ({networks:{…}}) instead of a flat
chain:network map — snapshot exposes coins[] for the panel and adds
coinLabel/networkLabel/testnet fields per wallet.
- Testnet wallets get a small "TEST" tag next to the network name so the
user can never mistake a chipnet or Nile balance for real money.
Legacy BCH mainnet index 0 derivation unchanged (bchwallet/mainnet/0 →
m/44'/145'/0' → bitcoincash prefix); the network parameter defaults to
"mainnet" and BCH_NETWORKS.mainnet reproduces the pre-change constants.
2026-09-07 01:07:31 +02:00
function chainMeta ( chain , network ) {
const c = COINS [ chain ] ; const n = c && c . networks [ network ] ;
if ( ! c || ! n ) return null ;
return {
chain : c . chain , network : n . id ,
label : c . label + " · " + n . label , short : c . short , ticker : c . ticker , decimals : c . decimals ,
color : c . color , logo : c . logo , coinLabel : c . label , networkLabel : n . label , testnet : ! ! n . testnet ,
purposePrefix : n . purposePrefix , startIndex : n . startIndex ,
supportsMessageSign : ! ! c . supportsMessageSign , supportsPageInject : ! ! c . supportsPageInject ,
feat(theseus/aegis): BTC address-family picker (BIP44/49/84/86 + Taproot)
BTC now matches DGB's family selector: pick BIP44 (1…), BIP49 (3…),
BIP84 (bc1q…, default) or BIP86 Taproot (bc1p…) from Settings, on
mainnet or testnet3 (paths shift coin type 0 → 1 automatically).
- lib/chain-btc.js: paymentFor(purpose, node, network) returns the
right bitcoinjs-lib payment (p2pkh / p2sh(p2wpkh) / p2wpkh / p2tr)
keyed off the derivation path's purpose. WalletKeys.entry captures
the family, redeem script (BIP49) and internal x-only pubkey
(BIP86) alongside the standard script/address fields.
bitcoinjs.initEccLib(ecc) is called once at load so p2tr resolves.
- Registry: BTC + DGB address families are purpose-only now; a
helper (addressFamiliesFor / defaultAccountPathFor) computes the
concrete m/PURPOSE'/COIN'/0' per (chain, network) — coin type
{mainnet:0, testnet:1} for BTC, always 20 for DGB. chainMeta
expands the list so the panel doesn't need per-chain knowledge.
- Panel: #btcSettings block mirrors #dgbSettings (family select →
path input auto-fill → Apply). The family-select listener + the
fillFamilyPicker() helper are shared between DGB and BTC — the
DOM prefix is the only per-chain input.
- Send is wired for BIP84 (default) and BIP49 (adds redeemScript to
the PSBT input). BIP44 (needs nonWitnessUtxo prev-tx fetch) and
BIP86 (needs tap-tweaked signer) throw a clear "not yet in this
rev — sweep to BIP84" error so users hit it at plan time, not at
broadcast time. Receive works on all four families today.
- Verified all four families derive the canonical BIP44/49/84/86
spec test vectors for the standard abandon×11 mnemonic — see
scratchpad/verify-btc-families.mjs. Byte-identical to the BIPs.
2026-09-07 21:23:15 +02:00
addressFamilies : addressFamiliesFor ( c , network ) ,
defaultAccountPath : defaultAccountPathFor ( c , network ) ,
feat(theseus/aegis): SVG coin logos, two-step coin/network picker, BCH Chipnet
- Inline SVG logos for BCH (green disc + ₿) and TRX (red disc + geometric T)
replace the 🟨/🔴/🔵 emoji in the sidebar header and wallet picker rows.
The approval overlay stays text-only ("Wallet: <name> — BCH · Mainnet")
because that surface renders plain rows, not HTML.
- Wallet picker's "Add wallet" is now two-step: click a coin to expand its
networks, then click a network to create the wallet. The flat list is gone.
- BCH Chipnet is a real chain option now: bchtest cashaddr prefix,
m/44'/1'/0' derivation (BIP44 testnet coin type), bundled Chipnet electrum
defaults, chipnet.imaginary.cash explorer, tbch.googol.cash faucet link
in Receive. The shared electrum-servers setting stays mainnet-only in
this rev; Chipnet uses adapter-embedded defaults.
- lib/chain-bch.js gained a BCH_NETWORKS table so mainnet vs chipnet
differences (prefix, path, servers, explorer, faucet) live in one place.
- Registry is grouped by coin ({networks:{…}}) instead of a flat
chain:network map — snapshot exposes coins[] for the panel and adds
coinLabel/networkLabel/testnet fields per wallet.
- Testnet wallets get a small "TEST" tag next to the network name so the
user can never mistake a chipnet or Nile balance for real money.
Legacy BCH mainnet index 0 derivation unchanged (bchwallet/mainnet/0 →
m/44'/145'/0' → bitcoincash prefix); the network parameter defaults to
"mainnet" and BCH_NETWORKS.mainnet reproduces the pre-change constants.
2026-09-07 01:07:31 +02:00
} ;
}
function coinsForPanel ( ) {
return Object . values ( COINS ) . map ( ( c ) => ( {
chain : c . chain , label : c . label , short : c . short , ticker : c . ticker , color : c . color , logo : c . logo , decimals : c . decimals ,
networks : Object . values ( c . networks ) . map ( ( n ) => ( { id : n . id , label : n . label , testnet : ! ! n . testnet } ) ) ,
} ) ) ;
}
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
// ---- wallet list ------------------------------------------------------------
function readWallets ( api ) {
const raw = api . storage . get ( "wallets" , null ) ;
return Array . isArray ( raw ) ? raw : null ;
}
function writeWallets ( api , list ) { api . storage . set ( "wallets" , list ) ; }
// Bring pre-multi-wallet storage forward: create the legacy BCH default entry
// and rehome its receiveCursor / txCache under the new per-wallet subkey.
function migrateLegacyStorage ( api ) {
if ( readWallets ( api ) ) return ; // already multi-wallet
const legacyAccountPath = String ( api . storage . get ( "accountPath" , "" ) || "" ) . trim ( ) || "m/44'/145'/0'" ;
const wallets = [ {
id : LEGACY _BCH _WALLET _ID ,
label : "BCH — main" ,
chain : "bch" ,
network : "mainnet" ,
purpose : LEGACY _BCH _PURPOSE ,
accountPath : legacyAccountPath ,
isDefault : true ,
isLegacy : true ,
createdAt : 0 ,
} ] ;
writeWallets ( api , wallets ) ;
api . storage . set ( "selectedWalletId" , LEGACY _BCH _WALLET _ID ) ;
// Move per-wallet state under the scoped prefix used by chain-bch.js.
const prefix = ` wallets/ ${ LEGACY _BCH _WALLET _ID } / ` ;
for ( const legacyKey of [ "receiveCursor" , "txCache" ] ) {
const v = api . storage . get ( legacyKey , null ) ;
if ( v !== null && api . storage . get ( prefix + legacyKey , null ) === null ) {
api . storage . set ( prefix + legacyKey , v ) ;
}
}
api . log ( "migrated legacy BCH wallet into multi-wallet layout" ) ;
}
function nextIndex ( wallets , meta ) {
let max = meta . startIndex - 1 ;
for ( const w of wallets ) {
if ( chainKey ( w . chain , w . network ) !== chainKey ( meta . chain , meta . network ) ) continue ;
if ( w . isLegacy ) continue ;
const m = /\/(\d+)$/ . exec ( w . purpose || "" ) ;
const n = m ? Number ( m [ 1 ] ) : NaN ;
if ( Number . isFinite ( n ) && n > max ) max = n ;
}
return max + 1 ;
feat(theseus/bchwallet): receive + history — vault-derived keys, cashaddr, QR, electrum
Wallet core on mainnet:
- keys from api.vault.derive("bchwallet/mainnet/0") -> BIP32 m/44'/145'/0'
(@scure/bip32), never persisted; wiped on deactivate.
- lib/cashaddr.js (encode/decode + legacy Base58Check, spec vectors pass),
lib/keys.js (hash160, p2pkh, electrum scripthash, ECDSA DER + BIP-137
recoverable signing), lib/tx.js (serialization, SIGHASH_ALL|FORKID
digest, coin selection, fee estimate), lib/electrum.js (Fulcrum WSS
client with failover + subscriptions), lib/wallet.js (gap-limit scan,
balance, UTXOs, 25-tx history with per-tx deltas, cached public txs).
- qr.js: dependency-free QR encoder (byte mode, v1-10, EC M/L; verified
against jsQR).
- panel: balance header, Receive (QR, copy, next unused address, explorer),
History (deltas, confirmations, explorer links), Settings (derivation
path, electrum server list, xpub / approval-gated xprv reveal). Locked
and not-set-up vault states explained in-panel.
- host: api.import for ESM-only deps, api.openTab for explorer links; an
add-on whose activate() throws is no longer listed twice.
2026-09-06 02:46:41 +02:00
}
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
function makeWalletId ( meta , index ) {
const n = String ( meta . network ) . replace ( /[^a-z0-9]/gi , "" ) ;
return ` ${ meta . chain } - ${ n } - ${ index } ` ;
}
function autoLabel ( meta , wallets ) {
const same = wallets . filter ( ( w ) => chainKey ( w . chain , w . network ) === chainKey ( meta . chain , meta . network ) ) ;
if ( ! same . length ) return meta . short ;
return ` ${ meta . short } # ${ same . length + 1 } ` ;
}
// ---- runtime wallet map -----------------------------------------------------
// A "runtime" is a mounted wallet: its adapter instance plus phase + error.
// activate() derives all of them in parallel once the vault unlocks.
async function mountAllWallets ( ) {
feat(theseus/bchwallet): receive + history — vault-derived keys, cashaddr, QR, electrum
Wallet core on mainnet:
- keys from api.vault.derive("bchwallet/mainnet/0") -> BIP32 m/44'/145'/0'
(@scure/bip32), never persisted; wiped on deactivate.
- lib/cashaddr.js (encode/decode + legacy Base58Check, spec vectors pass),
lib/keys.js (hash160, p2pkh, electrum scripthash, ECDSA DER + BIP-137
recoverable signing), lib/tx.js (serialization, SIGHASH_ALL|FORKID
digest, coin selection, fee estimate), lib/electrum.js (Fulcrum WSS
client with failover + subscriptions), lib/wallet.js (gap-limit scan,
balance, UTXOs, 25-tx history with per-tx deltas, cached public txs).
- qr.js: dependency-free QR encoder (byte mode, v1-10, EC M/L; verified
against jsQR).
- panel: balance header, Receive (QR, copy, next unused address, explorer),
History (deltas, confirmations, explorer links), Settings (derivation
path, electrum server list, xpub / approval-gated xprv reveal). Locked
and not-set-up vault states explained in-panel.
- host: api.import for ESM-only deps, api.openTab for explorer links; an
add-on whose activate() throws is no longer listed twice.
2026-09-06 02:46:41 +02:00
const c = ctx ;
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
const walletList = readWallets ( c . api ) || [ ] ;
for ( const w of walletList ) {
if ( ! c . runtimes . has ( w . id ) ) c . runtimes . set ( w . id , { entry : w , phase : "locked" , error : null , adapter : null } ) ;
}
emitState ( ) ;
await Promise . all ( walletList . map ( ( w ) => mountWallet ( w ) ) ) ;
feat(theseus/bchwallet): receive + history — vault-derived keys, cashaddr, QR, electrum
Wallet core on mainnet:
- keys from api.vault.derive("bchwallet/mainnet/0") -> BIP32 m/44'/145'/0'
(@scure/bip32), never persisted; wiped on deactivate.
- lib/cashaddr.js (encode/decode + legacy Base58Check, spec vectors pass),
lib/keys.js (hash160, p2pkh, electrum scripthash, ECDSA DER + BIP-137
recoverable signing), lib/tx.js (serialization, SIGHASH_ALL|FORKID
digest, coin selection, fee estimate), lib/electrum.js (Fulcrum WSS
client with failover + subscriptions), lib/wallet.js (gap-limit scan,
balance, UTXOs, 25-tx history with per-tx deltas, cached public txs).
- qr.js: dependency-free QR encoder (byte mode, v1-10, EC M/L; verified
against jsQR).
- panel: balance header, Receive (QR, copy, next unused address, explorer),
History (deltas, confirmations, explorer links), Settings (derivation
path, electrum server list, xpub / approval-gated xprv reveal). Locked
and not-set-up vault states explained in-panel.
- host: api.import for ESM-only deps, api.openTab for explorer links; an
add-on whose activate() throws is no longer listed twice.
2026-09-06 02:46:41 +02:00
}
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
async function mountWallet ( entry ) {
feat(theseus/bchwallet): receive + history — vault-derived keys, cashaddr, QR, electrum
Wallet core on mainnet:
- keys from api.vault.derive("bchwallet/mainnet/0") -> BIP32 m/44'/145'/0'
(@scure/bip32), never persisted; wiped on deactivate.
- lib/cashaddr.js (encode/decode + legacy Base58Check, spec vectors pass),
lib/keys.js (hash160, p2pkh, electrum scripthash, ECDSA DER + BIP-137
recoverable signing), lib/tx.js (serialization, SIGHASH_ALL|FORKID
digest, coin selection, fee estimate), lib/electrum.js (Fulcrum WSS
client with failover + subscriptions), lib/wallet.js (gap-limit scan,
balance, UTXOs, 25-tx history with per-tx deltas, cached public txs).
- qr.js: dependency-free QR encoder (byte mode, v1-10, EC M/L; verified
against jsQR).
- panel: balance header, Receive (QR, copy, next unused address, explorer),
History (deltas, confirmations, explorer links), Settings (derivation
path, electrum server list, xpub / approval-gated xprv reveal). Locked
and not-set-up vault states explained in-panel.
- host: api.import for ESM-only deps, api.openTab for explorer links; an
add-on whose activate() throws is no longer listed twice.
2026-09-06 02:46:41 +02:00
const c = ctx ;
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
const rt = c . runtimes . get ( entry . id ) || { entry , phase : "locked" , error : null , adapter : null } ;
rt . entry = entry ;
rt . phase = "locked" ; rt . error = null ;
c . runtimes . set ( entry . id , rt ) ;
emitState ( ) ;
let root ;
feat(theseus/bchwallet): receive + history — vault-derived keys, cashaddr, QR, electrum
Wallet core on mainnet:
- keys from api.vault.derive("bchwallet/mainnet/0") -> BIP32 m/44'/145'/0'
(@scure/bip32), never persisted; wiped on deactivate.
- lib/cashaddr.js (encode/decode + legacy Base58Check, spec vectors pass),
lib/keys.js (hash160, p2pkh, electrum scripthash, ECDSA DER + BIP-137
recoverable signing), lib/tx.js (serialization, SIGHASH_ALL|FORKID
digest, coin selection, fee estimate), lib/electrum.js (Fulcrum WSS
client with failover + subscriptions), lib/wallet.js (gap-limit scan,
balance, UTXOs, 25-tx history with per-tx deltas, cached public txs).
- qr.js: dependency-free QR encoder (byte mode, v1-10, EC M/L; verified
against jsQR).
- panel: balance header, Receive (QR, copy, next unused address, explorer),
History (deltas, confirmations, explorer links), Settings (derivation
path, electrum server list, xpub / approval-gated xprv reveal). Locked
and not-set-up vault states explained in-panel.
- host: api.import for ESM-only deps, api.openTab for explorer links; an
add-on whose activate() throws is no longer listed twice.
2026-09-06 02:46:41 +02:00
try {
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
root = await c . api . vault . derive ( entry . purpose ) ;
feat(theseus/bchwallet): receive + history — vault-derived keys, cashaddr, QR, electrum
Wallet core on mainnet:
- keys from api.vault.derive("bchwallet/mainnet/0") -> BIP32 m/44'/145'/0'
(@scure/bip32), never persisted; wiped on deactivate.
- lib/cashaddr.js (encode/decode + legacy Base58Check, spec vectors pass),
lib/keys.js (hash160, p2pkh, electrum scripthash, ECDSA DER + BIP-137
recoverable signing), lib/tx.js (serialization, SIGHASH_ALL|FORKID
digest, coin selection, fee estimate), lib/electrum.js (Fulcrum WSS
client with failover + subscriptions), lib/wallet.js (gap-limit scan,
balance, UTXOs, 25-tx history with per-tx deltas, cached public txs).
- qr.js: dependency-free QR encoder (byte mode, v1-10, EC M/L; verified
against jsQR).
- panel: balance header, Receive (QR, copy, next unused address, explorer),
History (deltas, confirmations, explorer links), Settings (derivation
path, electrum server list, xpub / approval-gated xprv reveal). Locked
and not-set-up vault states explained in-panel.
- host: api.import for ESM-only deps, api.openTab for explorer links; an
add-on whose activate() throws is no longer listed twice.
2026-09-06 02:46:41 +02:00
} catch ( e ) {
const msg = e ? . message || String ( e ) ;
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
rt . phase = /not set up/i . test ( msg ) ? "nosetup" : "error" ;
rt . error = msg ;
emitState ( ) ;
feat(theseus/bchwallet): receive + history — vault-derived keys, cashaddr, QR, electrum
Wallet core on mainnet:
- keys from api.vault.derive("bchwallet/mainnet/0") -> BIP32 m/44'/145'/0'
(@scure/bip32), never persisted; wiped on deactivate.
- lib/cashaddr.js (encode/decode + legacy Base58Check, spec vectors pass),
lib/keys.js (hash160, p2pkh, electrum scripthash, ECDSA DER + BIP-137
recoverable signing), lib/tx.js (serialization, SIGHASH_ALL|FORKID
digest, coin selection, fee estimate), lib/electrum.js (Fulcrum WSS
client with failover + subscriptions), lib/wallet.js (gap-limit scan,
balance, UTXOs, 25-tx history with per-tx deltas, cached public txs).
- qr.js: dependency-free QR encoder (byte mode, v1-10, EC M/L; verified
against jsQR).
- panel: balance header, Receive (QR, copy, next unused address, explorer),
History (deltas, confirmations, explorer links), Settings (derivation
path, electrum server list, xpub / approval-gated xprv reveal). Locked
and not-set-up vault states explained in-panel.
- host: api.import for ESM-only deps, api.openTab for explorer links; an
add-on whose activate() throws is no longer listed twice.
2026-09-06 02:46:41 +02:00
return ;
}
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
if ( ctx !== c ) return ;
try {
let adapter ;
if ( entry . chain === "bch" ) {
feat(theseus/aegis): SVG coin logos, two-step coin/network picker, BCH Chipnet
- Inline SVG logos for BCH (green disc + ₿) and TRX (red disc + geometric T)
replace the 🟨/🔴/🔵 emoji in the sidebar header and wallet picker rows.
The approval overlay stays text-only ("Wallet: <name> — BCH · Mainnet")
because that surface renders plain rows, not HTML.
- Wallet picker's "Add wallet" is now two-step: click a coin to expand its
networks, then click a network to create the wallet. The flat list is gone.
- BCH Chipnet is a real chain option now: bchtest cashaddr prefix,
m/44'/1'/0' derivation (BIP44 testnet coin type), bundled Chipnet electrum
defaults, chipnet.imaginary.cash explorer, tbch.googol.cash faucet link
in Receive. The shared electrum-servers setting stays mainnet-only in
this rev; Chipnet uses adapter-embedded defaults.
- lib/chain-bch.js gained a BCH_NETWORKS table so mainnet vs chipnet
differences (prefix, path, servers, explorer, faucet) live in one place.
- Registry is grouped by coin ({networks:{…}}) instead of a flat
chain:network map — snapshot exposes coins[] for the panel and adds
coinLabel/networkLabel/testnet fields per wallet.
- Testnet wallets get a small "TEST" tag next to the network name so the
user can never mistake a chipnet or Nile balance for real money.
Legacy BCH mainnet index 0 derivation unchanged (bchwallet/mainnet/0 →
m/44'/145'/0' → bitcoincash prefix); the network parameter defaults to
"mainnet" and BCH_NETWORKS.mainnet reproduces the pre-change constants.
2026-09-07 01:07:31 +02:00
// Mainnet still honors the user-set custom electrum list; chipnet uses
// adapter-embedded defaults (no per-network custom list in this rev).
const servers = entry . network === "mainnet" ? bchServerList ( c . api ) : undefined ;
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
adapter = new c . d . bchAdapter . BchWallet ( root , {
walletId : entry . id ,
storage : c . api . storage ,
log : ( ... a ) => c . api . log ( ` [ ${ entry . id } ] ` , ... a ) ,
onChange : ( ) => emitStateForWallet ( entry . id ) ,
feat(theseus/aegis): SVG coin logos, two-step coin/network picker, BCH Chipnet
- Inline SVG logos for BCH (green disc + ₿) and TRX (red disc + geometric T)
replace the 🟨/🔴/🔵 emoji in the sidebar header and wallet picker rows.
The approval overlay stays text-only ("Wallet: <name> — BCH · Mainnet")
because that surface renders plain rows, not HTML.
- Wallet picker's "Add wallet" is now two-step: click a coin to expand its
networks, then click a network to create the wallet. The flat list is gone.
- BCH Chipnet is a real chain option now: bchtest cashaddr prefix,
m/44'/1'/0' derivation (BIP44 testnet coin type), bundled Chipnet electrum
defaults, chipnet.imaginary.cash explorer, tbch.googol.cash faucet link
in Receive. The shared electrum-servers setting stays mainnet-only in
this rev; Chipnet uses adapter-embedded defaults.
- lib/chain-bch.js gained a BCH_NETWORKS table so mainnet vs chipnet
differences (prefix, path, servers, explorer, faucet) live in one place.
- Registry is grouped by coin ({networks:{…}}) instead of a flat
chain:network map — snapshot exposes coins[] for the panel and adds
coinLabel/networkLabel/testnet fields per wallet.
- Testnet wallets get a small "TEST" tag next to the network name so the
user can never mistake a chipnet or Nile balance for real money.
Legacy BCH mainnet index 0 derivation unchanged (bchwallet/mainnet/0 →
m/44'/145'/0' → bitcoincash prefix); the network parameter defaults to
"mainnet" and BCH_NETWORKS.mainnet reproduces the pre-change constants.
2026-09-07 01:07:31 +02:00
network : entry . network ,
servers ,
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
accountPath : entry . accountPath ,
} ) ;
} else if ( entry . chain === "trx" ) {
adapter = new c . d . tronAdapter . TronWallet ( root , entry . network , {
storage : c . api . storage ,
log : ( ... a ) => c . api . log ( ` [ ${ entry . id } ] ` , ... a ) ,
onChange : ( ) => emitStateForWallet ( entry . id ) ,
} ) ;
adapter . schedulePoll ( 20_000 ) ;
feat(theseus/aegis): fold Sia into the addon; add DGB (BIP84 native SegWit)
Aegis now covers four coins across two-step coin+network picks: BCH
(mainnet + chipnet), TRX (mainnet + Nile), SC (mainnet), DGB (mainnet).
- Sia (SC): pulled the standalone siawallet's lib into
bundled-addons/bchwallet/lib/sia/ and wrote lib/chain-sia.js exposing
the common adapter shape. The very first SC wallet the user adds in
Aegis reuses purpose "siawallet/mainnet/0" so pre-Aegis funds carry
over automatically; subsequent SC sub-accounts start at
"bchwallet/sc/mainnet/1". Per-wallet walletd URL setting; empty URL
shows a "Point Aegis at a walletd node" gate in the panel.
- Vault-derive gate now honors a manifest-declared `absorbs` list, so
Aegis's addon.json can list `absorbs: ["siawallet"]` and the derive()
guard accepts paths under either the current id or the absorbed one —
the mechanism a superseding add-on uses to inherit an older add-on's
keyspace without orphaning funds.
- DigiByte (DGB): lib/chain-dgb.js ports the relevant bits of the
SilentCode Digibyte design — SLIP-44 coin type 20, BIP84 native SegWit
(m/84'/20'/0'/0/x → dgb1q…) via ripemd160(sha256(pubkey)) + bech32.
ElectrumX-DGB backend reuses lib/electrum.js (public wss:50022 pool).
BIP143 P2WPKH sighash + witness-tx serialize implemented inline (no
FORKID — DGB uses standard Bitcoin sighash). Derivation cross-checked
against a known BIP39 vector in scratchpad/verify-dgb.mjs — the address
for "abandon×11 about, m/84'/20'/0'/0/0" is
dgb1q9gmf0pv8jdymcly6lz6fl7lf6mhslsd72e2jq8, matching iancoleman.io/bip39.
- Panel: SVG coin logos for SC (green disc with S) and DGB (blue
octagon with D) alongside the BCH/TRX marks. Chain-specific settings
block per coin (walletd URL for SC; derivation path for DGB). Balance
render uses BigInt-safe arithmetic so 24-decimal SC amounts don't
lose precision on the way through the panel; amount input on SC
returns a hastings string.
- Every chain adapter's snapshot fits the panel's shared shape
(address/balance/history/etc.), so future chains only need a new
chain-<x>.js file, a COINS registry entry, a matching case in
mountWallet, and an SVG logo.
Standalone siawallet addon stays as-is on disk; users can delete it once
they've confirmed Aegis shows the same balance. Nothing here disables it.
2026-09-07 01:56:25 +02:00
} else if ( entry . chain === "sc" ) {
// walletdUrl is per-Sia-wallet (each sub-account may point at a
// different node) and stored under the scoped wallets/<id>/walletdUrl
// key. Empty = the panel shows a "point me at walletd" gate.
const walletdUrl = String ( c . api . storage . get ( ` wallets/ ${ entry . id } /walletdUrl ` , "" ) || "" ) ;
adapter = new c . d . siaAdapter . SiaWallet ( root , {
walletId : entry . id ,
storage : c . api . storage ,
log : ( ... a ) => c . api . log ( ` [ ${ entry . id } ] ` , ... a ) ,
onChange : ( ) => emitStateForWallet ( entry . id ) ,
walletdUrl ,
} ) ;
if ( walletdUrl ) adapter . startPolling ( ) ;
} else if ( entry . chain === "dgb" ) {
adapter = new c . d . dgbAdapter . DgbWallet ( root , {
walletId : entry . id ,
storage : c . api . storage ,
log : ( ... a ) => c . api . log ( ` [ ${ entry . id } ] ` , ... a ) ,
onChange : ( ) => emitStateForWallet ( entry . id ) ,
accountPath : entry . accountPath ,
} ) ;
feat(theseus/aegis): Ethereum + Solana adapters, DGB address-family picker, Aegis-branded shield
Multi-currency coverage matches what aegis.x has been advertising: BCH,
TRX, SC, DGB, ETH, SOL — six coins, two-step coin/network picker for
each. Panel logos, favicon and fallback all read as Aegis.
- Ethereum (lib/chain-eth.js): mainnet + Sepolia. BIP44 m/44'/60'/0'/0/0
→ secp256k1 → EIP-55 checksummed hex address (verified against
MetaMask's canonical abandon×11 vector 0x9858EfFD23…4EcaEda94). JSON-RPC
backend (Cloudflare mainnet, PublicNode Sepolia by default; per-wallet
override). EIP-1559 send with an inline RLP encoder + secp256k1
recoverable sign; broadcast via eth_sendRawTransaction. personal_sign
message signing follows the \x19Ethereum Signed Message:\n prefix.
- Solana (lib/chain-sol.js): mainnet-beta + devnet. SLIP-0010 ed25519
derivation at m/44'/501'/0'/0' (all-hardened), base58 address (@noble
ed25519). SLIP-0010 layer verified against spec Test Vector 1 in
scratchpad/verify-slip10.mjs. Native SOL transfer via the system
program with compact-u16 message serialization + ed25519 sign +
sendTransaction. Devnet gets a faucet.solana.com link in Receive; the
panel appends ?cluster=devnet when opening the explorer.
- DGB address family selector (lib/chain-dgb.js already carried the
paths): the Settings block now shows a Native SegWit / Taproot /
Wrapped SegWit / Legacy P2PKH picker. Selecting a family auto-fills
the derivation-path input with that family's default; Apply
rebuilds the wallet against the new path. Address families exposed
via chainMeta.addressFamilies so the panel can render them from data.
- Panel branding: inline SVG shield (hexagonal aspis, same silhouette
as the aegis.x hero) replaces the "?" fallback in logoSvg() and is
what the header shows before a wallet is selected. Data-URI favicon
wired into panel.html so the Theseus sidebar tab icon reads as Aegis
rather than a chain-specific coin mark.
- QR payloads now follow each chain's own URI scheme (BIP21 for BCH/DGB,
EIP-681 for ETH, Solana Pay for SOL) so external scanners route the
scan to the right wallet.
Not shipped: EIP-1193 provider (window.ethereum) and wallet-adapter
protocol (window.solana). The signing paths exist; only the page-inject
bridge glue is missing. History for ETH/SOL is also empty in this rev —
both need indexer plumbing (Etherscan V2 for ETH, getSignaturesForAddress
+ getTransaction pagination for SOL).
2026-09-07 20:31:27 +02:00
} else if ( entry . chain === "eth" ) {
const rpcUrl = String ( c . api . storage . get ( ` wallets/ ${ entry . id } /rpcUrl ` , "" ) || "" ) ;
adapter = new c . d . ethAdapter . EthWallet ( root , entry . network , {
walletId : entry . id ,
storage : c . api . storage ,
log : ( ... a ) => c . api . log ( ` [ ${ entry . id } ] ` , ... a ) ,
onChange : ( ) => emitStateForWallet ( entry . id ) ,
rpcUrl ,
} ) ;
adapter . schedulePoll ( 20_000 ) ;
} else if ( entry . chain === "sol" ) {
const rpcUrl = String ( c . api . storage . get ( ` wallets/ ${ entry . id } /rpcUrl ` , "" ) || "" ) ;
adapter = new c . d . solAdapter . SolWallet ( root , entry . network , {
walletId : entry . id ,
storage : c . api . storage ,
log : ( ... a ) => c . api . log ( ` [ ${ entry . id } ] ` , ... a ) ,
onChange : ( ) => emitStateForWallet ( entry . id ) ,
rpcUrl ,
} ) ;
adapter . schedulePoll ( 20_000 ) ;
feat(theseus/aegis): Bitcoin adapter (mainnet + testnet3, BIP84 native SegWit)
Seven coins across twelve networks now — BTC joins the shipping roster.
- lib/chain-btc.js: BIP84 native SegWit — m/84'/0'/0'/0/x → bc1q…
(mainnet), m/84'/1'/0'/0/x → tb1q… (testnet3). Reuses the exact same
stack the DGB adapter already pulls in: bitcoinjs-lib for network
params + payments.p2wpkh + PSBT, bip32 for HD derivation, ecpair for
the Signer interface, ecc (@bitcoinerlab/secp256k1) for message-sign
recoverable sigs. No new npm deps.
- Backend: same lib/electrum.js Aegis uses for BCH and DGB — plugged
into a public Bitcoin ElectrumX pool (blockstream.info, lu.ke,
grey.pw) for mainnet and aranguren.org / blockstream.info:993 for
testnet3. Send flow: PSBT build + per-input signInput +
finalizeAllInputs + broadcast. BIP-137 recoverable message signing.
- Registered as btc:mainnet + btc:testnet in COINS with the orange
Bitcoin disc SVG logo. Mount case mirrors DGB (accountPath honored,
so switching to m/44'/0'/0' or m/49'/0'/0' via the setAccountPath
message gives legacy 1… or wrapped-segwit 3… — same one-line UI plumb
as the DGB address-family selector, deferred to a follow-up).
- Panel: sat as the small-unit label, bitcoin: BIP21 QR payload,
chain-aware send placeholder ("bc1q…" mainnet / "tb1q…" testnet).
- Verified: BIP84 spec test vector — abandon×11 mnemonic derives
bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu at m/84'/0'/0'/0/0
(byte-identical to the vector in the BIP text). Testnet variant
produces tb1q6rz28mcfaxtmd6v789l9rrlrusdprr9pqcpvkl at m/84'/1'/0'/0/0
(cross-checkable on iancoleman.io/bip39 with coin BTC Testnet).
2026-09-07 21:15:45 +02:00
} else if ( entry . chain === "btc" ) {
adapter = new c . d . btcAdapter . BtcWallet ( root , entry . network , {
walletId : entry . id ,
storage : c . api . storage ,
log : ( ... a ) => c . api . log ( ` [ ${ entry . id } ] ` , ... a ) ,
onChange : ( ) => emitStateForWallet ( entry . id ) ,
accountPath : entry . accountPath ,
} ) ;
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
} else {
throw new Error ( ` unknown chain ${ entry . chain } ` ) ;
}
rt . adapter = adapter ;
rt . phase = "ready" ;
// Kick a first fetch. Errors here don't fail the mount — the panel shows
// them per-wallet via snapshot.error.
adapter . refresh ( true ) . catch ( ( e ) => c . api . log ( ` [ ${ entry . id } ] initial refresh: ` , e ? . message || e ) ) ;
emitStateForWallet ( entry . id ) ;
} catch ( e ) {
rt . phase = "error" ;
rt . error = e ? . message || String ( e ) ;
emitState ( ) ;
} finally {
// Wipe the root buffer — the adapter has already turned it into keys.
if ( root ) try { root . fill ( 0 ) ; } catch { }
}
feat(theseus/bchwallet): receive + history — vault-derived keys, cashaddr, QR, electrum
Wallet core on mainnet:
- keys from api.vault.derive("bchwallet/mainnet/0") -> BIP32 m/44'/145'/0'
(@scure/bip32), never persisted; wiped on deactivate.
- lib/cashaddr.js (encode/decode + legacy Base58Check, spec vectors pass),
lib/keys.js (hash160, p2pkh, electrum scripthash, ECDSA DER + BIP-137
recoverable signing), lib/tx.js (serialization, SIGHASH_ALL|FORKID
digest, coin selection, fee estimate), lib/electrum.js (Fulcrum WSS
client with failover + subscriptions), lib/wallet.js (gap-limit scan,
balance, UTXOs, 25-tx history with per-tx deltas, cached public txs).
- qr.js: dependency-free QR encoder (byte mode, v1-10, EC M/L; verified
against jsQR).
- panel: balance header, Receive (QR, copy, next unused address, explorer),
History (deltas, confirmations, explorer links), Settings (derivation
path, electrum server list, xpub / approval-gated xprv reveal). Locked
and not-set-up vault states explained in-panel.
- host: api.import for ESM-only deps, api.openTab for explorer links; an
add-on whose activate() throws is no longer listed twice.
2026-09-06 02:46:41 +02:00
}
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
function unmountWallet ( walletId ) {
const rt = ctx . runtimes . get ( walletId ) ;
if ( rt && rt . adapter ) { try { rt . adapter . dispose ( ) ; } catch { } }
ctx . runtimes . delete ( walletId ) ;
feat(theseus/bchwallet): send — plan, approval overlay, sign, broadcast
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.
2026-09-06 02:49:09 +02:00
}
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
// ---- state / snapshot -------------------------------------------------------
function selectedWalletId ( ) {
const list = readWallets ( ctx . api ) || [ ] ;
if ( ! list . length ) return null ;
const saved = String ( ctx . api . storage . get ( "selectedWalletId" , "" ) || "" ) ;
if ( saved && list . some ( ( w ) => w . id === saved ) ) return saved ;
const dflt = list . find ( ( w ) => w . isDefault ) || list [ 0 ] ;
return dflt . id ;
feat(theseus/bchwallet): send — plan, approval overlay, sign, broadcast
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.
2026-09-06 02:49:09 +02:00
}
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
function walletEntries ( ) { return readWallets ( ctx . api ) || [ ] ; }
function overallPhase ( ) {
// If ANY wallet is nosetup, treat the whole addon as nosetup — the user
// hasn't unlocked / set up the vault, so no wallet can work.
const runtimes = [ ... ctx . runtimes . values ( ) ] ;
if ( ! runtimes . length ) return "locked" ;
if ( runtimes . some ( ( r ) => r . phase === "nosetup" ) ) return "nosetup" ;
if ( runtimes . some ( ( r ) => r . phase === "locked" ) ) return "locked" ;
return "ready" ;
}
function walletSummary ( w ) {
const meta = chainMeta ( w . chain , w . network ) ;
const rt = ctx . runtimes . get ( w . id ) ;
const snap = rt && rt . adapter ? rt . adapter . snapshot ( ) : null ;
return {
id : w . id , label : w . label , chain : w . chain , network : w . network , isDefault : ! ! w . isDefault , isLegacy : ! ! w . isLegacy ,
feat(theseus/aegis): SVG coin logos, two-step coin/network picker, BCH Chipnet
- Inline SVG logos for BCH (green disc + ₿) and TRX (red disc + geometric T)
replace the 🟨/🔴/🔵 emoji in the sidebar header and wallet picker rows.
The approval overlay stays text-only ("Wallet: <name> — BCH · Mainnet")
because that surface renders plain rows, not HTML.
- Wallet picker's "Add wallet" is now two-step: click a coin to expand its
networks, then click a network to create the wallet. The flat list is gone.
- BCH Chipnet is a real chain option now: bchtest cashaddr prefix,
m/44'/1'/0' derivation (BIP44 testnet coin type), bundled Chipnet electrum
defaults, chipnet.imaginary.cash explorer, tbch.googol.cash faucet link
in Receive. The shared electrum-servers setting stays mainnet-only in
this rev; Chipnet uses adapter-embedded defaults.
- lib/chain-bch.js gained a BCH_NETWORKS table so mainnet vs chipnet
differences (prefix, path, servers, explorer, faucet) live in one place.
- Registry is grouped by coin ({networks:{…}}) instead of a flat
chain:network map — snapshot exposes coins[] for the panel and adds
coinLabel/networkLabel/testnet fields per wallet.
- Testnet wallets get a small "TEST" tag next to the network name so the
user can never mistake a chipnet or Nile balance for real money.
Legacy BCH mainnet index 0 derivation unchanged (bchwallet/mainnet/0 →
m/44'/145'/0' → bitcoincash prefix); the network parameter defaults to
"mainnet" and BCH_NETWORKS.mainnet reproduces the pre-change constants.
2026-09-07 01:07:31 +02:00
logo : meta ? . logo || null , color : meta ? . color || "#888" ,
coinLabel : meta ? . coinLabel || w . chain , networkLabel : meta ? . networkLabel || w . network , testnet : ! ! meta ? . testnet ,
ticker : meta ? . ticker || "?" , short : meta ? . short || w . chain , decimals : meta ? . decimals || 8 ,
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
address : snap ? . address || null ,
balance : snap ? . balance || { confirmed : 0 , unconfirmed : 0 } ,
phase : rt ? . phase || "locked" ,
error : rt ? . error || null ,
} ;
}
function snapshotForSelected ( ) {
const id = selectedWalletId ( ) ;
if ( ! id ) return { phase : "empty" } ;
const rt = ctx . runtimes . get ( id ) ;
const entry = walletEntries ( ) . find ( ( w ) => w . id === id ) ;
const meta = entry ? chainMeta ( entry . chain , entry . network ) : null ;
const base = {
walletId : id ,
label : entry ? . label ,
chain : entry ? . chain ,
network : entry ? . network ,
isLegacy : ! ! entry ? . isLegacy ,
feat(theseus/aegis): SVG coin logos, two-step coin/network picker, BCH Chipnet
- Inline SVG logos for BCH (green disc + ₿) and TRX (red disc + geometric T)
replace the 🟨/🔴/🔵 emoji in the sidebar header and wallet picker rows.
The approval overlay stays text-only ("Wallet: <name> — BCH · Mainnet")
because that surface renders plain rows, not HTML.
- Wallet picker's "Add wallet" is now two-step: click a coin to expand its
networks, then click a network to create the wallet. The flat list is gone.
- BCH Chipnet is a real chain option now: bchtest cashaddr prefix,
m/44'/1'/0' derivation (BIP44 testnet coin type), bundled Chipnet electrum
defaults, chipnet.imaginary.cash explorer, tbch.googol.cash faucet link
in Receive. The shared electrum-servers setting stays mainnet-only in
this rev; Chipnet uses adapter-embedded defaults.
- lib/chain-bch.js gained a BCH_NETWORKS table so mainnet vs chipnet
differences (prefix, path, servers, explorer, faucet) live in one place.
- Registry is grouped by coin ({networks:{…}}) instead of a flat
chain:network map — snapshot exposes coins[] for the panel and adds
coinLabel/networkLabel/testnet fields per wallet.
- Testnet wallets get a small "TEST" tag next to the network name so the
user can never mistake a chipnet or Nile balance for real money.
Legacy BCH mainnet index 0 derivation unchanged (bchwallet/mainnet/0 →
m/44'/145'/0' → bitcoincash prefix); the network parameter defaults to
"mainnet" and BCH_NETWORKS.mainnet reproduces the pre-change constants.
2026-09-07 01:07:31 +02:00
meta : meta ? {
logo : meta . logo , color : meta . color , short : meta . short , ticker : meta . ticker , decimals : meta . decimals ,
coinLabel : meta . coinLabel , networkLabel : meta . networkLabel , testnet : meta . testnet ,
feat(theseus/aegis): Ethereum + Solana adapters, DGB address-family picker, Aegis-branded shield
Multi-currency coverage matches what aegis.x has been advertising: BCH,
TRX, SC, DGB, ETH, SOL — six coins, two-step coin/network picker for
each. Panel logos, favicon and fallback all read as Aegis.
- Ethereum (lib/chain-eth.js): mainnet + Sepolia. BIP44 m/44'/60'/0'/0/0
→ secp256k1 → EIP-55 checksummed hex address (verified against
MetaMask's canonical abandon×11 vector 0x9858EfFD23…4EcaEda94). JSON-RPC
backend (Cloudflare mainnet, PublicNode Sepolia by default; per-wallet
override). EIP-1559 send with an inline RLP encoder + secp256k1
recoverable sign; broadcast via eth_sendRawTransaction. personal_sign
message signing follows the \x19Ethereum Signed Message:\n prefix.
- Solana (lib/chain-sol.js): mainnet-beta + devnet. SLIP-0010 ed25519
derivation at m/44'/501'/0'/0' (all-hardened), base58 address (@noble
ed25519). SLIP-0010 layer verified against spec Test Vector 1 in
scratchpad/verify-slip10.mjs. Native SOL transfer via the system
program with compact-u16 message serialization + ed25519 sign +
sendTransaction. Devnet gets a faucet.solana.com link in Receive; the
panel appends ?cluster=devnet when opening the explorer.
- DGB address family selector (lib/chain-dgb.js already carried the
paths): the Settings block now shows a Native SegWit / Taproot /
Wrapped SegWit / Legacy P2PKH picker. Selecting a family auto-fills
the derivation-path input with that family's default; Apply
rebuilds the wallet against the new path. Address families exposed
via chainMeta.addressFamilies so the panel can render them from data.
- Panel branding: inline SVG shield (hexagonal aspis, same silhouette
as the aegis.x hero) replaces the "?" fallback in logoSvg() and is
what the header shows before a wallet is selected. Data-URI favicon
wired into panel.html so the Theseus sidebar tab icon reads as Aegis
rather than a chain-specific coin mark.
- QR payloads now follow each chain's own URI scheme (BIP21 for BCH/DGB,
EIP-681 for ETH, Solana Pay for SOL) so external scanners route the
scan to the right wallet.
Not shipped: EIP-1193 provider (window.ethereum) and wallet-adapter
protocol (window.solana). The signing paths exist; only the page-inject
bridge glue is missing. History for ETH/SOL is also empty in this rev —
both need indexer plumbing (Etherscan V2 for ETH, getSignaturesForAddress
+ getTransaction pagination for SOL).
2026-09-07 20:31:27 +02:00
addressFamilies : meta . addressFamilies , defaultAccountPath : meta . defaultAccountPath ,
feat(theseus/aegis): SVG coin logos, two-step coin/network picker, BCH Chipnet
- Inline SVG logos for BCH (green disc + ₿) and TRX (red disc + geometric T)
replace the 🟨/🔴/🔵 emoji in the sidebar header and wallet picker rows.
The approval overlay stays text-only ("Wallet: <name> — BCH · Mainnet")
because that surface renders plain rows, not HTML.
- Wallet picker's "Add wallet" is now two-step: click a coin to expand its
networks, then click a network to create the wallet. The flat list is gone.
- BCH Chipnet is a real chain option now: bchtest cashaddr prefix,
m/44'/1'/0' derivation (BIP44 testnet coin type), bundled Chipnet electrum
defaults, chipnet.imaginary.cash explorer, tbch.googol.cash faucet link
in Receive. The shared electrum-servers setting stays mainnet-only in
this rev; Chipnet uses adapter-embedded defaults.
- lib/chain-bch.js gained a BCH_NETWORKS table so mainnet vs chipnet
differences (prefix, path, servers, explorer, faucet) live in one place.
- Registry is grouped by coin ({networks:{…}}) instead of a flat
chain:network map — snapshot exposes coins[] for the panel and adds
coinLabel/networkLabel/testnet fields per wallet.
- Testnet wallets get a small "TEST" tag next to the network name so the
user can never mistake a chipnet or Nile balance for real money.
Legacy BCH mainnet index 0 derivation unchanged (bchwallet/mainnet/0 →
m/44'/145'/0' → bitcoincash prefix); the network parameter defaults to
"mainnet" and BCH_NETWORKS.mainnet reproduces the pre-change constants.
2026-09-07 01:07:31 +02:00
} : null ,
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
supportsMessageSign : ! ! meta ? . supportsMessageSign ,
phase : rt ? . phase || "locked" ,
error : rt ? . error || null ,
} ;
if ( rt && rt . adapter ) Object . assign ( base , rt . adapter . snapshot ( ) ) ;
return base ;
}
function fullState ( ) {
return {
overallPhase : overallPhase ( ) ,
selectedWalletId : selectedWalletId ( ) ,
wallets : walletEntries ( ) . map ( walletSummary ) ,
selected : snapshotForSelected ( ) ,
bchServers : {
list : bchServerList ( ctx . api ) ,
custom : Array . isArray ( ctx . api . storage . get ( "servers" , null ) ) ,
} ,
feat(theseus/aegis): SVG coin logos, two-step coin/network picker, BCH Chipnet
- Inline SVG logos for BCH (green disc + ₿) and TRX (red disc + geometric T)
replace the 🟨/🔴/🔵 emoji in the sidebar header and wallet picker rows.
The approval overlay stays text-only ("Wallet: <name> — BCH · Mainnet")
because that surface renders plain rows, not HTML.
- Wallet picker's "Add wallet" is now two-step: click a coin to expand its
networks, then click a network to create the wallet. The flat list is gone.
- BCH Chipnet is a real chain option now: bchtest cashaddr prefix,
m/44'/1'/0' derivation (BIP44 testnet coin type), bundled Chipnet electrum
defaults, chipnet.imaginary.cash explorer, tbch.googol.cash faucet link
in Receive. The shared electrum-servers setting stays mainnet-only in
this rev; Chipnet uses adapter-embedded defaults.
- lib/chain-bch.js gained a BCH_NETWORKS table so mainnet vs chipnet
differences (prefix, path, servers, explorer, faucet) live in one place.
- Registry is grouped by coin ({networks:{…}}) instead of a flat
chain:network map — snapshot exposes coins[] for the panel and adds
coinLabel/networkLabel/testnet fields per wallet.
- Testnet wallets get a small "TEST" tag next to the network name so the
user can never mistake a chipnet or Nile balance for real money.
Legacy BCH mainnet index 0 derivation unchanged (bchwallet/mainnet/0 →
m/44'/145'/0' → bitcoincash prefix); the network parameter defaults to
"mainnet" and BCH_NETWORKS.mainnet reproduces the pre-change constants.
2026-09-07 01:07:31 +02:00
coins : coinsForPanel ( ) ,
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
} ;
}
function emitState ( ) { try { ctx . api . emit ( "state" , fullState ( ) ) ; } catch { } }
function emitStateForWallet ( id ) {
// Any wallet change fans out to the panel with the full state so the
// wallet list balances update in the header too.
if ( ! ctx || ! ctx . runtimes . has ( id ) ) return ;
emitState ( ) ;
}
// ---- panel messages ---------------------------------------------------------
function requireWallet ( id ) {
const rt = ctx . runtimes . get ( id ) ;
if ( ! rt || rt . phase !== "ready" || ! rt . adapter ) throw new Error ( "wallet is not ready (vault locked?)" ) ;
return rt ;
}
function requireSelected ( ) { return requireWallet ( selectedWalletId ( ) ) ; }
function fromPanel ( m ) { if ( ! m || m . from !== "panel" ) throw new Error ( "panel-only message" ) ; }
function fromPage ( m ) {
if ( ! m || m . from !== "page" || ! m . origin ) throw new Error ( "page-only message" ) ;
return m . origin ;
}
const fmtBch = ( sats ) => ( Number ( sats ) / 1e8 ) . toFixed ( 8 ) . replace ( /(\.\d*?[1-9])0+$|\.0+$/ , "$1" ) ;
const fmtTrx = ( sun ) => ( Number ( sun ) / 1e6 ) . toFixed ( 6 ) . replace ( /(\.\d*?[1-9])0+$|\.0+$/ , "$1" ) ;
function fmtValue ( units , decimals ) {
const n = Number ( units ) / Math . pow ( 10 , decimals ) ;
return n . toFixed ( decimals ) . replace ( /(\.\d*?[1-9])0+$|\.0+$/ , "$1" ) ;
feat(theseus/bchwallet): receive + history — vault-derived keys, cashaddr, QR, electrum
Wallet core on mainnet:
- keys from api.vault.derive("bchwallet/mainnet/0") -> BIP32 m/44'/145'/0'
(@scure/bip32), never persisted; wiped on deactivate.
- lib/cashaddr.js (encode/decode + legacy Base58Check, spec vectors pass),
lib/keys.js (hash160, p2pkh, electrum scripthash, ECDSA DER + BIP-137
recoverable signing), lib/tx.js (serialization, SIGHASH_ALL|FORKID
digest, coin selection, fee estimate), lib/electrum.js (Fulcrum WSS
client with failover + subscriptions), lib/wallet.js (gap-limit scan,
balance, UTXOs, 25-tx history with per-tx deltas, cached public txs).
- qr.js: dependency-free QR encoder (byte mode, v1-10, EC M/L; verified
against jsQR).
- panel: balance header, Receive (QR, copy, next unused address, explorer),
History (deltas, confirmations, explorer links), Settings (derivation
path, electrum server list, xpub / approval-gated xprv reveal). Locked
and not-set-up vault states explained in-panel.
- host: api.import for ESM-only deps, api.openTab for explorer links; an
add-on whose activate() throws is no longer listed twice.
2026-09-06 02:46:41 +02:00
}
function registerPanelMessages ( api ) {
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
api . onMessage ( "state" , ( _p , m ) => { fromPanel ( m ) ; return fullState ( ) ; } ) ;
api . onMessage ( "selectWallet" , ( p , m ) => {
fromPanel ( m ) ;
const id = String ( p && p . id || "" ) ;
if ( ! walletEntries ( ) . some ( ( w ) => w . id === id ) ) throw new Error ( "unknown wallet" ) ;
api . storage . set ( "selectedWalletId" , id ) ;
emitState ( ) ;
return fullState ( ) ;
} ) ;
api . onMessage ( "addWallet" , async ( p , m ) => {
fromPanel ( m ) ;
const chain = String ( p && p . chain || "" ) ;
const network = String ( p && p . network || "" ) ;
const meta = chainMeta ( chain , network ) ;
if ( ! meta ) throw new Error ( "unknown chain/network" ) ;
const list = walletEntries ( ) . slice ( ) ;
feat(theseus/aegis): fold Sia into the addon; add DGB (BIP84 native SegWit)
Aegis now covers four coins across two-step coin+network picks: BCH
(mainnet + chipnet), TRX (mainnet + Nile), SC (mainnet), DGB (mainnet).
- Sia (SC): pulled the standalone siawallet's lib into
bundled-addons/bchwallet/lib/sia/ and wrote lib/chain-sia.js exposing
the common adapter shape. The very first SC wallet the user adds in
Aegis reuses purpose "siawallet/mainnet/0" so pre-Aegis funds carry
over automatically; subsequent SC sub-accounts start at
"bchwallet/sc/mainnet/1". Per-wallet walletd URL setting; empty URL
shows a "Point Aegis at a walletd node" gate in the panel.
- Vault-derive gate now honors a manifest-declared `absorbs` list, so
Aegis's addon.json can list `absorbs: ["siawallet"]` and the derive()
guard accepts paths under either the current id or the absorbed one —
the mechanism a superseding add-on uses to inherit an older add-on's
keyspace without orphaning funds.
- DigiByte (DGB): lib/chain-dgb.js ports the relevant bits of the
SilentCode Digibyte design — SLIP-44 coin type 20, BIP84 native SegWit
(m/84'/20'/0'/0/x → dgb1q…) via ripemd160(sha256(pubkey)) + bech32.
ElectrumX-DGB backend reuses lib/electrum.js (public wss:50022 pool).
BIP143 P2WPKH sighash + witness-tx serialize implemented inline (no
FORKID — DGB uses standard Bitcoin sighash). Derivation cross-checked
against a known BIP39 vector in scratchpad/verify-dgb.mjs — the address
for "abandon×11 about, m/84'/20'/0'/0/0" is
dgb1q9gmf0pv8jdymcly6lz6fl7lf6mhslsd72e2jq8, matching iancoleman.io/bip39.
- Panel: SVG coin logos for SC (green disc with S) and DGB (blue
octagon with D) alongside the BCH/TRX marks. Chain-specific settings
block per coin (walletd URL for SC; derivation path for DGB). Balance
render uses BigInt-safe arithmetic so 24-decimal SC amounts don't
lose precision on the way through the panel; amount input on SC
returns a hastings string.
- Every chain adapter's snapshot fits the panel's shared shape
(address/balance/history/etc.), so future chains only need a new
chain-<x>.js file, a COINS registry entry, a matching case in
mountWallet, and an SVG logo.
Standalone siawallet addon stays as-is on disk; users can delete it once
they've confirmed Aegis shows the same balance. Nothing here disables it.
2026-09-07 01:56:25 +02:00
// If this coin+network declares a `legacyFirstPurpose` (SC does, to
// recover funds from the standalone siawallet addon) and no wallet of
// this coin+network exists yet, use that purpose verbatim. The bump
// to the /aegis-namespaced/ prefix only starts on the second sub-account.
const netMeta = COINS [ chain ] ? . networks ? . [ network ] || { } ;
const existingForCoin = list . filter ( ( w ) => w . chain === chain && w . network === network && ! w . isLegacy ) ;
let purpose , isLegacy = false ;
if ( netMeta . legacyFirstPurpose && existingForCoin . length === 0
&& ! list . some ( ( w ) => w . purpose === netMeta . legacyFirstPurpose ) ) {
purpose = netMeta . legacyFirstPurpose ;
isLegacy = true ;
} else {
const index = nextIndex ( list , meta ) ;
purpose = meta . purposePrefix + index ;
}
const idIndex = nextIndex ( list , meta ) ;
const id = makeWalletId ( meta , idIndex ) ;
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
if ( list . some ( ( w ) => w . id === id || w . purpose === purpose ) ) throw new Error ( "duplicate wallet" ) ;
const label = String ( p && p . label || "" ) . trim ( ) || autoLabel ( meta , list ) ;
feat(theseus/aegis): fold Sia into the addon; add DGB (BIP84 native SegWit)
Aegis now covers four coins across two-step coin+network picks: BCH
(mainnet + chipnet), TRX (mainnet + Nile), SC (mainnet), DGB (mainnet).
- Sia (SC): pulled the standalone siawallet's lib into
bundled-addons/bchwallet/lib/sia/ and wrote lib/chain-sia.js exposing
the common adapter shape. The very first SC wallet the user adds in
Aegis reuses purpose "siawallet/mainnet/0" so pre-Aegis funds carry
over automatically; subsequent SC sub-accounts start at
"bchwallet/sc/mainnet/1". Per-wallet walletd URL setting; empty URL
shows a "Point Aegis at a walletd node" gate in the panel.
- Vault-derive gate now honors a manifest-declared `absorbs` list, so
Aegis's addon.json can list `absorbs: ["siawallet"]` and the derive()
guard accepts paths under either the current id or the absorbed one —
the mechanism a superseding add-on uses to inherit an older add-on's
keyspace without orphaning funds.
- DigiByte (DGB): lib/chain-dgb.js ports the relevant bits of the
SilentCode Digibyte design — SLIP-44 coin type 20, BIP84 native SegWit
(m/84'/20'/0'/0/x → dgb1q…) via ripemd160(sha256(pubkey)) + bech32.
ElectrumX-DGB backend reuses lib/electrum.js (public wss:50022 pool).
BIP143 P2WPKH sighash + witness-tx serialize implemented inline (no
FORKID — DGB uses standard Bitcoin sighash). Derivation cross-checked
against a known BIP39 vector in scratchpad/verify-dgb.mjs — the address
for "abandon×11 about, m/84'/20'/0'/0/0" is
dgb1q9gmf0pv8jdymcly6lz6fl7lf6mhslsd72e2jq8, matching iancoleman.io/bip39.
- Panel: SVG coin logos for SC (green disc with S) and DGB (blue
octagon with D) alongside the BCH/TRX marks. Chain-specific settings
block per coin (walletd URL for SC; derivation path for DGB). Balance
render uses BigInt-safe arithmetic so 24-decimal SC amounts don't
lose precision on the way through the panel; amount input on SC
returns a hastings string.
- Every chain adapter's snapshot fits the panel's shared shape
(address/balance/history/etc.), so future chains only need a new
chain-<x>.js file, a COINS registry entry, a matching case in
mountWallet, and an SVG logo.
Standalone siawallet addon stays as-is on disk; users can delete it once
they've confirmed Aegis shows the same balance. Nothing here disables it.
2026-09-07 01:56:25 +02:00
const entry = { id , label , chain , network , purpose , isLegacy , createdAt : Date . now ( ) } ;
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
list . push ( entry ) ;
writeWallets ( api , list ) ;
api . storage . set ( "selectedWalletId" , id ) ;
ctx . runtimes . set ( id , { entry , phase : "locked" , error : null , adapter : null } ) ;
emitState ( ) ;
await mountWallet ( entry ) ;
return fullState ( ) ;
} ) ;
api . onMessage ( "removeWallet" , ( p , m ) => {
fromPanel ( m ) ;
const id = String ( p && p . id || "" ) ;
const list = walletEntries ( ) ;
const entry = list . find ( ( w ) => w . id === id ) ;
if ( ! entry ) throw new Error ( "unknown wallet" ) ;
if ( entry . isDefault ) throw new Error ( "the default wallet cannot be removed" ) ;
const next = list . filter ( ( w ) => w . id !== id ) ;
writeWallets ( api , next ) ;
if ( selectedWalletId ( ) === id ) api . storage . set ( "selectedWalletId" , next [ 0 ] ? . id || "" ) ;
unmountWallet ( id ) ;
// Drop per-wallet storage subtree.
const all = api . storage . all ? api . storage . all ( ) : { } ;
const prefix = ` wallets/ ${ id } / ` ;
for ( const k of Object . keys ( all ) ) if ( k . startsWith ( prefix ) ) api . storage . set ( k , null ) ;
emitState ( ) ;
return fullState ( ) ;
} ) ;
api . onMessage ( "renameWallet" , ( p , m ) => {
fromPanel ( m ) ;
const id = String ( p && p . id || "" ) ;
const label = String ( p && p . label || "" ) . trim ( ) . slice ( 0 , 60 ) ;
if ( ! label ) throw new Error ( "label required" ) ;
const list = walletEntries ( ) ;
const entry = list . find ( ( w ) => w . id === id ) ;
if ( ! entry ) throw new Error ( "unknown wallet" ) ;
entry . label = label ;
writeWallets ( api , list ) ;
emitState ( ) ;
return fullState ( ) ;
} ) ;
api . onMessage ( "refresh" , async ( _p , m ) => { fromPanel ( m ) ; const rt = requireSelected ( ) ; await rt . adapter . refresh ( true ) ; return snapshotForSelected ( ) ; } ) ;
api . onMessage ( "nextAddress" , ( _p , m ) => {
fromPanel ( m ) ;
const rt = requireSelected ( ) ;
if ( rt . entry . chain !== "bch" ) throw new Error ( "only BCH wallets have multiple receive addresses" ) ;
rt . adapter . nextAddress ( ) ;
return snapshotForSelected ( ) ;
} ) ;
feat(theseus/bchwallet): receive + history — vault-derived keys, cashaddr, QR, electrum
Wallet core on mainnet:
- keys from api.vault.derive("bchwallet/mainnet/0") -> BIP32 m/44'/145'/0'
(@scure/bip32), never persisted; wiped on deactivate.
- lib/cashaddr.js (encode/decode + legacy Base58Check, spec vectors pass),
lib/keys.js (hash160, p2pkh, electrum scripthash, ECDSA DER + BIP-137
recoverable signing), lib/tx.js (serialization, SIGHASH_ALL|FORKID
digest, coin selection, fee estimate), lib/electrum.js (Fulcrum WSS
client with failover + subscriptions), lib/wallet.js (gap-limit scan,
balance, UTXOs, 25-tx history with per-tx deltas, cached public txs).
- qr.js: dependency-free QR encoder (byte mode, v1-10, EC M/L; verified
against jsQR).
- panel: balance header, Receive (QR, copy, next unused address, explorer),
History (deltas, confirmations, explorer links), Settings (derivation
path, electrum server list, xpub / approval-gated xprv reveal). Locked
and not-set-up vault states explained in-panel.
- host: api.import for ESM-only deps, api.openTab for explorer links; an
add-on whose activate() throws is no longer listed twice.
2026-09-06 02:46:41 +02:00
api . onMessage ( "openUrl" , ( p , m ) => { fromPanel ( m ) ; api . openTab ( String ( p && p . url || "" ) ) ; return true ; } ) ;
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
api . onMessage ( "setBchServers" , ( p , m ) => {
feat(theseus/bchwallet): receive + history — vault-derived keys, cashaddr, QR, electrum
Wallet core on mainnet:
- keys from api.vault.derive("bchwallet/mainnet/0") -> BIP32 m/44'/145'/0'
(@scure/bip32), never persisted; wiped on deactivate.
- lib/cashaddr.js (encode/decode + legacy Base58Check, spec vectors pass),
lib/keys.js (hash160, p2pkh, electrum scripthash, ECDSA DER + BIP-137
recoverable signing), lib/tx.js (serialization, SIGHASH_ALL|FORKID
digest, coin selection, fee estimate), lib/electrum.js (Fulcrum WSS
client with failover + subscriptions), lib/wallet.js (gap-limit scan,
balance, UTXOs, 25-tx history with per-tx deltas, cached public txs).
- qr.js: dependency-free QR encoder (byte mode, v1-10, EC M/L; verified
against jsQR).
- panel: balance header, Receive (QR, copy, next unused address, explorer),
History (deltas, confirmations, explorer links), Settings (derivation
path, electrum server list, xpub / approval-gated xprv reveal). Locked
and not-set-up vault states explained in-panel.
- host: api.import for ESM-only deps, api.openTab for explorer links; an
add-on whose activate() throws is no longer listed twice.
2026-09-06 02:46:41 +02:00
fromPanel ( m ) ;
const patch = p || { } ;
if ( "servers" in patch ) {
const list = Array . isArray ( patch . servers ) ? patch . servers . map ( ( s ) => String ( s ) . trim ( ) ) . filter ( Boolean ) : [ ] ;
for ( const s of list ) if ( ! /^wss?:\/\/[^/\s]+$/i . test ( s ) ) throw new Error ( ` server must be ws(s)://host:port — got ${ s } ` ) ;
api . storage . set ( "servers" , list . length ? list : null ) ;
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
// Push the new server list into every mounted BCH wallet.
for ( const rt of ctx . runtimes . values ( ) ) {
if ( rt . entry . chain === "bch" && rt . adapter ) rt . adapter . setServers ( bchServerList ( api ) ) ;
}
feat(theseus/bchwallet): receive + history — vault-derived keys, cashaddr, QR, electrum
Wallet core on mainnet:
- keys from api.vault.derive("bchwallet/mainnet/0") -> BIP32 m/44'/145'/0'
(@scure/bip32), never persisted; wiped on deactivate.
- lib/cashaddr.js (encode/decode + legacy Base58Check, spec vectors pass),
lib/keys.js (hash160, p2pkh, electrum scripthash, ECDSA DER + BIP-137
recoverable signing), lib/tx.js (serialization, SIGHASH_ALL|FORKID
digest, coin selection, fee estimate), lib/electrum.js (Fulcrum WSS
client with failover + subscriptions), lib/wallet.js (gap-limit scan,
balance, UTXOs, 25-tx history with per-tx deltas, cached public txs).
- qr.js: dependency-free QR encoder (byte mode, v1-10, EC M/L; verified
against jsQR).
- panel: balance header, Receive (QR, copy, next unused address, explorer),
History (deltas, confirmations, explorer links), Settings (derivation
path, electrum server list, xpub / approval-gated xprv reveal). Locked
and not-set-up vault states explained in-panel.
- host: api.import for ESM-only deps, api.openTab for explorer links; an
add-on whose activate() throws is no longer listed twice.
2026-09-06 02:46:41 +02:00
}
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
return fullState ( ) ;
} ) ;
api . onMessage ( "setAccountPath" , ( p , m ) => {
fromPanel ( m ) ;
const patch = p || { } ;
const id = String ( patch . id || selectedWalletId ( ) ) ;
const entry = walletEntries ( ) . find ( ( w ) => w . id === id ) ;
if ( ! entry ) throw new Error ( "unknown wallet" ) ;
feat(theseus/aegis): Bitcoin adapter (mainnet + testnet3, BIP84 native SegWit)
Seven coins across twelve networks now — BTC joins the shipping roster.
- lib/chain-btc.js: BIP84 native SegWit — m/84'/0'/0'/0/x → bc1q…
(mainnet), m/84'/1'/0'/0/x → tb1q… (testnet3). Reuses the exact same
stack the DGB adapter already pulls in: bitcoinjs-lib for network
params + payments.p2wpkh + PSBT, bip32 for HD derivation, ecpair for
the Signer interface, ecc (@bitcoinerlab/secp256k1) for message-sign
recoverable sigs. No new npm deps.
- Backend: same lib/electrum.js Aegis uses for BCH and DGB — plugged
into a public Bitcoin ElectrumX pool (blockstream.info, lu.ke,
grey.pw) for mainnet and aranguren.org / blockstream.info:993 for
testnet3. Send flow: PSBT build + per-input signInput +
finalizeAllInputs + broadcast. BIP-137 recoverable message signing.
- Registered as btc:mainnet + btc:testnet in COINS with the orange
Bitcoin disc SVG logo. Mount case mirrors DGB (accountPath honored,
so switching to m/44'/0'/0' or m/49'/0'/0' via the setAccountPath
message gives legacy 1… or wrapped-segwit 3… — same one-line UI plumb
as the DGB address-family selector, deferred to a follow-up).
- Panel: sat as the small-unit label, bitcoin: BIP21 QR payload,
chain-aware send placeholder ("bc1q…" mainnet / "tb1q…" testnet).
- Verified: BIP84 spec test vector — abandon×11 mnemonic derives
bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu at m/84'/0'/0'/0/0
(byte-identical to the vector in the BIP text). Testnet variant
produces tb1q6rz28mcfaxtmd6v789l9rrlrusdprr9pqcpvkl at m/84'/1'/0'/0/0
(cross-checkable on iancoleman.io/bip39 with coin BTC Testnet).
2026-09-07 21:15:45 +02:00
if ( ! [ "bch" , "dgb" , "btc" ] . includes ( entry . chain ) ) throw new Error ( "account path is a BCH/BTC/DGB-only setting" ) ;
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
const v = String ( patch . accountPath || "" ) . trim ( ) ;
feat(theseus/aegis): Bitcoin adapter (mainnet + testnet3, BIP84 native SegWit)
Seven coins across twelve networks now — BTC joins the shipping roster.
- lib/chain-btc.js: BIP84 native SegWit — m/84'/0'/0'/0/x → bc1q…
(mainnet), m/84'/1'/0'/0/x → tb1q… (testnet3). Reuses the exact same
stack the DGB adapter already pulls in: bitcoinjs-lib for network
params + payments.p2wpkh + PSBT, bip32 for HD derivation, ecpair for
the Signer interface, ecc (@bitcoinerlab/secp256k1) for message-sign
recoverable sigs. No new npm deps.
- Backend: same lib/electrum.js Aegis uses for BCH and DGB — plugged
into a public Bitcoin ElectrumX pool (blockstream.info, lu.ke,
grey.pw) for mainnet and aranguren.org / blockstream.info:993 for
testnet3. Send flow: PSBT build + per-input signInput +
finalizeAllInputs + broadcast. BIP-137 recoverable message signing.
- Registered as btc:mainnet + btc:testnet in COINS with the orange
Bitcoin disc SVG logo. Mount case mirrors DGB (accountPath honored,
so switching to m/44'/0'/0' or m/49'/0'/0' via the setAccountPath
message gives legacy 1… or wrapped-segwit 3… — same one-line UI plumb
as the DGB address-family selector, deferred to a follow-up).
- Panel: sat as the small-unit label, bitcoin: BIP21 QR payload,
chain-aware send placeholder ("bc1q…" mainnet / "tb1q…" testnet).
- Verified: BIP84 spec test vector — abandon×11 mnemonic derives
bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu at m/84'/0'/0'/0/0
(byte-identical to the vector in the BIP text). Testnet variant
produces tb1q6rz28mcfaxtmd6v789l9rrlrusdprr9pqcpvkl at m/84'/1'/0'/0/0
(cross-checkable on iancoleman.io/bip39 with coin BTC Testnet).
2026-09-07 21:15:45 +02:00
if ( v && ! /^m(\/\d+'?)+$/ . test ( v ) ) throw new Error ( "derivation path must look like m/84'/0'/0'" ) ;
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
const list = walletEntries ( ) ;
const idx = list . findIndex ( ( w ) => w . id === id ) ;
feat(theseus/aegis): BTC address-family picker (BIP44/49/84/86 + Taproot)
BTC now matches DGB's family selector: pick BIP44 (1…), BIP49 (3…),
BIP84 (bc1q…, default) or BIP86 Taproot (bc1p…) from Settings, on
mainnet or testnet3 (paths shift coin type 0 → 1 automatically).
- lib/chain-btc.js: paymentFor(purpose, node, network) returns the
right bitcoinjs-lib payment (p2pkh / p2sh(p2wpkh) / p2wpkh / p2tr)
keyed off the derivation path's purpose. WalletKeys.entry captures
the family, redeem script (BIP49) and internal x-only pubkey
(BIP86) alongside the standard script/address fields.
bitcoinjs.initEccLib(ecc) is called once at load so p2tr resolves.
- Registry: BTC + DGB address families are purpose-only now; a
helper (addressFamiliesFor / defaultAccountPathFor) computes the
concrete m/PURPOSE'/COIN'/0' per (chain, network) — coin type
{mainnet:0, testnet:1} for BTC, always 20 for DGB. chainMeta
expands the list so the panel doesn't need per-chain knowledge.
- Panel: #btcSettings block mirrors #dgbSettings (family select →
path input auto-fill → Apply). The family-select listener + the
fillFamilyPicker() helper are shared between DGB and BTC — the
DOM prefix is the only per-chain input.
- Send is wired for BIP84 (default) and BIP49 (adds redeemScript to
the PSBT input). BIP44 (needs nonWitnessUtxo prev-tx fetch) and
BIP86 (needs tap-tweaked signer) throw a clear "not yet in this
rev — sweep to BIP84" error so users hit it at plan time, not at
broadcast time. Receive works on all four families today.
- Verified all four families derive the canonical BIP44/49/84/86
spec test vectors for the standard abandon×11 mnemonic — see
scratchpad/verify-btc-families.mjs. Byte-identical to the BIPs.
2026-09-07 21:23:15 +02:00
// Per-network default: BTC/DGB come from the registry helper, BCH keeps
// its historical m/44'/145'/0'.
const dflt = entry . chain === "bch"
? "m/44'/145'/0'"
: ( defaultAccountPathFor ( COINS [ entry . chain ] , entry . network ) || "m/84'/0'/0'" ) ;
feat(theseus/aegis): fold Sia into the addon; add DGB (BIP84 native SegWit)
Aegis now covers four coins across two-step coin+network picks: BCH
(mainnet + chipnet), TRX (mainnet + Nile), SC (mainnet), DGB (mainnet).
- Sia (SC): pulled the standalone siawallet's lib into
bundled-addons/bchwallet/lib/sia/ and wrote lib/chain-sia.js exposing
the common adapter shape. The very first SC wallet the user adds in
Aegis reuses purpose "siawallet/mainnet/0" so pre-Aegis funds carry
over automatically; subsequent SC sub-accounts start at
"bchwallet/sc/mainnet/1". Per-wallet walletd URL setting; empty URL
shows a "Point Aegis at a walletd node" gate in the panel.
- Vault-derive gate now honors a manifest-declared `absorbs` list, so
Aegis's addon.json can list `absorbs: ["siawallet"]` and the derive()
guard accepts paths under either the current id or the absorbed one —
the mechanism a superseding add-on uses to inherit an older add-on's
keyspace without orphaning funds.
- DigiByte (DGB): lib/chain-dgb.js ports the relevant bits of the
SilentCode Digibyte design — SLIP-44 coin type 20, BIP84 native SegWit
(m/84'/20'/0'/0/x → dgb1q…) via ripemd160(sha256(pubkey)) + bech32.
ElectrumX-DGB backend reuses lib/electrum.js (public wss:50022 pool).
BIP143 P2WPKH sighash + witness-tx serialize implemented inline (no
FORKID — DGB uses standard Bitcoin sighash). Derivation cross-checked
against a known BIP39 vector in scratchpad/verify-dgb.mjs — the address
for "abandon×11 about, m/84'/20'/0'/0/0" is
dgb1q9gmf0pv8jdymcly6lz6fl7lf6mhslsd72e2jq8, matching iancoleman.io/bip39.
- Panel: SVG coin logos for SC (green disc with S) and DGB (blue
octagon with D) alongside the BCH/TRX marks. Chain-specific settings
block per coin (walletd URL for SC; derivation path for DGB). Balance
render uses BigInt-safe arithmetic so 24-decimal SC amounts don't
lose precision on the way through the panel; amount input on SC
returns a hastings string.
- Every chain adapter's snapshot fits the panel's shared shape
(address/balance/history/etc.), so future chains only need a new
chain-<x>.js file, a COINS registry entry, a matching case in
mountWallet, and an SVG logo.
Standalone siawallet addon stays as-is on disk; users can delete it once
they've confirmed Aegis shows the same balance. Nothing here disables it.
2026-09-07 01:56:25 +02:00
list [ idx ] = { ... list [ idx ] , accountPath : v || dflt } ;
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
writeWallets ( api , list ) ;
const rt = ctx . runtimes . get ( id ) ;
if ( rt && rt . adapter ) { try { rt . adapter . dispose ( ) ; } catch { } rt . adapter = null ; rt . phase = "locked" ; }
mountWallet ( list [ idx ] ) ;
return fullState ( ) ;
} ) ;
feat(theseus/aegis): Ethereum + Solana adapters, DGB address-family picker, Aegis-branded shield
Multi-currency coverage matches what aegis.x has been advertising: BCH,
TRX, SC, DGB, ETH, SOL — six coins, two-step coin/network picker for
each. Panel logos, favicon and fallback all read as Aegis.
- Ethereum (lib/chain-eth.js): mainnet + Sepolia. BIP44 m/44'/60'/0'/0/0
→ secp256k1 → EIP-55 checksummed hex address (verified against
MetaMask's canonical abandon×11 vector 0x9858EfFD23…4EcaEda94). JSON-RPC
backend (Cloudflare mainnet, PublicNode Sepolia by default; per-wallet
override). EIP-1559 send with an inline RLP encoder + secp256k1
recoverable sign; broadcast via eth_sendRawTransaction. personal_sign
message signing follows the \x19Ethereum Signed Message:\n prefix.
- Solana (lib/chain-sol.js): mainnet-beta + devnet. SLIP-0010 ed25519
derivation at m/44'/501'/0'/0' (all-hardened), base58 address (@noble
ed25519). SLIP-0010 layer verified against spec Test Vector 1 in
scratchpad/verify-slip10.mjs. Native SOL transfer via the system
program with compact-u16 message serialization + ed25519 sign +
sendTransaction. Devnet gets a faucet.solana.com link in Receive; the
panel appends ?cluster=devnet when opening the explorer.
- DGB address family selector (lib/chain-dgb.js already carried the
paths): the Settings block now shows a Native SegWit / Taproot /
Wrapped SegWit / Legacy P2PKH picker. Selecting a family auto-fills
the derivation-path input with that family's default; Apply
rebuilds the wallet against the new path. Address families exposed
via chainMeta.addressFamilies so the panel can render them from data.
- Panel branding: inline SVG shield (hexagonal aspis, same silhouette
as the aegis.x hero) replaces the "?" fallback in logoSvg() and is
what the header shows before a wallet is selected. Data-URI favicon
wired into panel.html so the Theseus sidebar tab icon reads as Aegis
rather than a chain-specific coin mark.
- QR payloads now follow each chain's own URI scheme (BIP21 for BCH/DGB,
EIP-681 for ETH, Solana Pay for SOL) so external scanners route the
scan to the right wallet.
Not shipped: EIP-1193 provider (window.ethereum) and wallet-adapter
protocol (window.solana). The signing paths exist; only the page-inject
bridge glue is missing. History for ETH/SOL is also empty in this rev —
both need indexer plumbing (Etherscan V2 for ETH, getSignaturesForAddress
+ getTransaction pagination for SOL).
2026-09-07 20:31:27 +02:00
// ETH/SOL: per-wallet RPC URL, live-swap without key rebuild.
api . onMessage ( "setRpcUrl" , ( p , m ) => {
fromPanel ( m ) ;
const patch = p || { } ;
const id = String ( patch . id || selectedWalletId ( ) ) ;
const entry = walletEntries ( ) . find ( ( w ) => w . id === id ) ;
if ( ! entry ) throw new Error ( "unknown wallet" ) ;
if ( entry . chain !== "eth" && entry . chain !== "sol" ) throw new Error ( "RPC URL is an ETH/SOL setting" ) ;
const v = String ( patch . rpcUrl || "" ) . trim ( ) ;
if ( v && ! /^https?:\/\/[^\s]+$/i . test ( v ) ) throw new Error ( "RPC URL must start with http:// or https://" ) ;
api . storage . set ( ` wallets/ ${ id } /rpcUrl ` , v ) ;
const rt = ctx . runtimes . get ( id ) ;
if ( rt && rt . adapter && typeof rt . adapter . setRpcUrl === "function" ) {
rt . adapter . setRpcUrl ( v ) ;
rt . adapter . refresh ( ) . catch ( ( e ) => api . log ( ` [ ${ id } ] refresh: ` , e ? . message || e ) ) ;
}
emitState ( ) ;
return fullState ( ) ;
} ) ;
feat(theseus/aegis): fold Sia into the addon; add DGB (BIP84 native SegWit)
Aegis now covers four coins across two-step coin+network picks: BCH
(mainnet + chipnet), TRX (mainnet + Nile), SC (mainnet), DGB (mainnet).
- Sia (SC): pulled the standalone siawallet's lib into
bundled-addons/bchwallet/lib/sia/ and wrote lib/chain-sia.js exposing
the common adapter shape. The very first SC wallet the user adds in
Aegis reuses purpose "siawallet/mainnet/0" so pre-Aegis funds carry
over automatically; subsequent SC sub-accounts start at
"bchwallet/sc/mainnet/1". Per-wallet walletd URL setting; empty URL
shows a "Point Aegis at a walletd node" gate in the panel.
- Vault-derive gate now honors a manifest-declared `absorbs` list, so
Aegis's addon.json can list `absorbs: ["siawallet"]` and the derive()
guard accepts paths under either the current id or the absorbed one —
the mechanism a superseding add-on uses to inherit an older add-on's
keyspace without orphaning funds.
- DigiByte (DGB): lib/chain-dgb.js ports the relevant bits of the
SilentCode Digibyte design — SLIP-44 coin type 20, BIP84 native SegWit
(m/84'/20'/0'/0/x → dgb1q…) via ripemd160(sha256(pubkey)) + bech32.
ElectrumX-DGB backend reuses lib/electrum.js (public wss:50022 pool).
BIP143 P2WPKH sighash + witness-tx serialize implemented inline (no
FORKID — DGB uses standard Bitcoin sighash). Derivation cross-checked
against a known BIP39 vector in scratchpad/verify-dgb.mjs — the address
for "abandon×11 about, m/84'/20'/0'/0/0" is
dgb1q9gmf0pv8jdymcly6lz6fl7lf6mhslsd72e2jq8, matching iancoleman.io/bip39.
- Panel: SVG coin logos for SC (green disc with S) and DGB (blue
octagon with D) alongside the BCH/TRX marks. Chain-specific settings
block per coin (walletd URL for SC; derivation path for DGB). Balance
render uses BigInt-safe arithmetic so 24-decimal SC amounts don't
lose precision on the way through the panel; amount input on SC
returns a hastings string.
- Every chain adapter's snapshot fits the panel's shared shape
(address/balance/history/etc.), so future chains only need a new
chain-<x>.js file, a COINS registry entry, a matching case in
mountWallet, and an SVG logo.
Standalone siawallet addon stays as-is on disk; users can delete it once
they've confirmed Aegis shows the same balance. Nothing here disables it.
2026-09-07 01:56:25 +02:00
// Sia-only: per-wallet walletd URL. Live: pushes the URL into the adapter
// without rebuilding the keys (the seed stays derived from the same
// vault path — only the node the wallet talks to changes).
api . onMessage ( "setWalletdUrl" , ( p , m ) => {
fromPanel ( m ) ;
const patch = p || { } ;
const id = String ( patch . id || selectedWalletId ( ) ) ;
const entry = walletEntries ( ) . find ( ( w ) => w . id === id ) ;
if ( ! entry ) throw new Error ( "unknown wallet" ) ;
if ( entry . chain !== "sc" ) throw new Error ( "walletd URL is a Sia-only setting" ) ;
const v = String ( patch . walletdUrl || "" ) . trim ( ) ;
if ( v && ! /^https?:\/\/[^\s]+$/i . test ( v ) ) throw new Error ( "walletd URL must start with http:// or https://" ) ;
api . storage . set ( ` wallets/ ${ id } /walletdUrl ` , v ) ;
const rt = ctx . runtimes . get ( id ) ;
if ( rt && rt . adapter ) {
rt . adapter . setWalletdUrl ( v ) ;
if ( v ) rt . adapter . startPolling ( ) ;
rt . adapter . refresh ( true ) . catch ( ( e ) => api . log ( ` [ ${ id } ] refresh: ` , e ? . message || e ) ) ;
}
emitState ( ) ;
return fullState ( ) ;
} ) ;
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
// Live plan preview for the selected wallet.
api . onMessage ( "planSend" , async ( p , m ) => {
fromPanel ( m ) ;
const rt = requireSelected ( ) ;
const plan = await Promise . resolve ( rt . adapter . plan ( p || { } ) ) ;
return describePlan ( plan , rt . entry . chain , rt . entry . network ) ;
feat(theseus/bchwallet): receive + history — vault-derived keys, cashaddr, QR, electrum
Wallet core on mainnet:
- keys from api.vault.derive("bchwallet/mainnet/0") -> BIP32 m/44'/145'/0'
(@scure/bip32), never persisted; wiped on deactivate.
- lib/cashaddr.js (encode/decode + legacy Base58Check, spec vectors pass),
lib/keys.js (hash160, p2pkh, electrum scripthash, ECDSA DER + BIP-137
recoverable signing), lib/tx.js (serialization, SIGHASH_ALL|FORKID
digest, coin selection, fee estimate), lib/electrum.js (Fulcrum WSS
client with failover + subscriptions), lib/wallet.js (gap-limit scan,
balance, UTXOs, 25-tx history with per-tx deltas, cached public txs).
- qr.js: dependency-free QR encoder (byte mode, v1-10, EC M/L; verified
against jsQR).
- panel: balance header, Receive (QR, copy, next unused address, explorer),
History (deltas, confirmations, explorer links), Settings (derivation
path, electrum server list, xpub / approval-gated xprv reveal). Locked
and not-set-up vault states explained in-panel.
- host: api.import for ESM-only deps, api.openTab for explorer links; an
add-on whose activate() throws is no longer listed twice.
2026-09-06 02:46:41 +02:00
} ) ;
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
// Execute a send with approval overlay.
feat(theseus/bchwallet): send — plan, approval overlay, sign, broadcast
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.
2026-09-06 02:49:09 +02:00
api . onMessage ( "send" , async ( p , m ) => {
fromPanel ( m ) ;
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
const rt = requireSelected ( ) ;
const plan = await Promise . resolve ( rt . adapter . plan ( p || { } ) ) ;
const d = describePlan ( plan , rt . entry . chain , rt . entry . network ) ;
const meta = chainMeta ( rt . entry . chain , rt . entry . network ) ;
const rows = [
{ label : "To" , value : d . recipients [ 0 ] . to , mono : true } ,
{ label : "Amount" , value : ` ${ fmtValue ( d . recipients [ 0 ] . value , meta . decimals ) } ${ meta . ticker } ` , strong : true } ,
{ label : "Fee" , value : rt . entry . chain === "bch" ? ` ${ plan . fee } sat ( ${ plan . feeRate } sat/B) ` : ` ${ fmtValue ( plan . fee , meta . decimals ) } ${ meta . ticker } ` } ,
{ label : "Total" , value : ` ${ fmtValue ( d . total , meta . decimals ) } ${ meta . ticker } ` } ,
feat(theseus/aegis): SVG coin logos, two-step coin/network picker, BCH Chipnet
- Inline SVG logos for BCH (green disc + ₿) and TRX (red disc + geometric T)
replace the 🟨/🔴/🔵 emoji in the sidebar header and wallet picker rows.
The approval overlay stays text-only ("Wallet: <name> — BCH · Mainnet")
because that surface renders plain rows, not HTML.
- Wallet picker's "Add wallet" is now two-step: click a coin to expand its
networks, then click a network to create the wallet. The flat list is gone.
- BCH Chipnet is a real chain option now: bchtest cashaddr prefix,
m/44'/1'/0' derivation (BIP44 testnet coin type), bundled Chipnet electrum
defaults, chipnet.imaginary.cash explorer, tbch.googol.cash faucet link
in Receive. The shared electrum-servers setting stays mainnet-only in
this rev; Chipnet uses adapter-embedded defaults.
- lib/chain-bch.js gained a BCH_NETWORKS table so mainnet vs chipnet
differences (prefix, path, servers, explorer, faucet) live in one place.
- Registry is grouped by coin ({networks:{…}}) instead of a flat
chain:network map — snapshot exposes coins[] for the panel and adds
coinLabel/networkLabel/testnet fields per wallet.
- Testnet wallets get a small "TEST" tag next to the network name so the
user can never mistake a chipnet or Nile balance for real money.
Legacy BCH mainnet index 0 derivation unchanged (bchwallet/mainnet/0 →
m/44'/145'/0' → bitcoincash prefix); the network parameter defaults to
"mainnet" and BCH_NETWORKS.mainnet reproduces the pre-change constants.
2026-09-07 01:07:31 +02:00
{ label : "Wallet" , value : ` ${ rt . entry . label } — ${ meta . coinLabel } · ${ meta . networkLabel } ` } ,
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
] ;
feat(theseus/bchwallet): send — plan, approval overlay, sign, broadcast
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.
2026-09-06 02:49:09 +02:00
const pick = await api . approvalModal ( {
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
title : ` Send ${ meta . ticker } ? ` ,
origin : "Aegis wallet panel" ,
rows ,
feat(theseus/bchwallet): send — plan, approval overlay, sign, broadcast
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.
2026-09-06 02:49:09 +02:00
actions : [ { id : "send" , label : "Send" , primary : true } ] ,
} ) ;
if ( pick !== "send" ) throw new Error ( "cancelled" ) ;
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
return rt . adapter . signAndBroadcast ( plan ) ;
feat(theseus/bchwallet): send — plan, approval overlay, sign, broadcast
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.
2026-09-06 02:49:09 +02:00
} ) ;
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
feat(theseus/bchwallet): receive + history — vault-derived keys, cashaddr, QR, electrum
Wallet core on mainnet:
- keys from api.vault.derive("bchwallet/mainnet/0") -> BIP32 m/44'/145'/0'
(@scure/bip32), never persisted; wiped on deactivate.
- lib/cashaddr.js (encode/decode + legacy Base58Check, spec vectors pass),
lib/keys.js (hash160, p2pkh, electrum scripthash, ECDSA DER + BIP-137
recoverable signing), lib/tx.js (serialization, SIGHASH_ALL|FORKID
digest, coin selection, fee estimate), lib/electrum.js (Fulcrum WSS
client with failover + subscriptions), lib/wallet.js (gap-limit scan,
balance, UTXOs, 25-tx history with per-tx deltas, cached public txs).
- qr.js: dependency-free QR encoder (byte mode, v1-10, EC M/L; verified
against jsQR).
- panel: balance header, Receive (QR, copy, next unused address, explorer),
History (deltas, confirmations, explorer links), Settings (derivation
path, electrum server list, xpub / approval-gated xprv reveal). Locked
and not-set-up vault states explained in-panel.
- host: api.import for ESM-only deps, api.openTab for explorer links; an
add-on whose activate() throws is no longer listed twice.
2026-09-06 02:46:41 +02:00
api . onMessage ( "recovery" , async ( p , m ) => {
fromPanel ( m ) ;
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
const id = String ( p && p . id || selectedWalletId ( ) ) ;
const rt = requireWallet ( id ) ;
feat(theseus/aegis): fold Sia into the addon; add DGB (BIP84 native SegWit)
Aegis now covers four coins across two-step coin+network picks: BCH
(mainnet + chipnet), TRX (mainnet + Nile), SC (mainnet), DGB (mainnet).
- Sia (SC): pulled the standalone siawallet's lib into
bundled-addons/bchwallet/lib/sia/ and wrote lib/chain-sia.js exposing
the common adapter shape. The very first SC wallet the user adds in
Aegis reuses purpose "siawallet/mainnet/0" so pre-Aegis funds carry
over automatically; subsequent SC sub-accounts start at
"bchwallet/sc/mainnet/1". Per-wallet walletd URL setting; empty URL
shows a "Point Aegis at a walletd node" gate in the panel.
- Vault-derive gate now honors a manifest-declared `absorbs` list, so
Aegis's addon.json can list `absorbs: ["siawallet"]` and the derive()
guard accepts paths under either the current id or the absorbed one —
the mechanism a superseding add-on uses to inherit an older add-on's
keyspace without orphaning funds.
- DigiByte (DGB): lib/chain-dgb.js ports the relevant bits of the
SilentCode Digibyte design — SLIP-44 coin type 20, BIP84 native SegWit
(m/84'/20'/0'/0/x → dgb1q…) via ripemd160(sha256(pubkey)) + bech32.
ElectrumX-DGB backend reuses lib/electrum.js (public wss:50022 pool).
BIP143 P2WPKH sighash + witness-tx serialize implemented inline (no
FORKID — DGB uses standard Bitcoin sighash). Derivation cross-checked
against a known BIP39 vector in scratchpad/verify-dgb.mjs — the address
for "abandon×11 about, m/84'/20'/0'/0/0" is
dgb1q9gmf0pv8jdymcly6lz6fl7lf6mhslsd72e2jq8, matching iancoleman.io/bip39.
- Panel: SVG coin logos for SC (green disc with S) and DGB (blue
octagon with D) alongside the BCH/TRX marks. Chain-specific settings
block per coin (walletd URL for SC; derivation path for DGB). Balance
render uses BigInt-safe arithmetic so 24-decimal SC amounts don't
lose precision on the way through the panel; amount input on SC
returns a hastings string.
- Every chain adapter's snapshot fits the panel's shared shape
(address/balance/history/etc.), so future chains only need a new
chain-<x>.js file, a COINS registry entry, a matching case in
mountWallet, and an SVG logo.
Standalone siawallet addon stays as-is on disk; users can delete it once
they've confirmed Aegis shows the same balance. Nothing here disables it.
2026-09-07 01:56:25 +02:00
if ( typeof rt . adapter . recovery !== "function" ) throw new Error ( "this chain does not expose recovery details" ) ;
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
const r = rt . adapter . recovery ( ) ;
const out = { accountPath : r . accountPath , xpub : r . xpub , purpose : rt . entry . purpose } ;
feat(theseus/bchwallet): receive + history — vault-derived keys, cashaddr, QR, electrum
Wallet core on mainnet:
- keys from api.vault.derive("bchwallet/mainnet/0") -> BIP32 m/44'/145'/0'
(@scure/bip32), never persisted; wiped on deactivate.
- lib/cashaddr.js (encode/decode + legacy Base58Check, spec vectors pass),
lib/keys.js (hash160, p2pkh, electrum scripthash, ECDSA DER + BIP-137
recoverable signing), lib/tx.js (serialization, SIGHASH_ALL|FORKID
digest, coin selection, fee estimate), lib/electrum.js (Fulcrum WSS
client with failover + subscriptions), lib/wallet.js (gap-limit scan,
balance, UTXOs, 25-tx history with per-tx deltas, cached public txs).
- qr.js: dependency-free QR encoder (byte mode, v1-10, EC M/L; verified
against jsQR).
- panel: balance header, Receive (QR, copy, next unused address, explorer),
History (deltas, confirmations, explorer links), Settings (derivation
path, electrum server list, xpub / approval-gated xprv reveal). Locked
and not-set-up vault states explained in-panel.
- host: api.import for ESM-only deps, api.openTab for explorer links; an
add-on whose activate() throws is no longer listed twice.
2026-09-06 02:46:41 +02:00
if ( p && p . reveal ) {
feat(theseus/aegis): fold Sia into the addon; add DGB (BIP84 native SegWit)
Aegis now covers four coins across two-step coin+network picks: BCH
(mainnet + chipnet), TRX (mainnet + Nile), SC (mainnet), DGB (mainnet).
- Sia (SC): pulled the standalone siawallet's lib into
bundled-addons/bchwallet/lib/sia/ and wrote lib/chain-sia.js exposing
the common adapter shape. The very first SC wallet the user adds in
Aegis reuses purpose "siawallet/mainnet/0" so pre-Aegis funds carry
over automatically; subsequent SC sub-accounts start at
"bchwallet/sc/mainnet/1". Per-wallet walletd URL setting; empty URL
shows a "Point Aegis at a walletd node" gate in the panel.
- Vault-derive gate now honors a manifest-declared `absorbs` list, so
Aegis's addon.json can list `absorbs: ["siawallet"]` and the derive()
guard accepts paths under either the current id or the absorbed one —
the mechanism a superseding add-on uses to inherit an older add-on's
keyspace without orphaning funds.
- DigiByte (DGB): lib/chain-dgb.js ports the relevant bits of the
SilentCode Digibyte design — SLIP-44 coin type 20, BIP84 native SegWit
(m/84'/20'/0'/0/x → dgb1q…) via ripemd160(sha256(pubkey)) + bech32.
ElectrumX-DGB backend reuses lib/electrum.js (public wss:50022 pool).
BIP143 P2WPKH sighash + witness-tx serialize implemented inline (no
FORKID — DGB uses standard Bitcoin sighash). Derivation cross-checked
against a known BIP39 vector in scratchpad/verify-dgb.mjs — the address
for "abandon×11 about, m/84'/20'/0'/0/0" is
dgb1q9gmf0pv8jdymcly6lz6fl7lf6mhslsd72e2jq8, matching iancoleman.io/bip39.
- Panel: SVG coin logos for SC (green disc with S) and DGB (blue
octagon with D) alongside the BCH/TRX marks. Chain-specific settings
block per coin (walletd URL for SC; derivation path for DGB). Balance
render uses BigInt-safe arithmetic so 24-decimal SC amounts don't
lose precision on the way through the panel; amount input on SC
returns a hastings string.
- Every chain adapter's snapshot fits the panel's shared shape
(address/balance/history/etc.), so future chains only need a new
chain-<x>.js file, a COINS registry entry, a matching case in
mountWallet, and an SVG logo.
Standalone siawallet addon stays as-is on disk; users can delete it once
they've confirmed Aegis shows the same balance. Nothing here disables it.
2026-09-07 01:56:25 +02:00
// Sia's "xprv" is really the 32-byte wallet seed (walletd KeyFromSeed);
// BCH/DGB's is the account xprv. Warning copy fits both.
feat(theseus/bchwallet): receive + history — vault-derived keys, cashaddr, QR, electrum
Wallet core on mainnet:
- keys from api.vault.derive("bchwallet/mainnet/0") -> BIP32 m/44'/145'/0'
(@scure/bip32), never persisted; wiped on deactivate.
- lib/cashaddr.js (encode/decode + legacy Base58Check, spec vectors pass),
lib/keys.js (hash160, p2pkh, electrum scripthash, ECDSA DER + BIP-137
recoverable signing), lib/tx.js (serialization, SIGHASH_ALL|FORKID
digest, coin selection, fee estimate), lib/electrum.js (Fulcrum WSS
client with failover + subscriptions), lib/wallet.js (gap-limit scan,
balance, UTXOs, 25-tx history with per-tx deltas, cached public txs).
- qr.js: dependency-free QR encoder (byte mode, v1-10, EC M/L; verified
against jsQR).
- panel: balance header, Receive (QR, copy, next unused address, explorer),
History (deltas, confirmations, explorer links), Settings (derivation
path, electrum server list, xpub / approval-gated xprv reveal). Locked
and not-set-up vault states explained in-panel.
- host: api.import for ESM-only deps, api.openTab for explorer links; an
add-on whose activate() throws is no longer listed twice.
2026-09-06 02:46:41 +02:00
const pick = await api . approvalModal ( {
feat(theseus/aegis): fold Sia into the addon; add DGB (BIP84 native SegWit)
Aegis now covers four coins across two-step coin+network picks: BCH
(mainnet + chipnet), TRX (mainnet + Nile), SC (mainnet), DGB (mainnet).
- Sia (SC): pulled the standalone siawallet's lib into
bundled-addons/bchwallet/lib/sia/ and wrote lib/chain-sia.js exposing
the common adapter shape. The very first SC wallet the user adds in
Aegis reuses purpose "siawallet/mainnet/0" so pre-Aegis funds carry
over automatically; subsequent SC sub-accounts start at
"bchwallet/sc/mainnet/1". Per-wallet walletd URL setting; empty URL
shows a "Point Aegis at a walletd node" gate in the panel.
- Vault-derive gate now honors a manifest-declared `absorbs` list, so
Aegis's addon.json can list `absorbs: ["siawallet"]` and the derive()
guard accepts paths under either the current id or the absorbed one —
the mechanism a superseding add-on uses to inherit an older add-on's
keyspace without orphaning funds.
- DigiByte (DGB): lib/chain-dgb.js ports the relevant bits of the
SilentCode Digibyte design — SLIP-44 coin type 20, BIP84 native SegWit
(m/84'/20'/0'/0/x → dgb1q…) via ripemd160(sha256(pubkey)) + bech32.
ElectrumX-DGB backend reuses lib/electrum.js (public wss:50022 pool).
BIP143 P2WPKH sighash + witness-tx serialize implemented inline (no
FORKID — DGB uses standard Bitcoin sighash). Derivation cross-checked
against a known BIP39 vector in scratchpad/verify-dgb.mjs — the address
for "abandon×11 about, m/84'/20'/0'/0/0" is
dgb1q9gmf0pv8jdymcly6lz6fl7lf6mhslsd72e2jq8, matching iancoleman.io/bip39.
- Panel: SVG coin logos for SC (green disc with S) and DGB (blue
octagon with D) alongside the BCH/TRX marks. Chain-specific settings
block per coin (walletd URL for SC; derivation path for DGB). Balance
render uses BigInt-safe arithmetic so 24-decimal SC amounts don't
lose precision on the way through the panel; amount input on SC
returns a hastings string.
- Every chain adapter's snapshot fits the panel's shared shape
(address/balance/history/etc.), so future chains only need a new
chain-<x>.js file, a COINS registry entry, a matching case in
mountWallet, and an SVG logo.
Standalone siawallet addon stays as-is on disk; users can delete it once
they've confirmed Aegis shows the same balance. Nothing here disables it.
2026-09-07 01:56:25 +02:00
title : rt . entry . chain === "sc" ? "Reveal the wallet seed?" : "Reveal the account private key?" ,
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
origin : "Aegis wallet panel" ,
feat(theseus/aegis): fold Sia into the addon; add DGB (BIP84 native SegWit)
Aegis now covers four coins across two-step coin+network picks: BCH
(mainnet + chipnet), TRX (mainnet + Nile), SC (mainnet), DGB (mainnet).
- Sia (SC): pulled the standalone siawallet's lib into
bundled-addons/bchwallet/lib/sia/ and wrote lib/chain-sia.js exposing
the common adapter shape. The very first SC wallet the user adds in
Aegis reuses purpose "siawallet/mainnet/0" so pre-Aegis funds carry
over automatically; subsequent SC sub-accounts start at
"bchwallet/sc/mainnet/1". Per-wallet walletd URL setting; empty URL
shows a "Point Aegis at a walletd node" gate in the panel.
- Vault-derive gate now honors a manifest-declared `absorbs` list, so
Aegis's addon.json can list `absorbs: ["siawallet"]` and the derive()
guard accepts paths under either the current id or the absorbed one —
the mechanism a superseding add-on uses to inherit an older add-on's
keyspace without orphaning funds.
- DigiByte (DGB): lib/chain-dgb.js ports the relevant bits of the
SilentCode Digibyte design — SLIP-44 coin type 20, BIP84 native SegWit
(m/84'/20'/0'/0/x → dgb1q…) via ripemd160(sha256(pubkey)) + bech32.
ElectrumX-DGB backend reuses lib/electrum.js (public wss:50022 pool).
BIP143 P2WPKH sighash + witness-tx serialize implemented inline (no
FORKID — DGB uses standard Bitcoin sighash). Derivation cross-checked
against a known BIP39 vector in scratchpad/verify-dgb.mjs — the address
for "abandon×11 about, m/84'/20'/0'/0/0" is
dgb1q9gmf0pv8jdymcly6lz6fl7lf6mhslsd72e2jq8, matching iancoleman.io/bip39.
- Panel: SVG coin logos for SC (green disc with S) and DGB (blue
octagon with D) alongside the BCH/TRX marks. Chain-specific settings
block per coin (walletd URL for SC; derivation path for DGB). Balance
render uses BigInt-safe arithmetic so 24-decimal SC amounts don't
lose precision on the way through the panel; amount input on SC
returns a hastings string.
- Every chain adapter's snapshot fits the panel's shared shape
(address/balance/history/etc.), so future chains only need a new
chain-<x>.js file, a COINS registry entry, a matching case in
mountWallet, and an SVG logo.
Standalone siawallet addon stays as-is on disk; users can delete it once
they've confirmed Aegis shows the same balance. Nothing here disables it.
2026-09-07 01:56:25 +02:00
body : "Anyone holding this can spend every coin in this wallet. It stays on screen until you close the Settings tab." ,
feat(theseus/bchwallet): receive + history — vault-derived keys, cashaddr, QR, electrum
Wallet core on mainnet:
- keys from api.vault.derive("bchwallet/mainnet/0") -> BIP32 m/44'/145'/0'
(@scure/bip32), never persisted; wiped on deactivate.
- lib/cashaddr.js (encode/decode + legacy Base58Check, spec vectors pass),
lib/keys.js (hash160, p2pkh, electrum scripthash, ECDSA DER + BIP-137
recoverable signing), lib/tx.js (serialization, SIGHASH_ALL|FORKID
digest, coin selection, fee estimate), lib/electrum.js (Fulcrum WSS
client with failover + subscriptions), lib/wallet.js (gap-limit scan,
balance, UTXOs, 25-tx history with per-tx deltas, cached public txs).
- qr.js: dependency-free QR encoder (byte mode, v1-10, EC M/L; verified
against jsQR).
- panel: balance header, Receive (QR, copy, next unused address, explorer),
History (deltas, confirmations, explorer links), Settings (derivation
path, electrum server list, xpub / approval-gated xprv reveal). Locked
and not-set-up vault states explained in-panel.
- host: api.import for ESM-only deps, api.openTab for explorer links; an
add-on whose activate() throws is no longer listed twice.
2026-09-06 02:46:41 +02:00
actions : [ { id : "reveal" , label : "Reveal" , danger : true } ] ,
} ) ;
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
if ( pick === "reveal" ) out . xprv = r . xprv ;
feat(theseus/bchwallet): receive + history — vault-derived keys, cashaddr, QR, electrum
Wallet core on mainnet:
- keys from api.vault.derive("bchwallet/mainnet/0") -> BIP32 m/44'/145'/0'
(@scure/bip32), never persisted; wiped on deactivate.
- lib/cashaddr.js (encode/decode + legacy Base58Check, spec vectors pass),
lib/keys.js (hash160, p2pkh, electrum scripthash, ECDSA DER + BIP-137
recoverable signing), lib/tx.js (serialization, SIGHASH_ALL|FORKID
digest, coin selection, fee estimate), lib/electrum.js (Fulcrum WSS
client with failover + subscriptions), lib/wallet.js (gap-limit scan,
balance, UTXOs, 25-tx history with per-tx deltas, cached public txs).
- qr.js: dependency-free QR encoder (byte mode, v1-10, EC M/L; verified
against jsQR).
- panel: balance header, Receive (QR, copy, next unused address, explorer),
History (deltas, confirmations, explorer links), Settings (derivation
path, electrum server list, xpub / approval-gated xprv reveal). Locked
and not-set-up vault states explained in-panel.
- host: api.import for ESM-only deps, api.openTab for explorer links; an
add-on whose activate() throws is no longer listed twice.
2026-09-06 02:46:41 +02:00
}
return out ;
} ) ;
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
api . onMessage ( "permissions" , ( _p , m ) => { fromPanel ( m ) ; return permissions ( api ) ; } ) ;
api . onMessage ( "revoke" , ( p , m ) => {
fromPanel ( m ) ;
const perms = permissions ( api ) ;
delete perms [ String ( p && p . origin || "" ) ] ;
api . storage . set ( "permissions" , perms ) ;
return perms ;
} ) ;
feat(theseus/bchwallet): receive + history — vault-derived keys, cashaddr, QR, electrum
Wallet core on mainnet:
- keys from api.vault.derive("bchwallet/mainnet/0") -> BIP32 m/44'/145'/0'
(@scure/bip32), never persisted; wiped on deactivate.
- lib/cashaddr.js (encode/decode + legacy Base58Check, spec vectors pass),
lib/keys.js (hash160, p2pkh, electrum scripthash, ECDSA DER + BIP-137
recoverable signing), lib/tx.js (serialization, SIGHASH_ALL|FORKID
digest, coin selection, fee estimate), lib/electrum.js (Fulcrum WSS
client with failover + subscriptions), lib/wallet.js (gap-limit scan,
balance, UTXOs, 25-tx history with per-tx deltas, cached public txs).
- qr.js: dependency-free QR encoder (byte mode, v1-10, EC M/L; verified
against jsQR).
- panel: balance header, Receive (QR, copy, next unused address, explorer),
History (deltas, confirmations, explorer links), Settings (derivation
path, electrum server list, xpub / approval-gated xprv reveal). Locked
and not-set-up vault states explained in-panel.
- host: api.import for ESM-only deps, api.openTab for explorer links; an
add-on whose activate() throws is no longer listed twice.
2026-09-06 02:46:41 +02:00
}
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
// One "describePlan" is enough for both chains because plan() returns a
// common shape: {recipients:[{to,value}], fee, feeRate, total, inputs:[]…}.
function describePlan ( plan ) {
const sent = plan . recipients . reduce ( ( a , r ) => a + r . value , 0 ) ;
return {
recipients : plan . recipients , fee : plan . fee , feeRate : plan . feeRate ,
inputs : ( plan . inputs || [ ] ) . length , change : plan . change || null ,
total : plan . total != null ? plan . total : ( sent + plan . fee ) ,
} ;
}
// ---- dapp bridges (page → activate()) --------------------------------------
// Permission model stays the same as the single-wallet build for BCH:
// { [origin]: { readAddress:true, sendTx:{capSats,usedSats,grantedAt},
// trx: { readAddress:true, network } } }
// The BCH bridge always talks to the LEGACY default BCH wallet (the .x pages
// pre-date multi-wallet and cannot pick between them). The Tron bridge talks
// to the currently-SELECTED Tron wallet; if none is selected, requests fail.
const BCH _ALLOWANCES = [ 100000 , 1000000 , 10000000 ] ; // 0.001, 0.01, 0.1 BCH
2026-09-06 02:56:34 +02:00
const pendingByOrigin = new Set ( ) ;
function permissions ( api ) { const p = api . storage . get ( "permissions" , { } ) ; return p && typeof p === "object" ? p : { } ; }
async function withOriginLock ( origin , fn ) {
if ( pendingByOrigin . has ( origin ) ) throw new Error ( "a wallet request from this site is already waiting for approval" ) ;
pendingByOrigin . add ( origin ) ;
try { return await fn ( ) ; } finally { pendingByOrigin . delete ( origin ) ; }
}
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
// Only .x sites (BCNR-native TLD) get the BCH bridge, matching the pre-
// multi-wallet gate. Widening the manifest to https://*/* makes the Tron
// bridge available everywhere; the BCH side enforces its narrower rule
// inside the handlers.
function isBchOrigin ( origin ) {
try { const h = new URL ( origin ) . hostname ; return /\.x$/ . test ( h ) ; }
catch { return false ; }
}
function legacyBchRuntime ( ) {
const rt = ctx . runtimes . get ( LEGACY _BCH _WALLET _ID ) ;
if ( ! rt || rt . phase !== "ready" || ! rt . adapter ) throw new Error ( "wallet is not ready (vault locked?)" ) ;
return rt ;
}
// The Tron bridge routes to the currently-selected wallet if it is Tron;
// otherwise it looks for the first ready Tron wallet on the selected network
// hint; else rejects with "no tron wallet".
function activeTronRuntime ( ) {
const selId = selectedWalletId ( ) ;
const selRt = selId && ctx . runtimes . get ( selId ) ;
if ( selRt && selRt . entry . chain === "trx" && selRt . phase === "ready" ) return selRt ;
for ( const rt of ctx . runtimes . values ( ) ) if ( rt . entry . chain === "trx" && rt . phase === "ready" ) return rt ;
throw new Error ( "no Tron wallet available — add one in the Aegis sidebar" ) ;
2026-09-06 02:56:34 +02:00
}
function registerPageMessages ( api ) {
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
// ---- BCH bridge (unchanged behavior; wallet source is legacy default) ----
2026-09-06 02:56:34 +02:00
api . onMessage ( "getAddress" , async ( _p , m ) => {
const origin = fromPage ( m ) ;
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
if ( ! isBchOrigin ( origin ) ) throw new Error ( "this site is not on a Bitcoin Cash origin" ) ;
const rt = legacyBchRuntime ( ) ;
2026-09-06 02:56:34 +02:00
const perms = permissions ( api ) ;
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
if ( perms [ origin ] && perms [ origin ] . readAddress ) return rt . adapter . current ( ) . address ;
2026-09-06 02:56:34 +02:00
return withOriginLock ( origin , async ( ) => {
const pick = await api . approvalModal ( {
title : "Share your Bitcoin Cash address?" ,
origin ,
body : "The site will see your current receiving address and can look up its balance and history on the public chain." ,
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
rows : [ { label : "Address" , value : rt . adapter . current ( ) . address , mono : true } ] ,
2026-09-06 02:56:34 +02:00
actions : [ { id : "allow" , label : "Share" , primary : true } ] ,
checkbox : { id : "always" , label : "Always allow this site to see my address" } ,
} ) ;
if ( ! pick . startsWith ( "allow" ) ) throw new Error ( "user rejected" ) ;
if ( pick === "allow+always" ) { perms [ origin ] = { ... ( perms [ origin ] || { } ) , readAddress : true } ; api . storage . set ( "permissions" , perms ) ; emitState ( ) ; }
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
return rt . adapter . current ( ) . address ;
2026-09-06 02:56:34 +02:00
} ) ;
} ) ;
api . onMessage ( "signAndSend" , async ( p , m ) => {
const origin = fromPage ( m ) ;
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
if ( ! isBchOrigin ( origin ) ) throw new Error ( "this site is not on a Bitcoin Cash origin" ) ;
const rt = legacyBchRuntime ( ) ;
2026-09-06 02:56:34 +02:00
return withOriginLock ( origin , async ( ) => {
let plan ;
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
try { plan = rt . adapter . plan ( p || { } ) ; }
2026-09-06 02:56:34 +02:00
catch ( e ) { throw new Error ( /insufficient funds|too small/i . test ( e ? . message ) ? "insufficient funds" : e ? . message || String ( e ) ) ; }
const d = describePlan ( plan ) ;
if ( d . recipients . length > 8 ) throw new Error ( "too many outputs" ) ;
2026-09-06 12:43:17 +02:00
const perms = permissions ( api ) ;
const budget = perms [ origin ] && perms [ origin ] . sendTx ;
const remaining = budget ? Math . max ( 0 , ( budget . capSats | 0 ) - ( budget . usedSats | 0 ) ) : 0 ;
if ( budget && d . total <= remaining ) {
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
const r = await rt . adapter . signAndBroadcast ( plan ) ;
2026-09-06 12:43:17 +02:00
budget . usedSats = ( budget . usedSats | 0 ) + d . total ;
api . storage . set ( "permissions" , perms ) ;
emitState ( ) ;
api . log ( ` silent send ${ d . total } sat for ${ origin } , ${ remaining - d . total } sat of allowance left ` ) ;
return { txid : r . txid } ;
}
2026-09-06 02:56:34 +02:00
const rows = d . recipients . map ( ( r , i ) => ( { label : d . recipients . length > 1 ? ` To # ${ i + 1 } ` : "To" , value : r . to , mono : true } ) ) ;
rows . push ( { label : "Amount" , value : fmtBch ( d . recipients . reduce ( ( a , r ) => a + r . value , 0 ) ) + " BCH" , strong : true } ) ;
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
rows . push ( { label : "Fee" , value : ` ${ plan . fee } sat ( ${ plan . feeRate } sat/B) ` } ) ;
2026-09-06 02:56:34 +02:00
rows . push ( { label : "Total" , value : fmtBch ( d . total ) + " BCH" } ) ;
const pick = await api . approvalModal ( {
title : "Send Bitcoin Cash?" ,
origin ,
2026-09-06 12:43:17 +02:00
body : budget
? ` This payment is over what is left of the site's allowance ( ${ fmtBch ( remaining ) } BCH). Check the address and amount. `
: "This site is asking your wallet to pay. Check the address and amount." ,
2026-09-06 02:56:34 +02:00
rows ,
actions : [ { id : "send" , label : "Send" , primary : true } ] ,
2026-09-06 12:43:17 +02:00
select : {
id : "cap" , label : "Afterwards" ,
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
options : [ { value : "" , label : "ask every time" } , ... BCH _ALLOWANCES . map ( ( s ) => ( { value : String ( s ) , label : ` allow up to ${ fmtBch ( s ) } BCH more without asking ` } ) ) ] ,
2026-09-06 12:43:17 +02:00
} ,
2026-09-06 02:56:34 +02:00
} ) ;
2026-09-06 12:43:17 +02:00
const [ action , ... flags ] = pick . split ( "+" ) ;
if ( action !== "send" ) throw new Error ( "user rejected" ) ;
const cap = flags . find ( ( f ) => f . startsWith ( "cap=" ) ) ;
const capSats = cap ? Number ( cap . slice ( 4 ) ) : 0 ;
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
if ( BCH _ALLOWANCES . includes ( capSats ) ) {
2026-09-06 12:43:17 +02:00
perms [ origin ] = { ... ( perms [ origin ] || { } ) , sendTx : { capSats , usedSats : 0 , grantedAt : Date . now ( ) } } ;
api . storage . set ( "permissions" , perms ) ;
} else if ( budget ) {
delete perms [ origin ] . sendTx ;
api . storage . set ( "permissions" , perms ) ;
}
emitState ( ) ;
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
const r = await rt . adapter . signAndBroadcast ( plan ) ;
2026-09-06 02:56:34 +02:00
return { txid : r . txid } ;
} ) ;
} ) ;
api . onMessage ( "signMessage" , async ( p , m ) => {
const origin = fromPage ( m ) ;
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
if ( ! isBchOrigin ( origin ) ) throw new Error ( "this site is not on a Bitcoin Cash origin" ) ;
const rt = legacyBchRuntime ( ) ;
2026-09-06 02:56:34 +02:00
const message = String ( p && p . message != null ? p . message : "" ) ;
if ( message . length > 4096 ) throw new Error ( "message too long" ) ;
return withOriginLock ( origin , async ( ) => {
const pick = await api . approvalModal ( {
title : "Sign a message?" ,
origin ,
body : "Signing proves you control the address below. It moves no coins." ,
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
rows : [
{ label : "Message" , value : message . length > 400 ? message . slice ( 0 , 400 ) + "…" : message , mono : true } ,
{ label : "Address" , value : rt . adapter . current ( ) . address , mono : true } ,
] ,
2026-09-06 02:56:34 +02:00
actions : [ { id : "sign" , label : "Sign" , primary : true } ] ,
} ) ;
if ( pick !== "sign" ) throw new Error ( "user rejected" ) ;
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
return rt . adapter . signMessage ( message ) ;
2026-09-06 02:56:34 +02:00
} ) ;
} ) ;
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
// ---- Tron bridge (tronWeb / tronLink) -----------------------------------
api . onMessage ( "trx.requestAccounts" , async ( _p , m ) => {
const origin = fromPage ( m ) ;
const rt = activeTronRuntime ( ) ;
2026-09-06 02:56:34 +02:00
const perms = permissions ( api ) ;
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
const alreadyOK = perms [ origin ] && perms [ origin ] . trx && perms [ origin ] . trx . readAddress ;
const snap = rt . adapter . snapshot ( ) ;
if ( alreadyOK ) return { code : 200 , address : snap . address , network : snap . network } ;
return withOriginLock ( origin , async ( ) => {
const pick = await api . approvalModal ( {
title : "Connect this site to your Tron wallet?" ,
origin ,
body : "The site will see this address and can build transactions for you to sign." ,
rows : [
{ label : "Address" , value : snap . address , mono : true } ,
{ label : "Network" , value : snap . network === "nile" ? "Nile testnet" : "Tron mainnet" } ,
feat(theseus/aegis): SVG coin logos, two-step coin/network picker, BCH Chipnet
- Inline SVG logos for BCH (green disc + ₿) and TRX (red disc + geometric T)
replace the 🟨/🔴/🔵 emoji in the sidebar header and wallet picker rows.
The approval overlay stays text-only ("Wallet: <name> — BCH · Mainnet")
because that surface renders plain rows, not HTML.
- Wallet picker's "Add wallet" is now two-step: click a coin to expand its
networks, then click a network to create the wallet. The flat list is gone.
- BCH Chipnet is a real chain option now: bchtest cashaddr prefix,
m/44'/1'/0' derivation (BIP44 testnet coin type), bundled Chipnet electrum
defaults, chipnet.imaginary.cash explorer, tbch.googol.cash faucet link
in Receive. The shared electrum-servers setting stays mainnet-only in
this rev; Chipnet uses adapter-embedded defaults.
- lib/chain-bch.js gained a BCH_NETWORKS table so mainnet vs chipnet
differences (prefix, path, servers, explorer, faucet) live in one place.
- Registry is grouped by coin ({networks:{…}}) instead of a flat
chain:network map — snapshot exposes coins[] for the panel and adds
coinLabel/networkLabel/testnet fields per wallet.
- Testnet wallets get a small "TEST" tag next to the network name so the
user can never mistake a chipnet or Nile balance for real money.
Legacy BCH mainnet index 0 derivation unchanged (bchwallet/mainnet/0 →
m/44'/145'/0' → bitcoincash prefix); the network parameter defaults to
"mainnet" and BCH_NETWORKS.mainnet reproduces the pre-change constants.
2026-09-07 01:07:31 +02:00
{ label : "Wallet" , value : ` ${ rt . entry . label } — Tron · ${ snap . network === "nile" ? "Nile testnet" : "Mainnet" } ` } ,
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
] ,
actions : [ { id : "allow" , label : "Connect" , primary : true } ] ,
checkbox : { id : "always" , label : "Always allow this site to see this address" } ,
} ) ;
if ( ! pick . startsWith ( "allow" ) ) throw new Error ( "user rejected" ) ;
if ( pick === "allow+always" ) {
perms [ origin ] = { ... ( perms [ origin ] || { } ) , trx : { readAddress : true , network : snap . network } } ;
api . storage . set ( "permissions" , perms ) ;
emitState ( ) ;
}
return { code : 200 , address : snap . address , network : snap . network } ;
} ) ;
} ) ;
api . onMessage ( "trx.getAccount" , ( _p , m ) => {
const origin = fromPage ( m ) ;
const perms = permissions ( api ) ;
if ( ! ( perms [ origin ] && perms [ origin ] . trx && perms [ origin ] . trx . readAddress ) ) throw new Error ( "not connected — call tron_requestAccounts first" ) ;
const rt = activeTronRuntime ( ) ;
const snap = rt . adapter . snapshot ( ) ;
return { address : snap . address , network : snap . network } ;
} ) ;
// Sign an arbitrary raw_data_hex the dapp built (with its own tronWeb).
// The wallet never guesses the intent — the approval overlay shows the
// decoded contract type and destination when it can, and always the txID.
api . onMessage ( "trx.signTransaction" , async ( p , m ) => {
const origin = fromPage ( m ) ;
const rt = activeTronRuntime ( ) ;
const perms = permissions ( api ) ;
if ( ! ( perms [ origin ] && perms [ origin ] . trx && perms [ origin ] . trx . readAddress ) ) throw new Error ( "not connected — call tron_requestAccounts first" ) ;
const tx = p && p . transaction ;
if ( ! tx || typeof tx !== "object" || ! tx . raw _data _hex || ! tx . raw _data ) throw new Error ( "bad transaction" ) ;
return withOriginLock ( origin , async ( ) => {
const contract = ( tx . raw _data . contract || [ ] ) [ 0 ] ;
const type = contract ? . type || "Contract" ;
const rows = [ { label : "Type" , value : type } , { label : "Tx ID" , value : tx . txID || "(unset)" , mono : true } ] ;
if ( type === "TransferContract" ) {
const v = contract . parameter ? . value || { } ;
try {
const to = v . to _address ? ctx . d . tronAdapter . hexToAddress ( v . to _address ) : ( v . to _address || "" ) ;
const amount = Number ( v . amount || 0 ) ;
rows . splice ( 1 , 0 , { label : "To" , value : to , mono : true } , { label : "Amount" , value : ` ${ fmtTrx ( amount ) } TRX ` , strong : true } ) ;
} catch { }
}
feat(theseus/aegis): SVG coin logos, two-step coin/network picker, BCH Chipnet
- Inline SVG logos for BCH (green disc + ₿) and TRX (red disc + geometric T)
replace the 🟨/🔴/🔵 emoji in the sidebar header and wallet picker rows.
The approval overlay stays text-only ("Wallet: <name> — BCH · Mainnet")
because that surface renders plain rows, not HTML.
- Wallet picker's "Add wallet" is now two-step: click a coin to expand its
networks, then click a network to create the wallet. The flat list is gone.
- BCH Chipnet is a real chain option now: bchtest cashaddr prefix,
m/44'/1'/0' derivation (BIP44 testnet coin type), bundled Chipnet electrum
defaults, chipnet.imaginary.cash explorer, tbch.googol.cash faucet link
in Receive. The shared electrum-servers setting stays mainnet-only in
this rev; Chipnet uses adapter-embedded defaults.
- lib/chain-bch.js gained a BCH_NETWORKS table so mainnet vs chipnet
differences (prefix, path, servers, explorer, faucet) live in one place.
- Registry is grouped by coin ({networks:{…}}) instead of a flat
chain:network map — snapshot exposes coins[] for the panel and adds
coinLabel/networkLabel/testnet fields per wallet.
- Testnet wallets get a small "TEST" tag next to the network name so the
user can never mistake a chipnet or Nile balance for real money.
Legacy BCH mainnet index 0 derivation unchanged (bchwallet/mainnet/0 →
m/44'/145'/0' → bitcoincash prefix); the network parameter defaults to
"mainnet" and BCH_NETWORKS.mainnet reproduces the pre-change constants.
2026-09-07 01:07:31 +02:00
rows . push ( { label : "Wallet" , value : ` ${ rt . entry . label } — Tron · ${ rt . adapter . snapshot ( ) . network === "nile" ? "Nile testnet" : "Mainnet" } ` } ) ;
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
const pick = await api . approvalModal ( {
title : "Sign a Tron transaction?" ,
origin ,
body : "The site built this transaction. Check the type, amount, and destination before signing." ,
rows ,
actions : [ { id : "sign" , label : "Sign" , primary : true } ] ,
} ) ;
if ( pick !== "sign" ) throw new Error ( "user rejected" ) ;
const sig = rt . adapter . signRawData ( tx . raw _data _hex ) ;
const signed = { ... tx , signature : [ sig ] } ;
return signed ;
} ) ;
} ) ;
api . onMessage ( "trx.sendRawTransaction" , async ( p , m ) => {
const origin = fromPage ( m ) ;
const rt = activeTronRuntime ( ) ;
const perms = permissions ( api ) ;
if ( ! ( perms [ origin ] && perms [ origin ] . trx && perms [ origin ] . trx . readAddress ) ) throw new Error ( "not connected — call tron_requestAccounts first" ) ;
const signedTx = p && p . transaction ;
if ( ! signedTx || ! signedTx . raw _data _hex || ! Array . isArray ( signedTx . signature ) ) throw new Error ( "bad signed tx" ) ;
// No approval here — broadcasting a *signed* tx does not add any risk
// the sign step didn't already carry. Sites that don't want an extra
// network round-trip pass {broadcast:true} to sign; we support both.
return rt . adapter . broadcastSignedTx ( signedTx ) ;
} ) ;
api . onMessage ( "trx.signMessageV2" , async ( p , m ) => {
const origin = fromPage ( m ) ;
const rt = activeTronRuntime ( ) ;
const perms = permissions ( api ) ;
if ( ! ( perms [ origin ] && perms [ origin ] . trx && perms [ origin ] . trx . readAddress ) ) throw new Error ( "not connected — call tron_requestAccounts first" ) ;
const message = String ( p && p . message != null ? p . message : "" ) ;
if ( message . length > 4096 ) throw new Error ( "message too long" ) ;
return withOriginLock ( origin , async ( ) => {
const snap = rt . adapter . snapshot ( ) ;
const pick = await api . approvalModal ( {
title : "Sign a Tron message?" ,
origin ,
body : "Signing proves you control this address. It moves no coins." ,
rows : [
{ label : "Message" , value : message . length > 400 ? message . slice ( 0 , 400 ) + "…" : message , mono : true } ,
{ label : "Address" , value : snap . address , mono : true } ,
] ,
actions : [ { id : "sign" , label : "Sign" , primary : true } ] ,
} ) ;
if ( pick !== "sign" ) throw new Error ( "user rejected" ) ;
return rt . adapter . signMessageV2 ( message ) ;
} ) ;
2026-09-06 02:56:34 +02:00
} ) ;
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
// ---- Ethereum (EIP-1193) ---------------------------------------------
// Routes the same way as Tron: pick the currently-selected ETH wallet if
// any; else the first ready ETH wallet. Chain switches happen at the
// wallet-picker level, not here — dapps that call wallet_switchEthereumChain
// get a friendly "switch wallet in the Aegis sidebar" error.
function activeEthRuntime ( ) {
const selId = selectedWalletId ( ) ;
const selRt = selId && ctx . runtimes . get ( selId ) ;
if ( selRt && selRt . entry . chain === "eth" && selRt . phase === "ready" ) return selRt ;
for ( const rt of ctx . runtimes . values ( ) ) if ( rt . entry . chain === "eth" && rt . phase === "ready" ) return rt ;
throw new Error ( "no Ethereum wallet available — add one in the Aegis sidebar" ) ;
}
function ethConnectedFor ( origin ) {
const p = permissions ( api ) [ origin ] ;
return ! ! ( p && p . eth && p . eth . readAddress ) ;
}
api . onMessage ( "eth.requestAccounts" , async ( _p , m ) => {
const origin = fromPage ( m ) ;
const rt = activeEthRuntime ( ) ;
const snap = rt . adapter . snapshot ( ) ;
const chainIdHex = "0x" + Number ( snap . chainId ) . toString ( 16 ) ;
const networkVersion = String ( snap . chainId ) ;
const perms = permissions ( api ) ;
if ( perms [ origin ] && perms [ origin ] . eth && perms [ origin ] . eth . readAddress ) {
return { address : snap . address , chainIdHex , networkVersion } ;
}
return withOriginLock ( origin , async ( ) => {
const pick = await api . approvalModal ( {
title : "Connect this site to your Ethereum wallet?" ,
origin ,
body : "The site will see this address and can build transactions for you to sign." ,
rows : [
{ label : "Address" , value : snap . address , mono : true } ,
{ label : "Network" , value : snap . network === "mainnet" ? "Ethereum mainnet" : "Sepolia testnet" } ,
{ label : "Wallet" , value : ` ${ rt . entry . label } — Ethereum · ${ snap . network } ` } ,
] ,
actions : [ { id : "allow" , label : "Connect" , primary : true } ] ,
checkbox : { id : "always" , label : "Always allow this site to see this address" } ,
} ) ;
if ( ! pick . startsWith ( "allow" ) ) throw new Error ( "user rejected" ) ;
if ( pick === "allow+always" ) {
perms [ origin ] = { ... ( perms [ origin ] || { } ) , eth : { readAddress : true , chainId : snap . chainId } } ;
api . storage . set ( "permissions" , perms ) ;
emitState ( ) ;
}
return { address : snap . address , chainIdHex , networkVersion } ;
} ) ;
} ) ;
api . onMessage ( "eth.personalSign" , async ( p , m ) => {
const origin = fromPage ( m ) ;
if ( ! ethConnectedFor ( origin ) ) throw new Error ( "not connected — call eth_requestAccounts first" ) ;
const rt = activeEthRuntime ( ) ;
const message = String ( p && p . message != null ? p . message : "" ) ;
if ( message . length > 4096 ) throw new Error ( "message too long" ) ;
return withOriginLock ( origin , async ( ) => {
const pick = await api . approvalModal ( {
title : "Sign an Ethereum message?" ,
origin ,
body : "Signing proves you control this address. It moves no ETH." ,
rows : [
{ label : "Message" , value : message . length > 400 ? message . slice ( 0 , 400 ) + "…" : message , mono : true } ,
{ label : "Address" , value : rt . adapter . snapshot ( ) . address , mono : true } ,
] ,
actions : [ { id : "sign" , label : "Sign" , primary : true } ] ,
} ) ;
if ( pick !== "sign" ) throw new Error ( "user rejected" ) ;
return rt . adapter . signMessage ( message ) ;
} ) ;
} ) ;
api . onMessage ( "eth.sendTransaction" , async ( p , m ) => {
const origin = fromPage ( m ) ;
if ( ! ethConnectedFor ( origin ) ) throw new Error ( "not connected — call eth_requestAccounts first" ) ;
const rt = activeEthRuntime ( ) ;
const tx = ( p && p . tx ) || { } ;
if ( ! tx . to ) throw new Error ( "tx.to required" ) ;
// MetaMask semantics: `value` and `gas`/`gasLimit` are hex-encoded wei;
// convert to numbers/bigints Aegis's own plan() understands.
const valueWei = tx . value ? BigInt ( tx . value ) . toString ( ) : "0" ;
return withOriginLock ( origin , async ( ) => {
const snap = rt . adapter . snapshot ( ) ;
const plan = await rt . adapter . plan ( { to : tx . to , amount : valueWei , sendMax : false } ) ;
const meta = chainMeta ( "eth" , rt . entry . network ) ;
const pick = await api . approvalModal ( {
title : "Send Ethereum transaction?" ,
origin ,
body : tx . data && tx . data !== "0x" ? "This transaction carries call data (a contract call). Check the destination + value carefully." : "This site is asking your wallet to send ETH." ,
rows : [
{ label : "To" , value : plan . recipients [ 0 ] . to , mono : true } ,
{ label : "Amount" , value : ` ${ fmtValue ( plan . recipients [ 0 ] . value , meta . decimals ) } ETH ` , strong : true } ,
{ label : "Fee (est.)" , value : ` ${ fmtValue ( plan . fee , meta . decimals ) } ETH ` } ,
{ label : "Wallet" , value : ` ${ rt . entry . label } — Ethereum · ${ snap . network } ` } ,
] ,
actions : [ { id : "send" , label : "Send" , primary : true } ] ,
} ) ;
if ( pick !== "send" ) throw new Error ( "user rejected" ) ;
const r = await rt . adapter . signAndBroadcast ( plan ) ;
return { txid : r . txid } ;
} ) ;
} ) ;
api . onMessage ( "eth.switchChain" , async ( p , m ) => {
fromPage ( m ) ;
const want = String ( p && p . chainId || "" ) . toLowerCase ( ) ;
const rt = activeEthRuntime ( ) ;
const cur = "0x" + Number ( rt . adapter . snapshot ( ) . chainId ) . toString ( 16 ) ;
if ( want === cur ) return null ;
throw new Error ( ` Aegis: switch chains via the Aegis sidebar picker. This wallet is on ${ cur } ; site asked for ${ want } . ` ) ;
} ) ;
// Read passthrough: forward eth_getBalance / eth_call / etc. to the
// wallet's own configured RPC. Nothing here reveals the private key.
api . onMessage ( "eth.rpc" , async ( p , m ) => {
fromPage ( m ) ;
const rt = activeEthRuntime ( ) ;
const method = String ( p && p . method || "" ) ;
const params = ( p && p . params ) || [ ] ;
if ( ! /^eth_|^net_|^web3_/ . test ( method ) ) throw new Error ( "Aegis: only eth_/net_/web3_ read methods are passed through" ) ;
return rt . adapter . _client . call ( method , params ) ;
} ) ;
// ---- Solana (wallet-adapter) ------------------------------------------
function activeSolRuntime ( ) {
const selId = selectedWalletId ( ) ;
const selRt = selId && ctx . runtimes . get ( selId ) ;
if ( selRt && selRt . entry . chain === "sol" && selRt . phase === "ready" ) return selRt ;
for ( const rt of ctx . runtimes . values ( ) ) if ( rt . entry . chain === "sol" && rt . phase === "ready" ) return rt ;
throw new Error ( "no Solana wallet available — add one in the Aegis sidebar" ) ;
}
function solConnectedFor ( origin ) {
const p = permissions ( api ) [ origin ] ;
return ! ! ( p && p . sol && p . sol . readAddress ) ;
}
api . onMessage ( "sol.connect" , async ( _p , m ) => {
const origin = fromPage ( m ) ;
const rt = activeSolRuntime ( ) ;
const snap = rt . adapter . snapshot ( ) ;
if ( solConnectedFor ( origin ) ) return { address : snap . address , network : snap . network } ;
return withOriginLock ( origin , async ( ) => {
const pick = await api . approvalModal ( {
title : "Connect this site to your Solana wallet?" ,
origin ,
body : "The site will see this address and can build transactions for you to sign." ,
rows : [
{ label : "Address" , value : snap . address , mono : true } ,
{ label : "Network" , value : snap . network === "mainnet" ? "Mainnet-beta" : "Devnet" } ,
{ label : "Wallet" , value : ` ${ rt . entry . label } — Solana · ${ snap . network } ` } ,
] ,
actions : [ { id : "allow" , label : "Connect" , primary : true } ] ,
checkbox : { id : "always" , label : "Always allow this site to see this address" } ,
} ) ;
if ( ! pick . startsWith ( "allow" ) ) throw new Error ( "user rejected" ) ;
if ( pick === "allow+always" ) {
const perms = permissions ( api ) ;
perms [ origin ] = { ... ( perms [ origin ] || { } ) , sol : { readAddress : true , network : snap . network } } ;
api . storage . set ( "permissions" , perms ) ;
emitState ( ) ;
}
return { address : snap . address , network : snap . network } ;
} ) ;
} ) ;
api . onMessage ( "sol.signMessage" , async ( p , m ) => {
const origin = fromPage ( m ) ;
if ( ! solConnectedFor ( origin ) ) throw new Error ( "not connected — call solana.connect first" ) ;
const rt = activeSolRuntime ( ) ;
const b64 = String ( p && p . messageB64 || "" ) ;
const bytes = Buffer . from ( b64 , "base64" ) ;
if ( bytes . length > 4096 ) throw new Error ( "message too long" ) ;
return withOriginLock ( origin , async ( ) => {
const preview = bytes . every ( ( c ) => c >= 0x20 && c < 0x7f ) ? bytes . toString ( "utf8" ) : ` < ${ bytes . length } bytes: 0x ${ bytes . toString ( "hex" ) . slice ( 0 , 60 ) } …> ` ;
const pick = await api . approvalModal ( {
title : "Sign a Solana message?" ,
origin ,
body : "Signing proves you control this address. It moves no SOL." ,
rows : [
{ label : "Message" , value : preview . length > 400 ? preview . slice ( 0 , 400 ) + "…" : preview , mono : true } ,
{ label : "Address" , value : rt . adapter . snapshot ( ) . address , mono : true } ,
] ,
actions : [ { id : "sign" , label : "Sign" , primary : true } ] ,
} ) ;
if ( pick !== "sign" ) throw new Error ( "user rejected" ) ;
return rt . adapter . signMessage ( bytes ) ;
} ) ;
} ) ;
// Dapp-built transaction: page hands us the wallet-adapter Transaction's
// .serializeMessage() output (base64). We sign it + broadcast via the
// adapter's own RPC. The txid returned by broadcast is the wire's txid.
api . onMessage ( "sol.signAndSend" , async ( p , m ) => {
const origin = fromPage ( m ) ;
if ( ! solConnectedFor ( origin ) ) throw new Error ( "not connected — call solana.connect first" ) ;
const rt = activeSolRuntime ( ) ;
const b64 = String ( p && p . messageB64 || "" ) ;
const messageBytes = new Uint8Array ( Buffer . from ( b64 , "base64" ) ) ;
return withOriginLock ( origin , async ( ) => {
const snap = rt . adapter . snapshot ( ) ;
const pick = await api . approvalModal ( {
title : "Sign + send a Solana transaction?" ,
origin ,
body : "The site built this transaction. Aegis can't decode arbitrary Solana instructions in this rev — verify the site before signing." ,
rows : [
{ label : "Message size" , value : ` ${ messageBytes . length } bytes ` } ,
{ label : "Address" , value : snap . address , mono : true } ,
{ label : "Wallet" , value : ` ${ rt . entry . label } — Solana · ${ snap . network } ` } ,
] ,
actions : [ { id : "send" , label : "Sign & send" , primary : true } ] ,
} ) ;
if ( pick !== "send" ) throw new Error ( "user rejected" ) ;
// Sign the message with the wallet's ed25519 key (Solana signs the
// raw message bytes, no prefix).
const sigInfo = rt . adapter . signMessage ( messageBytes ) ; // {signature: base58}
const sigBytes = ctx . d . base58check . decodeBase58 ( sigInfo . signature ) ;
if ( sigBytes . length !== 64 ) throw new Error ( "bad ed25519 signature length" ) ;
// Wire = compact-u16(1) || 64-byte sig || message. Single-signer only
// in this rev: multi-signer flows would need the dapp's other sigs.
const wire = new Uint8Array ( 1 + 64 + messageBytes . length ) ;
wire [ 0 ] = 0x01 ;
wire . set ( sigBytes , 1 ) ;
wire . set ( messageBytes , 65 ) ;
const wireB58 = ctx . d . base58check . encodeBase58 ( wire ) ;
const txid = await rt . adapter . _client . call ( "sendTransaction" , [ wireB58 ] ) ;
if ( typeof txid !== "string" || ! txid . length ) throw new Error ( "bad txid from RPC: " + JSON . stringify ( txid ) ) ;
setTimeout ( ( ) => rt . adapter . refresh ( ) . catch ( ( ) => { } ) , 4000 ) ;
return { txid } ;
} ) ;
} ) ;
2026-09-06 02:56:34 +02:00
}
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
// ---- activate ---------------------------------------------------------------
2026-09-06 02:33:27 +02:00
module . exports = {
activate ( api ) {
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
api . registerSidebarPanel ( { id : "main" , title : "Wallet" , icon : "🛡" , page : "panel.html" } ) ;
const c = ctx = {
api ,
d : null ,
runtimes : new Map ( ) , // walletId -> { entry, phase, error, adapter }
} ;
migrateLegacyStorage ( api ) ;
feat(theseus/bchwallet): receive + history — vault-derived keys, cashaddr, QR, electrum
Wallet core on mainnet:
- keys from api.vault.derive("bchwallet/mainnet/0") -> BIP32 m/44'/145'/0'
(@scure/bip32), never persisted; wiped on deactivate.
- lib/cashaddr.js (encode/decode + legacy Base58Check, spec vectors pass),
lib/keys.js (hash160, p2pkh, electrum scripthash, ECDSA DER + BIP-137
recoverable signing), lib/tx.js (serialization, SIGHASH_ALL|FORKID
digest, coin selection, fee estimate), lib/electrum.js (Fulcrum WSS
client with failover + subscriptions), lib/wallet.js (gap-limit scan,
balance, UTXOs, 25-tx history with per-tx deltas, cached public txs).
- qr.js: dependency-free QR encoder (byte mode, v1-10, EC M/L; verified
against jsQR).
- panel: balance header, Receive (QR, copy, next unused address, explorer),
History (deltas, confirmations, explorer links), Settings (derivation
path, electrum server list, xpub / approval-gated xprv reveal). Locked
and not-set-up vault states explained in-panel.
- host: api.import for ESM-only deps, api.openTab for explorer links; an
add-on whose activate() throws is no longer listed twice.
2026-09-06 02:46:41 +02:00
registerPanelMessages ( api ) ;
2026-09-06 02:56:34 +02:00
registerPageMessages ( api ) ;
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
loadDeps ( api ) . then ( ( d ) => {
feat(theseus/bchwallet): receive + history — vault-derived keys, cashaddr, QR, electrum
Wallet core on mainnet:
- keys from api.vault.derive("bchwallet/mainnet/0") -> BIP32 m/44'/145'/0'
(@scure/bip32), never persisted; wiped on deactivate.
- lib/cashaddr.js (encode/decode + legacy Base58Check, spec vectors pass),
lib/keys.js (hash160, p2pkh, electrum scripthash, ECDSA DER + BIP-137
recoverable signing), lib/tx.js (serialization, SIGHASH_ALL|FORKID
digest, coin selection, fee estimate), lib/electrum.js (Fulcrum WSS
client with failover + subscriptions), lib/wallet.js (gap-limit scan,
balance, UTXOs, 25-tx history with per-tx deltas, cached public txs).
- qr.js: dependency-free QR encoder (byte mode, v1-10, EC M/L; verified
against jsQR).
- panel: balance header, Receive (QR, copy, next unused address, explorer),
History (deltas, confirmations, explorer links), Settings (derivation
path, electrum server list, xpub / approval-gated xprv reveal). Locked
and not-set-up vault states explained in-panel.
- host: api.import for ESM-only deps, api.openTab for explorer links; an
add-on whose activate() throws is no longer listed twice.
2026-09-06 02:46:41 +02:00
if ( ctx !== c ) return ;
c . d = d ;
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
return mountAllWallets ( ) ;
feat(theseus/bchwallet): receive + history — vault-derived keys, cashaddr, QR, electrum
Wallet core on mainnet:
- keys from api.vault.derive("bchwallet/mainnet/0") -> BIP32 m/44'/145'/0'
(@scure/bip32), never persisted; wiped on deactivate.
- lib/cashaddr.js (encode/decode + legacy Base58Check, spec vectors pass),
lib/keys.js (hash160, p2pkh, electrum scripthash, ECDSA DER + BIP-137
recoverable signing), lib/tx.js (serialization, SIGHASH_ALL|FORKID
digest, coin selection, fee estimate), lib/electrum.js (Fulcrum WSS
client with failover + subscriptions), lib/wallet.js (gap-limit scan,
balance, UTXOs, 25-tx history with per-tx deltas, cached public txs).
- qr.js: dependency-free QR encoder (byte mode, v1-10, EC M/L; verified
against jsQR).
- panel: balance header, Receive (QR, copy, next unused address, explorer),
History (deltas, confirmations, explorer links), Settings (derivation
path, electrum server list, xpub / approval-gated xprv reveal). Locked
and not-set-up vault states explained in-panel.
- host: api.import for ESM-only deps, api.openTab for explorer links; an
add-on whose activate() throws is no longer listed twice.
2026-09-06 02:46:41 +02:00
} ) . catch ( ( e ) => {
if ( ctx !== c ) return ;
api . log ( "startup failed:" , e ? . message ) ;
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
emitState ( ) ;
feat(theseus/bchwallet): receive + history — vault-derived keys, cashaddr, QR, electrum
Wallet core on mainnet:
- keys from api.vault.derive("bchwallet/mainnet/0") -> BIP32 m/44'/145'/0'
(@scure/bip32), never persisted; wiped on deactivate.
- lib/cashaddr.js (encode/decode + legacy Base58Check, spec vectors pass),
lib/keys.js (hash160, p2pkh, electrum scripthash, ECDSA DER + BIP-137
recoverable signing), lib/tx.js (serialization, SIGHASH_ALL|FORKID
digest, coin selection, fee estimate), lib/electrum.js (Fulcrum WSS
client with failover + subscriptions), lib/wallet.js (gap-limit scan,
balance, UTXOs, 25-tx history with per-tx deltas, cached public txs).
- qr.js: dependency-free QR encoder (byte mode, v1-10, EC M/L; verified
against jsQR).
- panel: balance header, Receive (QR, copy, next unused address, explorer),
History (deltas, confirmations, explorer links), Settings (derivation
path, electrum server list, xpub / approval-gated xprv reveal). Locked
and not-set-up vault states explained in-panel.
- host: api.import for ESM-only deps, api.openTab for explorer links; an
add-on whose activate() throws is no longer listed twice.
2026-09-06 02:46:41 +02:00
} ) ;
} ,
deactivate ( ) {
const c = ctx ; ctx = null ;
if ( ! c ) return ;
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
for ( const rt of c . runtimes . values ( ) ) {
try { rt . adapter && rt . adapter . dispose ( ) ; } catch { }
}
c . runtimes . clear ( ) ;
2026-09-06 02:33:27 +02:00
} ,
} ;