/* eslint-env browser */ 'use strict'; const Logger = require('blgr'); const FullNode = require('../../lib/node/fullnode'); const Amount = require('../../lib/btc/amount'); const plugin = require('../../lib/wallet/plugin'); const util = require('../../lib/utils/util'); const ProxySocket = require('./proxysocket'); const body = document.getElementsByTagName('body')[0]; const log = document.getElementById('log'); const wdiv = document.getElementById('wallet'); const tdiv = document.getElementById('tx'); const floating = document.getElementById('floating'); const send = document.getElementById('send'); const newaddr = document.getElementById('newaddr'); const chainState = document.getElementById('state'); const rpc = document.getElementById('rpc'); const cmd = document.getElementById('cmd'); const items = []; let scrollback = 0; const logger = new Logger({ level: 'debug', console: true }); logger.writeConsole = function writeConsole(level, module, args) { const name = Logger.levelsByVal[level]; const msg = this.fmt(args, false); if (++scrollback > 1000) { log.innerHTML = ''; scrollback = 1; } const now = Math.floor(Date.now() / 1000); log.innerHTML += `${now} `; if (name === 'error') { log.innerHTML += `[${name}] `; if (module) log.innerHTML += `(${module}) `; log.innerHTML += ''; } else { log.innerHTML += `[${name}] `; if (module) log.innerHTML += `(${module}) `; } log.innerHTML += escape(msg) + '\n'; log.scrollTop = log.scrollHeight; }; const node = new FullNode({ hash: true, query: true, prune: true, network: 'main', memory: false, coinCache: 30, logConsole: true, workers: true, workerFile: '/worker.js', createSocket: (port, host) => { const proto = global.location.protocol === 'https:' ? 'wss' : 'ws'; const hostname = global.location.host; return ProxySocket.connect(`${proto}://${hostname}`, port, host); }, logger: logger, plugins: [plugin] }); const {wdb} = node.require('walletdb'); wdb.options.witness = true; window.onunhandledrejection = function onunhandledrejection(event) { throw event.reason; }; body.onmouseup = function onmouseup() { floating.style.display = 'none'; }; floating.onmouseup = function onmouseup(ev) { ev.stopPropagation(); return false; }; function show(obj) { if (obj instanceof Error) { floating.innerHTML = obj.stack; floating.style.display = 'block'; return; } floating.innerHTML = escape(JSON.stringify(obj, null, 2)); floating.style.display = 'block'; } rpc.onsubmit = function onsubmit(ev) { const text = cmd.value || ''; const argv = text.trim().split(/\s+/); const method = argv.shift(); const params = []; cmd.value = ''; for (const arg of argv) { let param; try { param = JSON.parse(arg); } catch (e) { param = arg; } params.push(param); } (async () => { try { const result = await node.rpc.execute({ method, params }); show(result); } catch (e) { show(e); } })(); ev.preventDefault(); ev.stopPropagation(); return false; }; send.onsubmit = function onsubmit(ev) { const value = document.getElementById('amount').value; const address = document.getElementById('address').value; const options = { outputs: [{ address: address, value: Amount.value(value) }] }; (async () => { try { const mtx = await wdb.primary.createTX(options); await wdb.primary.sign(mtx); await node.relay(mtx.toTX()); show(mtx); } catch (e) { show(e); } })(); ev.preventDefault(); ev.stopPropagation(); return false; }; newaddr.onmouseup = function onmouseup() { (async () => { try { await wdb.primary.createReceive(); formatWallet(wdb.primary); } catch (e) { show(e); } })(); }; function kb(size) { size /= 1000; return size.toFixed(2) + 'kb'; } function create(html) { const el = document.createElement('div'); el.innerHTML = html; return el.firstChild; } function escape(html, encode) { return html .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } function addItem(item, entry) { const height = entry ? entry.height : -1; if (items.length === 20) { const el = items.shift(); tdiv.removeChild(el); el.onmouseup = null; } const el = create('' + `` + `${item.rhash()} (${height} - ${kb(item.getSize())})` + '' ); tdiv.appendChild(el); setMouseup(el, item); items.push(el); chainState.innerHTML = '' + `tx=${node.chain.db.state.tx} ` + `coin=${node.chain.db.state.coin} ` + `value=${Amount.btc(node.chain.db.state.value)}`; } function setMouseup(el, obj) { el.onmouseup = function onmouseup(ev) { show(obj); ev.stopPropagation(); return false; }; } async function formatWallet(wallet) { try { await _formatWallet(wallet); } catch (e) { show(e); } } async function _formatWallet(wallet) { const {key, mnemonic} = wallet.master.toJSON(node.network, true); const account = await wallet.getAccount('default'); const receive = account.receiveAddress(); const nested = account.nestedAddress(); const raddr = receive.toString(node.network); const naddr = nested ? nested.toString(node.network) : null; let html = ''; html += 'Wallet
'; if (naddr) { html += `Current Address (p2wpkh): ${raddr}
`; html += `Current Address (p2wpkh behind p2sh): ${naddr}
`; } else { html += `Current Address: ${raddr}
`; } html += `Extended Private Key: ${key.xprivkey}
`; html += `Mnemonic: ${mnemonic.phrase}
`; const balance = await wallet.getBalance(); html += `Confirmed Balance: ${Amount.btc(balance.confirmed)}
`; html += `Unconfirmed Balance: ${Amount.btc(balance.unconfirmed)}
`; const txs = await wallet.getHistory(); const det = await wallet.toDetails(txs); html += 'TXs:\n'; wdiv.innerHTML = html; for (const tx of det) { const hash = util.revHex(tx.hash); const el = create( `${hash}`); wdiv.appendChild(el); setMouseup(el, tx.toJSON()); } } node.chain.on('block', addItem); node.mempool.on('tx', addItem); (async () => { await node.open(); await node.connect(); node.startSync(); wdb.primary.on('balance', () => { formatWallet(wdb.primary); }); formatWallet(wdb.primary); })().catch((err) => { throw err; });