diff --git a/bundled-addons/aegis/addon.json b/bundled-addons/aegis/addon.json index 84f46b6d..f237fb85 100644 --- a/bundled-addons/aegis/addon.json +++ b/bundled-addons/aegis/addon.json @@ -1,7 +1,7 @@ { "id": "aegis", "name": "Aegis Wallet", - "version": "0.9.4", + "version": "0.9.5", "category": "plugin", "description": "Multi-chain wallet (BCH, BTC, TRX, ETH, SOL, SC, DGB) derived from your Theseus vault. Dapps get window.bitcoincash on .x sites; window.tronWeb / window.tronLink / window.ethereum / window.solana on any https page.", "author": "Silent Mode", diff --git a/bundled-addons/aegis/lib/wc-sign.js b/bundled-addons/aegis/lib/wc-sign.js index 5872afce..33d76999 100644 --- a/bundled-addons/aegis/lib/wc-sign.js +++ b/bundled-addons/aegis/lib/wc-sign.js @@ -37,8 +37,23 @@ async function signTx({ request, account, branches, libauth, secp256k1 }) { hash256, encodeTransaction, } = libauth; - const tx = ensureTransaction(request.transaction, libauth); - const sourceOutputs = (request.sourceOutputs || []).map((o, i) => { + // The WC message nests the whole WcSignTransactionRequest under + // `.transaction`, so the real shape is: + // request.transaction.transaction — the tx (object or hex) + // request.transaction.sourceOutputs — the spent outputs + // request.inputPaths / request.sequence — on the outer message + // Reading request.transaction as the tx (and request.sourceOutputs as + // the outputs) meant `tx.inputs` was undefined and signing threw on the + // first real request. index.js already read the nested + // request.transaction.userPrompt for the approval dialog, so only this + // module had it wrong. The flat shape is still accepted so a caller + // that hands us an already-unwrapped payload keeps working. + const inner = (request.transaction && (request.transaction.transaction !== undefined + || request.transaction.sourceOutputs !== undefined)) + ? request.transaction + : request; + const tx = ensureTransaction(inner.transaction, libauth); + const sourceOutputs = (inner.sourceOutputs || []).map((o, i) => { if (o.contract) throw new Error(`wc-sign: input ${i} spends a contract — unsupported`); return { lockingBytecode: o.lockingBytecode instanceof Uint8Array ? o.lockingBytecode : fromHex(o.lockingBytecode), @@ -63,12 +78,22 @@ async function signTx({ request, account, branches, libauth, secp256k1 }) { if (!branch) throw new Error(`wc-sign: unknown path "${hint.pathName}"`); const node = branch.deriveChild(hint.addressIndex); - const preimage = generateSigningSerializationBCH({ - inputIndex: i, - signingSerializationType: new Uint8Array([REQUIRED_SIGHASH]), - sourceOutputs, - transaction: { ...tx, inputs: signedInputs }, - }); + // generateSigningSerializationBCH takes TWO positional arguments: + // (compilationContext, { coveredBytecode, signingSerializationType }) + // Passing one merged object left coveredBytecode undefined, which threw + // "Cannot destructure property 'coveredBytecode' of 'undefined'". + // For P2PKH the covered bytecode is the spent output's locking script. + const preimage = generateSigningSerializationBCH( + { + inputIndex: i, + sourceOutputs, + transaction: { ...tx, inputs: signedInputs }, + }, + { + coveredBytecode: sourceOutputs[i].lockingBytecode, + signingSerializationType: new Uint8Array([REQUIRED_SIGHASH]), + }, + ); const digest = hash256(preimage); const sig = secp256k1.sign(digest, node.privateKey, { prehash: false, lowS: true, format: "der" }); // signature || sighashType byte diff --git a/bundled-addons/aegis/lib/wc.js b/bundled-addons/aegis/lib/wc.js index 41c03efd..e8c81cc2 100644 --- a/bundled-addons/aegis/lib/wc.js +++ b/bundled-addons/aegis/lib/wc.js @@ -171,12 +171,29 @@ module.exports = function makeWc({ HDKey, secp256k1, sha256, hkdf, WalletConnect function snapshot() { const out = {}; for (const [walletId, mgr] of managers) { - const list = [...(mgr.connections?.values?.() || [])].map((c) => ({ + // getConnections() is the documented accessor and returns a plain + // {id: RelayConnectionState} record. We used to walk mgr.connections + // (a private Map) directly, which works but is one library refactor + // away from silently returning nothing. + const states = typeof mgr.getConnections === "function" + ? Object.values(mgr.getConnections() || {}) + : [...(mgr.connections?.values?.() || [])]; + const list = states.map((c) => ({ id: c.id, uri: c.uri, + // `label` is the library's own "dapp name once known, otherwise + // Connecting…", so it's the right thing to show while a pairing + // is still settling. + label: c.label || null, dappName: c.dappName || null, dappIcon: c.dappIcon || null, - status: c.status?.kind || String(c.status || "unknown"), + // RelayStatus is an OBJECT: { status: "connected" | "reconnecting" + // | "disconnected" | "session_deleted" }. Reading `.kind` (which + // does not exist) fell through to String(object) and put the + // literal "[object Object]" in the panel's status field. + status: typeof c.status === "string" + ? c.status + : (c.status?.status || "unknown"), connectedAt: c.connectedAt || null, })); out[walletId] = list; diff --git a/bundled-addons/aegis/panel.js b/bundled-addons/aegis/panel.js index ce8b70cb..98c3461c 100644 --- a/bundled-addons/aegis/panel.js +++ b/bundled-addons/aegis/panel.js @@ -1825,6 +1825,19 @@ function paintRcvMode() { } } +// A paired dapp's relay status, from RelayStatus.status. Worth showing: +// "reconnecting" is the difference between "the dapp will see my next +// signature" and "this pairing is dead and I should re-pair", and that is +// invisible otherwise. "connected" is the normal case, so it stays quiet. +function wcStatusTag(status) { + const s = String(status || ""); + if (!s || s === "connected") return ""; + const label = s === "reconnecting" ? "RECONNECTING" + : s === "session_deleted" ? "SESSION GONE" + : s === "disconnected" ? "OFFLINE" : s.toUpperCase(); + return `${esc(label)}`; +} + // Content of the Connect pane in the picker — WizardConnect pairing lives // here so users can paste a wiz:// URI without diving into per-wallet // Settings. If no BCH wallet is ready, we show a gate instead of the form. @@ -1866,7 +1879,7 @@ function renderConnectPane(bchWallets) { const rowsHtml = rows.length ? rows.map((c) => `
${c.dappIcon ? `` : ""}
-
${esc(c.dappName || "(pairing…)")}
on ${esc(c.walletLabel)} · ${esc((c.uri || "").slice(0, 40))}…
+
${esc(c.dappName || c.label || "(pairing…)")} ${wcStatusTag(c.status)}
on ${esc(c.walletLabel)} · ${esc((c.uri || "").slice(0, 40))}…
`).join("") : `
No dapps paired yet.
`; @@ -4207,11 +4220,11 @@ function renderWcSites() { const conns = (state?.wc && state.wc[walletId]) || []; if (!conns.length) { el.innerHTML = `
No dapps paired yet.
`; return; } el.innerHTML = conns.map((c) => { - const label = c.dappName || "(pairing…)"; + const label = c.dappName || c.label || "(pairing…)"; const iconHtml = c.dappIcon ? `` : ""; return `
${iconHtml}
-
${esc(label)}
${esc((c.uri || "").slice(0, 46))}…
+
${esc(label)} ${wcStatusTag(c.status)}
${esc((c.uri || "").slice(0, 46))}…
`; }).join("");