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
|
|
|
// Transaction building for P2PKH spends on Bitcoin Cash: serialization, the
|
|
|
|
|
// BIP143-style replay-protected sighash (SIGHASH_ALL | FORKID), coin
|
|
|
|
|
// selection and fee estimation. Signing itself is delegated to WalletKeys so
|
|
|
|
|
// private keys stay in one module.
|
|
|
|
|
module.exports = function makeTx({ sha256 }) {
|
|
|
|
|
const SIGHASH_ALL_FORKID = 0x41;
|
|
|
|
|
const DUST = 546;
|
|
|
|
|
const P2PKH_INPUT_SIZE = 149; // outpoint 36 + len 1 + sig push 74 + pubkey push 34 + sequence 4
|
|
|
|
|
const P2PKH_OUTPUT_SIZE = 34;
|
|
|
|
|
const OVERHEAD = 10; // version 4 + in/out counts 2 + locktime 4
|
|
|
|
|
|
|
|
|
|
const dsha = (b) => sha256(sha256(b));
|
|
|
|
|
const toHex = (b) => Array.from(b, (x) => x.toString(16).padStart(2, "0")).join("");
|
|
|
|
|
const fromHex = (h) => Uint8Array.from(h.match(/../g) || [], (x) => parseInt(x, 16));
|
|
|
|
|
const concat = (...parts) => {
|
|
|
|
|
const n = parts.reduce((a, p) => a + p.length, 0);
|
|
|
|
|
const out = new Uint8Array(n); let o = 0;
|
|
|
|
|
for (const p of parts) { out.set(p, o); o += p.length; }
|
|
|
|
|
return out;
|
|
|
|
|
};
|
|
|
|
|
const u32le = (n) => Uint8Array.from([n & 0xff, (n >>> 8) & 0xff, (n >>> 16) & 0xff, (n >>> 24) & 0xff]);
|
|
|
|
|
const u64le = (n) => {
|
|
|
|
|
let v = BigInt(n); const out = new Uint8Array(8);
|
|
|
|
|
for (let i = 0; i < 8; i++) { out[i] = Number(v & 0xffn); v >>= 8n; }
|
|
|
|
|
return out;
|
|
|
|
|
};
|
|
|
|
|
const varint = (n) => {
|
|
|
|
|
if (n < 0xfd) return Uint8Array.from([n]);
|
|
|
|
|
if (n <= 0xffff) return Uint8Array.from([0xfd, n & 0xff, n >> 8]);
|
|
|
|
|
return concat(Uint8Array.from([0xfe]), u32le(n));
|
|
|
|
|
};
|
|
|
|
|
const varbytes = (b) => concat(varint(b.length), b);
|
|
|
|
|
const pushdata = (b) => {
|
|
|
|
|
if (b.length < 0x4c) return concat(Uint8Array.from([b.length]), b);
|
|
|
|
|
return concat(Uint8Array.from([0x4c, b.length]), b);
|
|
|
|
|
};
|
|
|
|
|
const outpoint = (inp) => concat(fromHex(inp.txid).reverse(), u32le(inp.vout));
|
|
|
|
|
|
|
|
|
|
const estimateSize = (nIn, nOut) => OVERHEAD + nIn * P2PKH_INPUT_SIZE + nOut * P2PKH_OUTPUT_SIZE;
|
chore(aegis): 0.8.2 — sectioned Settings tab
Settings grew tall enough that the user had to scroll past a dozen
cards to reach Prices, Sites or About. Split it into six named
sections (Security, Session, Wallet, Prices, Sites, About) with a
chip nav row at the top; only one section is visible at a time and
the choice persists across restarts.
Adds an About card that names the wallet, the aegis.x front-door
site and the silentmode.st umbrella, so support triage has a
one-click way to reach either from within the panel.
Includes the accumulated 0.7.x-0.8.1 wallet work that was already
shipping on OTA (CashTokens/BCMR, imported-wallet spend, siascan
integration, consolidate, currency picker, footer update chip).
2026-09-22 20:37:28 +02:00
|
|
|
// OP_RETURN data outputs vary — approximate with 12 + payload bytes to
|
|
|
|
|
// keep the fee estimate honest without threading a full byte size through.
|
|
|
|
|
const estimateSizeWithData = (nIn, nOut, dataBytes) => estimateSize(nIn, nOut) + (dataBytes ? 12 + dataBytes : 0);
|
|
|
|
|
const feeFor = (nIn, nOut, satPerByte, dataBytes = 0) => Math.ceil(estimateSizeWithData(nIn, nOut, dataBytes) * satPerByte);
|
|
|
|
|
|
|
|
|
|
// Build a memo protocol OP_RETURN script from a plain UTF-8 string. Layout:
|
|
|
|
|
// 0x6a OP_RETURN
|
|
|
|
|
// [pushdata] memo bytes (up to 220 to stay under standardness)
|
|
|
|
|
// The output's value is always 0 and it's flagged { data: true } so the
|
|
|
|
|
// dust check in select() skips it. Callers can pass raw bytes if they
|
|
|
|
|
// want to embed a non-UTF8 payload; strings are the common case.
|
|
|
|
|
function memoScript(input) {
|
|
|
|
|
const bytes = typeof input === "string" ? new TextEncoder().encode(input) : new Uint8Array(input || 0);
|
|
|
|
|
if (bytes.length > 220) throw new Error(`memo too long: ${bytes.length} bytes (max 220)`);
|
|
|
|
|
return concat(Uint8Array.from([0x6a]), pushdata(bytes));
|
|
|
|
|
}
|
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
|
|
|
|
|
|
|
|
// inputs: [{ txid, vout, value, script(Uint8Array), sig?(Uint8Array) }]
|
|
|
|
|
// outputs: [{ value, script(Uint8Array) }]
|
|
|
|
|
function serialize(tx) {
|
|
|
|
|
return concat(
|
|
|
|
|
u32le(tx.version ?? 2),
|
|
|
|
|
varint(tx.inputs.length),
|
|
|
|
|
...tx.inputs.map((i) => concat(outpoint(i), varbytes(i.unlocking || new Uint8Array(0)), u32le(i.sequence ?? 0xffffffff))),
|
|
|
|
|
varint(tx.outputs.length),
|
|
|
|
|
...tx.outputs.map((o) => concat(u64le(o.value), varbytes(o.script))),
|
|
|
|
|
u32le(tx.locktime ?? 0),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function sighash(tx, index) {
|
|
|
|
|
const inp = tx.inputs[index];
|
|
|
|
|
const hashPrevouts = dsha(concat(...tx.inputs.map(outpoint)));
|
|
|
|
|
const hashSequence = dsha(concat(...tx.inputs.map((i) => u32le(i.sequence ?? 0xffffffff))));
|
|
|
|
|
const hashOutputs = dsha(concat(...tx.outputs.map((o) => concat(u64le(o.value), varbytes(o.script)))));
|
|
|
|
|
const preimage = concat(
|
|
|
|
|
u32le(tx.version ?? 2),
|
|
|
|
|
hashPrevouts, hashSequence,
|
|
|
|
|
outpoint(inp),
|
|
|
|
|
varbytes(inp.script),
|
|
|
|
|
u64le(inp.value),
|
|
|
|
|
u32le(inp.sequence ?? 0xffffffff),
|
|
|
|
|
hashOutputs,
|
|
|
|
|
u32le(tx.locktime ?? 0),
|
|
|
|
|
u32le(SIGHASH_ALL_FORKID),
|
|
|
|
|
);
|
|
|
|
|
return dsha(preimage);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// signer(input, index, digest) -> { sig: DER bytes, publicKey }
|
|
|
|
|
function sign(tx, signer) {
|
|
|
|
|
tx.inputs.forEach((inp, i) => {
|
|
|
|
|
const { sig, publicKey } = signer(inp, i, sighash(tx, i));
|
|
|
|
|
inp.unlocking = concat(pushdata(concat(sig, Uint8Array.from([SIGHASH_ALL_FORKID]))), pushdata(publicKey));
|
|
|
|
|
});
|
|
|
|
|
const raw = serialize(tx);
|
|
|
|
|
return { raw, hex: toHex(raw), txid: toHex(dsha(raw).reverse()) };
|
|
|
|
|
}
|
|
|
|
|
|
chore(aegis): 0.8.2 — sectioned Settings tab
Settings grew tall enough that the user had to scroll past a dozen
cards to reach Prices, Sites or About. Split it into six named
sections (Security, Session, Wallet, Prices, Sites, About) with a
chip nav row at the top; only one section is visible at a time and
the choice persists across restarts.
Adds an About card that names the wallet, the aegis.x front-door
site and the silentmode.st umbrella, so support triage has a
one-click way to reach either from within the panel.
Includes the accumulated 0.7.x-0.8.1 wallet work that was already
shipping on OTA (CashTokens/BCMR, imported-wallet spend, siascan
integration, consolidate, currency picker, footer update chip).
2026-09-22 20:37:28 +02:00
|
|
|
// Largest-first accumulation. `targets` = [{ value, script, data? }]:
|
|
|
|
|
// data:true — an OP_RETURN memo output; value MUST be 0 and doesn't
|
|
|
|
|
// count toward the send amount or the dust check.
|
|
|
|
|
// sendMax spends every UTXO into the sole non-data target with no change.
|
|
|
|
|
// Data outputs are preserved verbatim in every returned outputs array.
|
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 select(utxos, targets, satPerByte, changeScript, { sendMax = false } = {}) {
|
chore(aegis): 0.8.2 — sectioned Settings tab
Settings grew tall enough that the user had to scroll past a dozen
cards to reach Prices, Sites or About. Split it into six named
sections (Security, Session, Wallet, Prices, Sites, About) with a
chip nav row at the top; only one section is visible at a time and
the choice persists across restarts.
Adds an About card that names the wallet, the aegis.x front-door
site and the silentmode.st umbrella, so support triage has a
one-click way to reach either from within the panel.
Includes the accumulated 0.7.x-0.8.1 wallet work that was already
shipping on OTA (CashTokens/BCMR, imported-wallet spend, siascan
integration, consolidate, currency picker, footer update chip).
2026-09-22 20:37:28 +02:00
|
|
|
const dataOuts = targets.filter((t) => t.data);
|
|
|
|
|
const spendOuts = targets.filter((t) => !t.data);
|
|
|
|
|
const dataBytes = dataOuts.reduce((a, t) => a + (t.script?.length || 0), 0);
|
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 sorted = utxos.slice().sort((a, b) => b.value - a.value);
|
|
|
|
|
const total = sorted.reduce((a, u) => a + u.value, 0);
|
|
|
|
|
if (sendMax) {
|
chore(aegis): 0.8.2 — sectioned Settings tab
Settings grew tall enough that the user had to scroll past a dozen
cards to reach Prices, Sites or About. Split it into six named
sections (Security, Session, Wallet, Prices, Sites, About) with a
chip nav row at the top; only one section is visible at a time and
the choice persists across restarts.
Adds an About card that names the wallet, the aegis.x front-door
site and the silentmode.st umbrella, so support triage has a
one-click way to reach either from within the panel.
Includes the accumulated 0.7.x-0.8.1 wallet work that was already
shipping on OTA (CashTokens/BCMR, imported-wallet spend, siascan
integration, consolidate, currency picker, footer update chip).
2026-09-22 20:37:28 +02:00
|
|
|
if (spendOuts.length !== 1) throw new Error("send max needs exactly one recipient");
|
|
|
|
|
const fee = feeFor(sorted.length, 1 + dataOuts.length, satPerByte, dataBytes);
|
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 value = total - fee;
|
|
|
|
|
if (!sorted.length || value < DUST) throw new Error("balance too small to send");
|
chore(aegis): 0.8.2 — sectioned Settings tab
Settings grew tall enough that the user had to scroll past a dozen
cards to reach Prices, Sites or About. Split it into six named
sections (Security, Session, Wallet, Prices, Sites, About) with a
chip nav row at the top; only one section is visible at a time and
the choice persists across restarts.
Adds an About card that names the wallet, the aegis.x front-door
site and the silentmode.st umbrella, so support triage has a
one-click way to reach either from within the panel.
Includes the accumulated 0.7.x-0.8.1 wallet work that was already
shipping on OTA (CashTokens/BCMR, imported-wallet spend, siascan
integration, consolidate, currency picker, footer update chip).
2026-09-22 20:37:28 +02:00
|
|
|
return { inputs: sorted, outputs: [{ value, script: spendOuts[0].script }, ...dataOuts], fee, change: 0 };
|
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
|
|
|
}
|
chore(aegis): 0.8.2 — sectioned Settings tab
Settings grew tall enough that the user had to scroll past a dozen
cards to reach Prices, Sites or About. Split it into six named
sections (Security, Session, Wallet, Prices, Sites, About) with a
chip nav row at the top; only one section is visible at a time and
the choice persists across restarts.
Adds an About card that names the wallet, the aegis.x front-door
site and the silentmode.st umbrella, so support triage has a
one-click way to reach either from within the panel.
Includes the accumulated 0.7.x-0.8.1 wallet work that was already
shipping on OTA (CashTokens/BCMR, imported-wallet spend, siascan
integration, consolidate, currency picker, footer update chip).
2026-09-22 20:37:28 +02:00
|
|
|
const want = spendOuts.reduce((a, t) => a + t.value, 0);
|
|
|
|
|
for (const t of spendOuts) if (t.value < DUST) throw new Error(`amount below dust limit (${DUST} sat)`);
|
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 chosen = []; let sum = 0;
|
|
|
|
|
for (const u of sorted) {
|
|
|
|
|
chosen.push(u); sum += u.value;
|
chore(aegis): 0.8.2 — sectioned Settings tab
Settings grew tall enough that the user had to scroll past a dozen
cards to reach Prices, Sites or About. Split it into six named
sections (Security, Session, Wallet, Prices, Sites, About) with a
chip nav row at the top; only one section is visible at a time and
the choice persists across restarts.
Adds an About card that names the wallet, the aegis.x front-door
site and the silentmode.st umbrella, so support triage has a
one-click way to reach either from within the panel.
Includes the accumulated 0.7.x-0.8.1 wallet work that was already
shipping on OTA (CashTokens/BCMR, imported-wallet spend, siascan
integration, consolidate, currency picker, footer update chip).
2026-09-22 20:37:28 +02:00
|
|
|
const feeWithChange = feeFor(chosen.length, spendOuts.length + dataOuts.length + 1, satPerByte, dataBytes);
|
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 (sum >= want + feeWithChange) {
|
|
|
|
|
const change = sum - want - feeWithChange;
|
|
|
|
|
if (change >= DUST) {
|
chore(aegis): 0.8.2 — sectioned Settings tab
Settings grew tall enough that the user had to scroll past a dozen
cards to reach Prices, Sites or About. Split it into six named
sections (Security, Session, Wallet, Prices, Sites, About) with a
chip nav row at the top; only one section is visible at a time and
the choice persists across restarts.
Adds an About card that names the wallet, the aegis.x front-door
site and the silentmode.st umbrella, so support triage has a
one-click way to reach either from within the panel.
Includes the accumulated 0.7.x-0.8.1 wallet work that was already
shipping on OTA (CashTokens/BCMR, imported-wallet spend, siascan
integration, consolidate, currency picker, footer update chip).
2026-09-22 20:37:28 +02:00
|
|
|
return {
|
|
|
|
|
inputs: chosen,
|
|
|
|
|
outputs: [...spendOuts, { value: change, script: changeScript }, ...dataOuts],
|
|
|
|
|
fee: feeWithChange, change,
|
|
|
|
|
};
|
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
|
|
|
}
|
|
|
|
|
// Change would be dust: fold it into the fee, one output fewer.
|
|
|
|
|
const fee = sum - want;
|
chore(aegis): 0.8.2 — sectioned Settings tab
Settings grew tall enough that the user had to scroll past a dozen
cards to reach Prices, Sites or About. Split it into six named
sections (Security, Session, Wallet, Prices, Sites, About) with a
chip nav row at the top; only one section is visible at a time and
the choice persists across restarts.
Adds an About card that names the wallet, the aegis.x front-door
site and the silentmode.st umbrella, so support triage has a
one-click way to reach either from within the panel.
Includes the accumulated 0.7.x-0.8.1 wallet work that was already
shipping on OTA (CashTokens/BCMR, imported-wallet spend, siascan
integration, consolidate, currency picker, footer update chip).
2026-09-22 20:37:28 +02:00
|
|
|
return { inputs: chosen, outputs: [...spendOuts, ...dataOuts], fee, change: 0 };
|
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
|
|
|
}
|
chore(aegis): 0.8.2 — sectioned Settings tab
Settings grew tall enough that the user had to scroll past a dozen
cards to reach Prices, Sites or About. Split it into six named
sections (Security, Session, Wallet, Prices, Sites, About) with a
chip nav row at the top; only one section is visible at a time and
the choice persists across restarts.
Adds an About card that names the wallet, the aegis.x front-door
site and the silentmode.st umbrella, so support triage has a
one-click way to reach either from within the panel.
Includes the accumulated 0.7.x-0.8.1 wallet work that was already
shipping on OTA (CashTokens/BCMR, imported-wallet spend, siascan
integration, consolidate, currency picker, footer update chip).
2026-09-22 20:37:28 +02:00
|
|
|
const feeNoChange = feeFor(chosen.length, spendOuts.length + dataOuts.length, satPerByte, dataBytes);
|
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 (sum >= want + feeNoChange && sum - want - feeNoChange < DUST) {
|
chore(aegis): 0.8.2 — sectioned Settings tab
Settings grew tall enough that the user had to scroll past a dozen
cards to reach Prices, Sites or About. Split it into six named
sections (Security, Session, Wallet, Prices, Sites, About) with a
chip nav row at the top; only one section is visible at a time and
the choice persists across restarts.
Adds an About card that names the wallet, the aegis.x front-door
site and the silentmode.st umbrella, so support triage has a
one-click way to reach either from within the panel.
Includes the accumulated 0.7.x-0.8.1 wallet work that was already
shipping on OTA (CashTokens/BCMR, imported-wallet spend, siascan
integration, consolidate, currency picker, footer update chip).
2026-09-22 20:37:28 +02:00
|
|
|
return { inputs: chosen, outputs: [...spendOuts, ...dataOuts], fee: sum - want, change: 0 };
|
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
|
|
|
}
|
|
|
|
|
}
|
chore(aegis): 0.8.2 — sectioned Settings tab
Settings grew tall enough that the user had to scroll past a dozen
cards to reach Prices, Sites or About. Split it into six named
sections (Security, Session, Wallet, Prices, Sites, About) with a
chip nav row at the top; only one section is visible at a time and
the choice persists across restarts.
Adds an About card that names the wallet, the aegis.x front-door
site and the silentmode.st umbrella, so support triage has a
one-click way to reach either from within the panel.
Includes the accumulated 0.7.x-0.8.1 wallet work that was already
shipping on OTA (CashTokens/BCMR, imported-wallet spend, siascan
integration, consolidate, currency picker, footer update chip).
2026-09-22 20:37:28 +02:00
|
|
|
const short = want + feeFor(Math.max(1, sorted.length), spendOuts.length + dataOuts.length + 1, satPerByte, dataBytes) - total;
|
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
|
|
|
throw new Error(`insufficient funds: need about ${short} more sat`);
|
|
|
|
|
}
|
|
|
|
|
|
chore(aegis): 0.8.2 — sectioned Settings tab
Settings grew tall enough that the user had to scroll past a dozen
cards to reach Prices, Sites or About. Split it into six named
sections (Security, Session, Wallet, Prices, Sites, About) with a
chip nav row at the top; only one section is visible at a time and
the choice persists across restarts.
Adds an About card that names the wallet, the aegis.x front-door
site and the silentmode.st umbrella, so support triage has a
one-click way to reach either from within the panel.
Includes the accumulated 0.7.x-0.8.1 wallet work that was already
shipping on OTA (CashTokens/BCMR, imported-wallet spend, siascan
integration, consolidate, currency picker, footer update chip).
2026-09-22 20:37:28 +02:00
|
|
|
return { SIGHASH_ALL_FORKID, DUST, serialize, sighash, sign, select, feeFor, estimateSize, memoScript, toHex, fromHex, dsha, concat, pushdata };
|
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
|
|
|
};
|