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.
83 lines
3.2 KiB
JavaScript
83 lines
3.2 KiB
JavaScript
// Base58Check encode/decode for Tron addresses (0x41 || H160 || sha256d[:4]).
|
|
// Bitcoin-style base58 alphabet; the caller supplies the raw 21-byte payload
|
|
// (version byte first) so this module knows nothing about Tron itself.
|
|
const ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
const INDEX = new Int8Array(128).fill(-1);
|
|
for (let i = 0; i < ALPHABET.length; i++) INDEX[ALPHABET.charCodeAt(i)] = i;
|
|
|
|
module.exports = function makeBase58Check({ sha256 }) {
|
|
function encodeBase58(bytes) {
|
|
let zeros = 0;
|
|
while (zeros < bytes.length && bytes[zeros] === 0) zeros++;
|
|
// Convert base-256 → base-58 by repeated division.
|
|
const b58 = new Uint8Array(Math.ceil(bytes.length * 138 / 100 + 1));
|
|
let length = 0;
|
|
for (let i = zeros; i < bytes.length; i++) {
|
|
let carry = bytes[i];
|
|
let j = 0;
|
|
for (let k = b58.length - 1; (carry !== 0 || j < length) && k >= 0; k--, j++) {
|
|
carry += (b58[k] << 8) >>> 0;
|
|
b58[k] = carry % 58;
|
|
carry = (carry / 58) | 0;
|
|
}
|
|
length = j;
|
|
}
|
|
// Skip leading zero-bytes in the base58 buffer, then prepend '1' per leading zero-byte in input.
|
|
let it = b58.length - length;
|
|
while (it < b58.length && b58[it] === 0) it++;
|
|
let out = "";
|
|
for (let i = 0; i < zeros; i++) out += ALPHABET[0];
|
|
for (; it < b58.length; it++) out += ALPHABET[b58[it]];
|
|
return out;
|
|
}
|
|
|
|
function decodeBase58(str) {
|
|
if (typeof str !== "string" || str.length === 0) throw new Error("base58: empty input");
|
|
let zeros = 0;
|
|
while (zeros < str.length && str[zeros] === ALPHABET[0]) zeros++;
|
|
const out = new Uint8Array(Math.ceil(str.length * 733 / 1000 + 1));
|
|
let length = 0;
|
|
for (let i = zeros; i < str.length; i++) {
|
|
const c = str.charCodeAt(i);
|
|
const val = c < 128 ? INDEX[c] : -1;
|
|
if (val < 0) throw new Error("base58: bad character " + JSON.stringify(str[i]));
|
|
let carry = val;
|
|
let j = 0;
|
|
for (let k = out.length - 1; (carry !== 0 || j < length) && k >= 0; k--, j++) {
|
|
carry += 58 * out[k];
|
|
out[k] = carry & 0xff;
|
|
carry >>>= 8;
|
|
}
|
|
length = j;
|
|
}
|
|
let it = out.length - length;
|
|
while (it < out.length && out[it] === 0) it++;
|
|
const total = zeros + (out.length - it);
|
|
const decoded = new Uint8Array(total);
|
|
for (let i = 0; i < zeros; i++) decoded[i] = 0;
|
|
let p = zeros;
|
|
while (it < out.length) decoded[p++] = out[it++];
|
|
return decoded;
|
|
}
|
|
|
|
function encodeCheck(payload) {
|
|
const bytes = payload instanceof Uint8Array ? payload : Uint8Array.from(payload);
|
|
const check = sha256(sha256(bytes)).slice(0, 4);
|
|
const full = new Uint8Array(bytes.length + 4);
|
|
full.set(bytes, 0);
|
|
full.set(check, bytes.length);
|
|
return encodeBase58(full);
|
|
}
|
|
|
|
function decodeCheck(str) {
|
|
const full = decodeBase58(str);
|
|
if (full.length < 5) throw new Error("base58check: too short");
|
|
const payload = full.slice(0, full.length - 4);
|
|
const check = full.slice(full.length - 4);
|
|
const want = sha256(sha256(payload)).slice(0, 4);
|
|
for (let i = 0; i < 4; i++) if (check[i] !== want[i]) throw new Error("base58check: bad checksum");
|
|
return payload;
|
|
}
|
|
|
|
return { encodeBase58, decodeBase58, encodeCheck, decodeCheck };
|
|
};
|