diff --git a/bin/hsd-cli b/bin/hsd-cli index 46792ae7..4dda1bcc 100755 --- a/bin/hsd-cli +++ b/bin/hsd-cli @@ -1,5 +1,267 @@ #!/usr/bin/env node - 'use strict'; +'use strict'; - require('hs-client/bin/hsd-cli'); +const Config = require('bcfg'); +const {NodeClient} = require('../lib/client'); + +// NOTE: This is part of generated `hs-client`. +// Don't introduce any unnecessary dependencies to this. +// This needs to be remain as is for hs-client to be simple. + +const ports = { + main: 12037, + testnet: 13037, + regtest: 14037, + simnet: 15037 +}; + +const HELP = ` +Commands: + $ block [hash/height]: View block. + $ broadcast [tx-hex]: Broadcast transaction. + $ coin [hash+index/address]: View coins. + $ header [hash/height]: View block header. + $ help: Show help message. + $ info: Get server info. + $ mempool: Get mempool snapshot. + $ reset [height/hash]: Reset chain to desired block. + $ rpc [command] [args]: Execute RPC command. + $ tx [hash/address]: View transactions. + +For additional information and a complete list of commands +visit https://hsd-dev.org/api-docs/ +`; + +class CLI { + constructor() { + this.config = new Config('hsd', { + suffix: 'network', + fallback: 'main', + alias: { + 'n': 'network', + 'u': 'url', + 'uri': 'url', + 'k': 'api-key', + 's': 'ssl', + 'h': 'httphost', + 'p': 'httpport' + } + }); + + this.config.load({ + argv: true, + env: true + }); + + this.config.open('hsd.conf'); + + this.argv = this.config.argv; + this.network = this.config.str('network', 'main'); + + this.client = new NodeClient({ + url: this.config.str('url'), + apiKey: this.config.str('api-key'), + ssl: this.config.bool('ssl'), + host: this.config.str('http-host'), + port: this.config.uint('http-port') + || ports[this.network] + || ports.main, + timeout: this.config.uint('timeout'), + limit: this.config.uint('limit') + }); + } + + log(json) { + if (typeof json === 'string') + return console.log.apply(console, arguments); + return console.log(JSON.stringify(json, null, 2)); + } + + async getInfo() { + const info = await this.client.getInfo(); + this.log(info); + } + + async getTX() { + const hash = this.config.str(0, ''); + + if (hash.length !== 64) { + const txs = await this.client.getTXByAddress(hash); + this.log(txs); + return; + } + + const tx = await this.client.getTX(hash); + + if (!tx) { + this.log('TX not found.'); + return; + } + + this.log(tx); + } + + async getBlock() { + let hash = this.config.str(0, ''); + + if (hash.length !== 64) + hash = parseInt(hash, 10); + + const block = await this.client.getBlock(hash); + + if (!block) { + this.log('Block not found.'); + return; + } + + this.log(block); + } + + async getBlockHeader() { + let hash = this.config.str(0, ''); + + if (hash.length !== 64) + hash = parseInt(hash, 10); + + const header = await this.client.getBlockHeader(hash); + + if (!header) { + this.log('Block header not found.'); + return; + } + + this.log(header); + } + + async getCoin() { + const hash = this.config.str(0, ''); + const index = this.config.uint(1); + + if (hash.length !== 64) { + const coins = await this.client.getCoinsByAddress(hash); + this.log(coins); + return; + } + + const coin = await this.client.getCoin(hash, index); + + if (!coin) { + this.log('Coin not found.'); + return; + } + + this.log(coin); + } + + async getMempool() { + const txs = await this.client.getMempool(); + + this.log(txs); + } + + async broadcast() { + const raw = this.config.str([0, 'tx']); + const tx = await this.client.broadcast(raw); + + this.log('Broadcasted:'); + this.log(tx); + } + + async reset() { + let hash = this.config.str(0); + + if (hash.length !== 64) + hash = parseInt(hash, 10); + + await this.client.reset(hash); + + this.log('Chain has been reset.'); + } + + async rpc() { + const method = this.argv.shift(); + if (!method) { + this.log('Missing RPC method'); + return; + } + + const params = []; + + for (const arg of this.argv) { + let param; + try { + param = JSON.parse(arg); + } catch (e) { + param = arg; + } + params.push(param); + } + + let result; + try { + result = await this.client.execute(method, params); + } catch (e) { + if (e.type === 'RPCError') { + this.log(e.message); + return; + } + throw e; + } + + this.log(result); + } + + async open() { + switch (this.argv.shift()) { + case 'block': + await this.getBlock(); + break; + case 'broadcast': + await this.broadcast(); + break; + case 'coin': + await this.getCoin(); + break; + case 'header': + await this.getBlockHeader(); + break; + case 'help': + process.stdout.write(HELP + '\n'); + break; + case 'info': + await this.getInfo(); + break; + case 'mempool': + await this.getMempool(); + break; + case 'reset': + await this.reset(); + break; + case 'rpc': + await this.rpc(); + break; + case 'tx': + await this.getTX(); + break; + default: + process.stdout.write('Unrecognized command.\n'); + process.stdout.write(HELP + '\n'); + break; + } + } + + async destroy() { + if (this.client && this.client.opened) + await this.client.close(); + } +} + +(async () => { + const cli = new CLI(); + await cli.open(); + await cli.destroy(); +})().catch((err) => { + console.error(err.stack); + process.exit(1); +}); diff --git a/bin/hsd-rpc b/bin/hsd-rpc new file mode 100755 index 00000000..3c262d4c --- /dev/null +++ b/bin/hsd-rpc @@ -0,0 +1,23 @@ +#!/bin/sh + +# NOTE: This is part of generated `hs-client`. + +rl=0 + +if ! type perl > /dev/null 2>& 1; then + if uname | grep -i 'darwin' > /dev/null; then + echo 'hsd-rpc requires perl to start on OSX.' >& 2 + exit 1 + fi + rl=1 +fi + +if test $rl -eq 1; then + file=$(readlink -f "$0") +else + file=$(perl -MCwd -e "print Cwd::realpath('$0')") +fi + +dir=$(dirname "$file") + +exec "${dir}/hsd-cli" rpc "$@" diff --git a/bin/hsw-cli b/bin/hsw-cli index b3650c5a..163fb976 100755 --- a/bin/hsw-cli +++ b/bin/hsw-cli @@ -1,5 +1,720 @@ #!/usr/bin/env node - 'use strict'; +'use strict'; - require('hs-client/bin/hsw-cli'); +const Config = require('bcfg'); +const {WalletClient} = require('../lib/client'); +const EXP = 6; + +// NOTE: This is part of generated `hs-client`. +// Don't introduce any unnecessary dependencies to this. +// This needs to be remain as is for hs-client to be simple. + +const ports = { + main: 12039, + testnet: 13039, + regtest: 14039, + simnet: 15039 +}; + +const HELP = ` +Commands: + $ abandon [hash]: Abandon a transaction. + $ account create [account-name]: Create account. + $ account get [account-name]: Get account details. + $ account list: List account names. + $ address [account-name]: Derive new address. + $ balance: Get wallet balance. + $ block [height]: View wallet block. + $ blocks: List wallet blocks. + $ change [account-name]: Derive new change address. + $ coins: View wallet coins. + $ dump [address]: Get wallet key WIF by address. + $ get: View wallet. + $ help: Show help message. + $ history: View TX history. + $ import [wif|hex]: Import private or public key. + $ key [address]: Get wallet key by address. + $ listen: Listen for events. + $ lock: Lock wallet. + $ mkauctiontxs [name] [bid] [lockup] [broadcast]: Create bid and reveal TXs. + $ mktx [address] [value]: Create transaction. + $ mkwallet [id]: Create wallet. + $ pending: View pending TXs. + $ resendwallet [id]: Resend pending transactions for a single wallet. + $ retoken: Create new api key. + $ send [address] [value]: Send transaction. + $ shared add [account-name] [xpubkey]: Add key to account. + $ shared remove [account-name] [xpubkey]: Remove key from account. + $ shared list [account-name]: List keys in account. + $ sign [tx-hex]: Sign transaction. + $ tx [hash]: View transaction details. + $ unlock [passphrase] [timeout?]: Unlock wallet. + $ view [tx-hex]: Parse and view transaction. + $ watch [address]: Import an address. + $ zap [age]: Zap pending wallet TXs. + +If node is run with wallet-auth flag, then wallet commands +require authorization token. +Admin commands require admin permissions for provided authorization token: + $ backup [path]: Backup the wallet db. + $ master: View wallet master key. + $ rescan [height]: Rescan for transactions. + $ resend: Resend pending transactions for all wallets. + $ rpc [command] [args]: Execute RPC command. + $ wallets: List all wallets. + +Other options: + --id [wallet id]: Wallet id. + --passphrase [passphrase]: For signing/account-creation. + --account [account-name]: Account name. + --token [token]: Wallet-specific or admin authorization token. + --api-key [key]: General API authorization key. + +For additional information and a complete list of commands +visit https://hsd-dev.org/api-docs/ +`; + +class CLI { + constructor() { + this.config = new Config('hsd', { + suffix: 'network', + fallback: 'main', + alias: { + 'n': 'network', + 'u': 'url', + 'uri': 'url', + 'k': 'api-key', + 's': 'ssl', + 'h': 'httphost', + 'p': 'httpport' + } + }); + + this.config.load({ + argv: true, + env: true + }); + + this.config.open('hsw.conf'); + + this.argv = this.config.argv; + this.network = this.config.str('network', 'main'); + + const id = this.config.str('id', 'primary'); + const token = this.config.str('token', ''); + + this.client = new WalletClient({ + url: this.config.str('url'), + apiKey: this.config.str('api-key'), + ssl: this.config.bool('ssl'), + host: this.config.str('http-host'), + port: this.config.uint('http-port') + || ports[this.network] + || ports.main, + timeout: this.config.uint('timeout'), + token + }); + + this.wallet = this.client.wallet(id, token); + } + + log(json) { + if (typeof json === 'string') + return console.log.apply(console, arguments); + return console.log(JSON.stringify(json, null, 2)); + } + + async getWallets() { + const wallets = await this.client.getWallets(); + this.log(wallets); + } + + async createWallet() { + const id = this.config.str([0, 'id']); + + const options = { + type: this.config.str('type'), + master: this.config.str('master'), + mnemonic: this.config.str('mnemonic'), + m: this.config.uint('m'), + n: this.config.uint('n'), + witness: this.config.bool('witness'), + passphrase: this.config.str('passphrase'), + bip39Passphrase: this.config.str('bip39Passphrase'), + watchOnly: this.config.has('key') ? true : this.config.bool('watch'), + accountKey: this.config.str('key'), + lookahead: this.config.uint('lookahead'), + language: this.config.str('language') + }; + + const wallet = await this.client.createWallet(id, options); + + this.log(wallet); + } + + async getMaster() { + const master = await this.wallet.getMaster(); + + this.log(master); + } + + async getKey() { + const address = this.config.str(0); + const key = await this.wallet.getKey(address); + + this.log(key); + } + + async getWIF() { + const address = this.config.str(0); + const passphrase = this.config.str('passphrase'); + const key = await this.wallet.getWIF(address, passphrase); + + if (!key) { + this.log('Key not found.'); + return; + } + + this.log(key.privateKey); + } + + async addSharedKey() { + const key = this.config.str(0); + const account = this.config.str('account'); + + await this.wallet.addSharedKey(account, key); + + this.log('Added key.'); + } + + async removeSharedKey() { + const key = this.config.str(0); + const account = this.config.str('account'); + + await this.wallet.removeSharedKey(account, key); + + this.log('Removed key.'); + } + + async getSharedKeys() { + const acct = this.config.str([0, 'account']); + const account = await this.wallet.getAccount(acct); + + if (!account) { + this.log('Account not found.'); + return; + } + + this.log(account.keys); + } + + async getAccount() { + const acct = this.config.str([0, 'account']); + const account = await this.wallet.getAccount(acct); + + this.log(account); + } + + async createAccount() { + const name = this.config.str([0, 'name']); + + const options = { + type: this.config.str('type'), + m: this.config.uint('m'), + n: this.config.uint('n'), + witness: this.config.bool('witness'), + accountKey: this.config.str('key'), + lookahead: this.config.uint('lookahead') + }; + + const account = await this.wallet.createAccount(name, options); + + this.log(account); + } + + async createAddress() { + const account = this.config.str([0, 'account']); + const addr = await this.wallet.createAddress(account); + + this.log(addr); + } + + async createChange() { + const account = this.config.str([0, 'account']); + const addr = await this.wallet.createChange(account); + + this.log(addr); + } + + async getAccounts() { + const accounts = await this.wallet.getAccounts(); + this.log(accounts); + } + + async getWallet() { + const info = await this.wallet.getInfo(); + this.log(info); + } + + async getWalletHistory() { + const account = this.config.str('account'); + const txs = await this.wallet.getHistory(account); + + this.log(txs); + } + + async getWalletPending() { + const account = this.config.str('account'); + const txs = await this.wallet.getPending(account); + + this.log(txs); + } + + async getWalletCoins() { + const account = this.config.str('account'); + const coins = await this.wallet.getCoins(account); + + this.log(coins); + } + + async listenWallet() { + await this.client.open(); + await this.wallet.open(); + + this.wallet.on('tx', (details) => { + this.log('TX:'); + this.log(details); + }); + + this.wallet.on('confirmed', (details) => { + this.log('TX confirmed:'); + this.log(details); + }); + + this.wallet.on('unconfirmed', (details) => { + this.log('TX unconfirmed:'); + this.log(details); + }); + + this.wallet.on('conflict', (details) => { + this.log('TX conflict:'); + this.log(details); + }); + + this.wallet.on('address', (receive) => { + this.log('New addresses allocated:'); + this.log(receive); + }); + + this.wallet.on('balance', (balance) => { + this.log('Balance:'); + this.log(balance); + }); + + return new Promise((resolve, reject) => { + this.client.once('disconnect', resolve); + }); + } + + async getBalance() { + const account = this.config.str('account'); + const balance = await this.wallet.getBalance(account); + + this.log(balance); + } + + async getMempool() { + const txs = await this.wallet.getMempool(); + + this.log(txs); + } + + async sendTX() { + const outputs = []; + + if (this.config.has('script')) { + outputs.push({ + script: this.config.str('script'), + value: this.config.ufixed([0, 'value'], EXP) + }); + } else { + outputs.push({ + address: this.config.str([0, 'address']), + value: this.config.ufixed([1, 'value'], EXP) + }); + } + + const options = { + account: this.config.str('account'), + passphrase: this.config.str('passphrase'), + outputs: outputs, + smart: this.config.bool('smart'), + rate: this.config.ufixed('rate', EXP), + subtractFee: this.config.bool('subtract-fee') + }; + + const tx = await this.wallet.send(options); + + this.log(tx); + } + + async createAuctionTxs() { + const options = { + name: this.config.str([0, 'name']), + bid: this.config.ufixed([1, 'bid'], EXP), + lockup: this.config.ufixed([2, 'lockup'], EXP), + broadcastBid: this.config.bool([3, 'broadcastBid']), + passphrase: this.config.str('passphrase') + }; + + const txs = await this.wallet.createAuctionTxs(options); + + this.log(txs); + } + + async createTX() { + let output; + + if (this.config.has('script')) { + output = { + script: this.config.str('script'), + value: this.config.ufixed([0, 'value'], EXP) + }; + } else { + output = { + address: this.config.str([0, 'address']), + value: this.config.ufixed([1, 'value'], EXP) + }; + } + + const options = { + account: this.config.str('account'), + passphrase: this.config.str('passphrase'), + outputs: [output], + smart: this.config.bool('smart'), + rate: this.config.ufixed('rate', EXP), + subtractFee: this.config.bool('subtract-fee') + }; + + const tx = await this.wallet.createTX(options); + + this.log(tx); + } + + async signTX() { + const passphrase = this.config.str('passphrase'); + const tx = this.config.str([0, 'tx']); + const signedTx = await this.wallet.sign({tx, passphrase}); + + this.log(signedTx); + } + + async zapWallet() { + const age = this.config.uint([0, 'age'], 72 * 60 * 60); + const account = this.config.str('account'); + + await this.wallet.zap(account, age); + + this.log('Zapped!'); + } + + async abandonTX() { + const hash = this.config.str(0); + + await this.wallet.abandon(hash); + + this.log('Abandoned tx: ' + hash); + } + + async viewTX() { + const raw = this.config.str([0, 'tx']); + const tx = await this.wallet.fill(raw); + + this.log(tx); + } + + async getDetails() { + const hash = this.config.str(0); + const details = await this.wallet.getTX(hash); + + this.log(details); + } + + async getWalletBlocks() { + const blocks = await this.wallet.getBlocks(); + this.log(blocks); + } + + async getWalletBlock() { + const height = this.config.uint(0); + const block = await this.wallet.getBlock(height); + + this.log(block); + } + + async retoken() { + const passphrase = this.config.str('passphrase'); + const result = await this.wallet.retoken(passphrase); + + this.log(result); + } + + async rescan() { + const height = this.config.uint(0); + + await this.client.rescan(height); + + this.log('Rescanning...'); + } + + async resend() { + await this.client.resend(); + + this.log('Resending...'); + } + + async resendWallet() { + await this.wallet.resend(); + + this.log('Resending...'); + } + + async backup() { + const path = this.config.str(0); + + await this.client.backup(path); + + this.log('Backup complete.'); + } + + async importKey() { + const key = this.config.str(0); + const account = this.config.str('account'); + const passphrase = this.config.str('passphrase'); + + if (!key) + throw new Error('No key for import.'); + + if (key.length === 66 || key.length === 130) { + await this.wallet.importPublic(account, key); + this.log('Imported public key.'); + return; + } + + await this.wallet.importPrivate(account, key, passphrase); + + this.log('Imported private key.'); + } + + async importAddress() { + const address = this.config.str(0); + const account = this.config.str('account'); + + await this.wallet.importAddress(account, address); + + this.log('Imported address.'); + } + + async lock() { + await this.wallet.lock(); + + this.log('Locked.'); + } + + async unlock() { + const passphrase = this.config.str(0); + const timeout = this.config.uint(1); + + await this.wallet.unlock(passphrase, timeout); + + this.log('Unlocked.'); + } + + async rpc() { + const method = this.argv.shift(); + if (!method) { + this.log('Missing RPC method'); + return; + } + const params = []; + + for (const arg of this.argv) { + let param; + try { + param = JSON.parse(arg); + } catch (e) { + param = arg; + } + params.push(param); + } + + let result; + try { + result = await this.client.execute(method, params); + } catch (e) { + if (e.type === 'RPCError') { + this.log(e.message); + return; + } + throw e; + } + + this.log(result); + } + + async handleWallet() { + switch (this.argv.shift()) { + case 'abandon': + await this.abandonTX(); + break; + case 'account': + if (this.argv[0] === 'list') { + this.argv.shift(); + await this.getAccounts(); + break; + } + if (this.argv[0] === 'create') { + this.argv.shift(); + await this.createAccount(); + break; + } + if (this.argv[0] === 'get') + this.argv.shift(); + await this.getAccount(); + break; + case 'address': + await this.createAddress(); + break; + case 'backup': + await this.backup(); + break; + case 'balance': + await this.getBalance(); + break; + case 'block': + await this.getWalletBlock(); + break; + case 'blocks': + await this.getWalletBlocks(); + break; + case 'change': + await this.createChange(); + break; + case 'coins': + await this.getWalletCoins(); + break; + case 'dump': + await this.getWIF(); + break; + case 'get': + await this.getWallet(); + break; + case 'help': + process.stdout.write(HELP + '\n'); + break; + case 'history': + await this.getWalletHistory(); + break; + case 'import': + await this.importKey(); + break; + case 'key': + await this.getKey(); + break; + case 'listen': + await this.listenWallet(); + break; + case 'lock': + await this.lock(); + break; + case 'master': + await this.getMaster(); + break; + case 'mkauctiontxs': + await this.createAuctionTxs(); + break; + case 'mktx': + await this.createTX(); + break; + case 'mkwallet': + await this.createWallet(); + break; + case 'pending': + await this.getWalletPending(); + break; + case 'rescan': + await this.rescan(); + break; + case 'resend': + await this.resend(); + break; + case 'resendwallet': + await this.resendWallet(); + break; + case 'retoken': + await this.retoken(); + break; + case 'rpc': + await this.rpc(); + break; + case 'send': + await this.sendTX(); + break; + case 'shared': + if (this.argv[0] === 'add') { + this.argv.shift(); + await this.addSharedKey(); + break; + } + if (this.argv[0] === 'remove') { + this.argv.shift(); + await this.removeSharedKey(); + break; + } + if (this.argv[0] === 'list') + this.argv.shift(); + await this.getSharedKeys(); + break; + case 'sign': + await this.signTX(); + break; + case 'tx': + await this.getDetails(); + break; + case 'unlock': + await this.unlock(); + break; + case 'view': + await this.viewTX(); + break; + case 'wallets': + await this.getWallets(); + break; + case 'watch': + await this.importAddress(); + break; + case 'zap': + await this.zapWallet(); + break; + default: + process.stdout.write('Unrecognized command.\n'); + process.stdout.write(HELP + '\n'); + break; + } + } + + async destroy() { + if (this.client.opened) + await this.client.close(); + } +} + +(async () => { + const cli = new CLI(); + await cli.handleWallet(); + await cli.destroy(); +})().catch((err) => { + console.error(err.stack); + process.exit(1); +}); diff --git a/bin/hsw-rpc b/bin/hsw-rpc new file mode 100755 index 00000000..4e06573a --- /dev/null +++ b/bin/hsw-rpc @@ -0,0 +1,23 @@ +#!/bin/sh + +# NOTE: This is part of generated `hs-client`. + +rl=0 + +if ! type perl > /dev/null 2>& 1; then + if uname | grep -i 'darwin' > /dev/null; then + echo 'hsw-rpc requires perl to start on OSX.' >& 2 + exit 1 + fi + rl=1 +fi + +if test $rl -eq 1; then + file=$(readlink -f "$0") +else + file=$(perl -MCwd -e "print Cwd::realpath('$0')") +fi + +dir=$(dirname "$file") + +exec "${dir}/hsw-cli" rpc "$@" diff --git a/docs/release-files.md b/docs/release-files.md index a98b74d1..e1e2ba6c 100644 --- a/docs/release-files.md +++ b/docs/release-files.md @@ -1,29 +1,32 @@ -Releasing hsd -============= +Releasing hsd and hs-client +=========================== This document contains information about bundling, signing and distributing the files. -`hsd` is distributed through several platforms: `github`, `npm`, `brew`. +`hsd/hs-client` is distributed through several platforms: `github`, `npm`, `brew`. -- [Deploying to github (tag)](#deploying-to-github-tag) - * [Major, minor and patches](#major-minor-and-patches) - + [Major](#major) - + [Minor, Patch](#minor-patch) -- [Deploying to npm](#deploying-to-npm) - * [Deploying latest version, minor and patches included](#deploying-latest-version-minor-and-patches-included) - * [Deploying support versions (previous and life-support)](#deploying-support-versions-previous-and-life-support) -- [Deploying to homebrew](#deploying-to-homebrew) -- [Deploying to handshake.org](#deploying-to-handshakeorg) - * [Building tarball](#building-tarball) - * [Signing and upload](#signing-and-upload) +- [hsd](#hsd) + * [Deploying to github (tag)](#deploying-to-github-tag) + + [Major, minor and patches](#major-minor-and-patches) + - [Major](#major) + - [Minor, Patch](#minor-patch) + * [Deploying to npm](#deploying-to-npm) + + [Deploying latest version, minor and patches included](#deploying-latest-version-minor-and-patches-included) + + [Deploying support versions (previous and life-support)](#deploying-support-versions-previous-and-life-support) + * [Deploying to homebrew](#deploying-to-homebrew) + * [Deploying to handshake.org](#deploying-to-handshakeorg) + + [Building tarball](#building-tarball) + + [Signing and upload](#signing-and-upload) +- [hs-client](#hs-client) +# hsd ## Deploying to github (tag) This does not need many additional actions as we use github as our primary @@ -119,6 +122,33 @@ and create PR with the relevant updates to the `download/index.html` and - Update `download/index.html` with new links. - Create PR to the main repository. +# hs-client + Since hsd v5 `hs-client` is part of the `hsd`. Original [hs-client repo][hsclient] is now used to +publish generated content. `hs-client` version will now be strictly tied to +the `hsd` version. It is then generated from `hsd` code to release separately on +`git` and `npm`. Most of the process is done by the introduced helper script +`scripts/gen-hsclient.js`. It can help you setup `hs-client` that just needs +publishing on `git` and `npm`. It also gives instructions how to do both. + After `hsd` has been released we can also release `hs-client` from the same +commit/tag, just run: `./scripts/gen-hsclient.js` which will generate `hs-client` +package with `git` setup in `tmp` directory. You can alternatively pass +`HS_CLIENT_DIR` env variable for custom place. If generating git failed for some +reason, it will list commands that needs executing and you can proceed manually +or fix the issues and rerun the script. NOTE, that the script will never try to +publish by itself, only generate files to review locally. + - `./scripts/gen-hsclient.js` - script will also list left commands that are + necessary for publishing. + - `cd /tmp/hs-client` + - `git push -f origin master` - rewrite whole `hs-client` repo with the new content. + - `git push -f origin vVersion` - push newly generated tag to the `hs-client`. + - You can check the `gen-hsclient` output for the proper version or + - `git tag -l` to list. + - `npm publish` - this will also tag it as `latest`. If you want to tag it differently + you can do so, same as above hsd `npm publish`. + - NOTE: You can use `npm publish --dry-run` to see the details before actual + release. + + [homebrew]: https://brew.sh/ [homebrew-repo]: https://github.com/Homebrew/homebrew-core [homebrew-new-formula]: https://github.com/Homebrew/homebrew-core/pull/51014 @@ -126,3 +156,4 @@ and create PR with the relevant updates to the `download/index.html` and [homebrew-guidelines]: https://github.com/Homebrew/homebrew-core/blob/master/CONTRIBUTING.md [handshake-web]: https://github.com/handshake-org/handshake-web/ [bpkg]: https://github.com/chjj/bpkg +[hsclient]: https://github.com/handshake-org/hs-client diff --git a/lib/client/index.js b/lib/client/index.js new file mode 100644 index 00000000..d1b09377 --- /dev/null +++ b/lib/client/index.js @@ -0,0 +1,16 @@ +/*! + * client/index.js - http clients for hs + * Copyright (c) 2017, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + +'use strict'; + +// NOTE: This is part of generated `hs-client`. + +/** + * @module client + */ + +exports.NodeClient = require('./node'); +exports.WalletClient = require('./wallet'); diff --git a/lib/client/node.js b/lib/client/node.js new file mode 100644 index 00000000..3d0bca6c --- /dev/null +++ b/lib/client/node.js @@ -0,0 +1,343 @@ +/*! + * client.js - http client for wallets + * Copyright (c) 2017, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + +'use strict'; + +// NOTE: This is part of generated `hs-client`. +// Don't introduce any unnecessary dependencies to this. + +const assert = require('bsert'); +const {Client} = require('bcurl'); + +/** + * Node Client + * @alias module:client.NodeClient + * @extends {bcurl.Client} + */ + +class NodeClient extends Client { + /** + * Creat a node client. + * @param {Object?} options + */ + + constructor(options) { + super(options); + } + + /** + * Auth with server. + * @returns {Promise} + */ + + async auth() { + await this.call('auth', this.password); + await this.watchChain(); + await this.watchMempool(); + } + + /** + * Make an RPC call. + * @returns {Promise} + */ + + execute(name, params) { + return super.execute('/', name, params); + } + + /** + * Get a mempool snapshot. + * @returns {Promise} + */ + + getMempool() { + return this.get('/mempool'); + } + + /** + * Get some info about the server (network and version). + * @returns {Promise} + */ + + getInfo() { + return this.get('/'); + } + + /** + * Get coins that pertain to an address from the mempool or chain database. + * Takes into account spent coins in the mempool. + * @param {String} address + * @returns {Promise} + */ + + getCoinsByAddress(address) { + assert(typeof address === 'string'); + return this.get(`/coin/address/${address}`); + } + + /** + * Get coins that pertain to addresses from the mempool or chain database. + * Takes into account spent coins in the mempool. + * @param {String[]} addresses + * @returns {Promise} + */ + + getCoinsByAddresses(addresses) { + assert(Array.isArray(addresses)); + return this.post('/coin/address', { addresses }); + } + + /** + * Retrieve a coin from the mempool or chain database. + * Takes into account spent coins in the mempool. + * @param {Hash} hash + * @param {Number} index + * @returns {Promise} + */ + + getCoin(hash, index) { + assert(typeof hash === 'string'); + assert((index >>> 0) === index); + return this.get(`/coin/${hash}/${index}`); + } + + /** + * Retrieve transactions pertaining to an + * address from the mempool or chain database. + * @param {String} address + * @returns {Promise} + */ + + getTXByAddress(address) { + assert(typeof address === 'string'); + return this.get(`/tx/address/${address}`); + } + + /** + * Retrieve transactions pertaining to + * addresses from the mempool or chain database. + * @param {String[]} addresses + * @returns {Promise} + */ + + getTXByAddresses(addresses) { + assert(Array.isArray(addresses)); + return this.post('/tx/address', { addresses }); + } + + /** + * Retrieve a transaction from the mempool or chain database. + * @param {Hash} hash + * @returns {Promise} + */ + + getTX(hash) { + assert(typeof hash === 'string'); + return this.get(`/tx/${hash}`); + } + + /** + * Retrieve a block from the chain database. + * @param {Hash|Number} block + * @returns {Promise} + */ + + getBlock(block) { + assert(typeof block === 'string' || typeof block === 'number'); + return this.get(`/block/${block}`); + } + + /** + * Retrieve a block header. + * @param {Hash|Number} block + * @returns {Promise} + */ + + getBlockHeader(block) { + assert(typeof block === 'string' || typeof block === 'number'); + return this.get(`/header/${block}`); + } + + /** + * Add a transaction to the mempool and broadcast it. + * @param {TX} tx + * @returns {Promise} + */ + + broadcast(tx) { + assert(typeof tx === 'string'); + return this.post('/broadcast', { tx }); + } + + /** + * Add a claim to the mempool and broadcast it. + * @param {Claim} claim + * @returns {Promise} + */ + + broadcastClaim(claim) { + assert(typeof claim === 'string'); + return this.post('/claim', { claim }); + } + + /** + * Reset the chain. + * @param {Number} height + * @returns {Promise} + */ + + reset(height) { + return this.post('/reset', { height }); + } + + /** + * Watch the blockchain. + * @private + * @returns {Promise} + */ + + watchChain() { + return this.call('watch chain'); + } + + /** + * Watch the blockchain. + * @private + * @returns {Promise} + */ + + watchMempool() { + return this.call('watch mempool'); + } + + /** + * Get chain tip. + * @returns {Promise} + */ + + getTip() { + return this.call('get tip'); + } + + /** + * Get chain entry. + * @param {Hash} hash + * @returns {Promise} + */ + + getEntry(block) { + return this.call('get entry', block); + } + + /** + * Get hashes. + * @param {Number} [start=-1] + * @param {Number} [end=-1] + * @returns {Promise} + */ + + getHashes(start, end) { + return this.call('get hashes', start, end); + } + + /** + * Send a transaction. Do not wait for promise. + * @param {TX} tx + * @returns {Promise} + */ + + send(tx) { + assert(Buffer.isBuffer(tx)); + return this.call('send', tx); + } + + /** + * Send a claim. Do not wait for promise. + * @param {Claim} claim + * @returns {Promise} + */ + + sendClaim(claim) { + assert(Buffer.isBuffer(claim)); + return this.call('send claim', claim); + } + + /** + * Get name state. + * @param {Buffer} nameHash + * @returns {Promise} + */ + + getNameStatus(nameHash) { + assert(Buffer.isBuffer(nameHash)); + return this.call('get name', nameHash); + } + + /** + * Set bloom filter. + * @param {Bloom} filter + * @returns {Promise} + */ + + setFilter(filter) { + assert(Buffer.isBuffer(filter)); + return this.call('set filter', filter); + } + + /** + * Add data to filter. + * @param {Buffer} data + * @returns {Promise} + */ + + addFilter(chunks) { + if (!Array.isArray(chunks)) + chunks = [chunks]; + + return this.call('add filter', chunks); + } + + /** + * Reset filter. + * @returns {Promise} + */ + + resetFilter() { + return this.call('reset filter'); + } + + /** + * Esimate smart fee. + * @param {Number?} blocks + * @returns {Promise} + */ + + estimateFee(blocks) { + assert(blocks == null || typeof blocks === 'number'); + return this.call('estimate fee', blocks); + } + + /** + * Rescan for any missed transactions. + * @param {Number|Hash} start - Start block. + * @returns {Promise} + */ + + rescan(start) { + if (start == null) + start = 0; + + assert(typeof start === 'number' || Buffer.isBuffer(start)); + + return this.call('rescan', start); + } +} + +/* + * Expose + */ + +module.exports = NodeClient; diff --git a/lib/client/wallet.js b/lib/client/wallet.js new file mode 100644 index 00000000..0a9bc7b8 --- /dev/null +++ b/lib/client/wallet.js @@ -0,0 +1,1561 @@ +/*! + * wallet.js - http wallet for bcoin + * Copyright (c) 2017, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + +'use strict'; + +// NOTE: This is part of generated `hs-client`. +// Don't introduce any unnecessary dependencies to this. + +const assert = require('bsert'); +const EventEmitter = require('events'); +const {Client} = require('bcurl'); + +/** + * Wallet Client + * @alias module:client.WalletClient + * @extends {bcurl.Client} + */ + +class WalletClient extends Client { + /** + * Create a wallet client. + * @param {Object?} options + */ + + constructor(options) { + super(options); + this.wallets = new Map(); + } + + /** + * Open the client. + * @private + * @returns {Promise} + */ + + init() { + this.bind('tx', (id, details) => { + this.dispatch(id, 'tx', details); + }); + + this.bind('confirmed', (id, details) => { + this.dispatch(id, 'confirmed', details); + }); + + this.bind('unconfirmed', (id, details) => { + this.dispatch(id, 'unconfirmed', details); + }); + + this.bind('conflict', (id, details) => { + this.dispatch(id, 'conflict', details); + }); + + this.bind('updated', (id, details) => { + this.dispatch(id, 'updated', details); + }); + + this.bind('address', (id, receive) => { + this.dispatch(id, 'address', receive); + }); + + this.bind('balance', (id, balance) => { + this.dispatch(id, 'balance', balance); + }); + } + + /** + * Dispatch event. + * @private + */ + + dispatch(id, event, ...args) { + const wallet = this.wallets.get(id); + + if (wallet) + wallet.emit(event, ...args); + } + + /** + * Open the client. + * @returns {Promise} + */ + + async open() { + await super.open(); + this.init(); + } + + /** + * Close the client. + * @returns {Promise} + */ + + async close() { + await super.close(); + this.wallets = new Map(); + } + + /** + * Auth with server. + * @returns {Promise} + */ + + async auth() { + await this.call('auth', this.password); + } + + /** + * Make an RPC call. + * @returns {Promise} + */ + + execute(name, params) { + return super.execute('/', name, params); + } + + /** + * Create a wallet object. + */ + + wallet(id, token) { + return new Wallet(this, id, token); + } + + /** + * Join a wallet. + */ + + all(token) { + return this.call('join', '*', token); + } + + /** + * Leave a wallet. + */ + + none() { + return this.call('leave', '*'); + } + + /** + * Join a wallet. + */ + + join(id, token) { + return this.call('join', id, token); + } + + /** + * Leave a wallet. + */ + + leave(id) { + return this.call('leave', id); + } + + /** + * Rescan the chain. + * @param {Number} height + * @returns {Promise} + */ + + rescan(height) { + return this.post('/rescan', { height }); + } + + /** + * Resend pending transactions. + * @returns {Promise} + */ + + resend() { + return this.post('/resend'); + } + + /** + * Backup the walletdb. + * @param {String} path + * @returns {Promise} + */ + + backup(path) { + return this.post('/backup', { path }); + } + + /** + * Get list of all wallet IDs. + * @returns {Promise} + */ + + getWallets() { + return this.get('/wallet'); + } + + /** + * Create a wallet. + * @param {Object} options + * @returns {Promise} + */ + + createWallet(id, options) { + if (id == null) + throw new Error('Wallet id is required.'); + + return this.put(`/wallet/${id}`, options); + } + + /** + * Get wallet transaction history. + * @param {String} account + * @returns {Promise} + */ + + getHistory(id, account) { + return this.get(`/wallet/${id}/tx/history`, { account }); + } + + /** + * Get wallet coins. + * @param {String} account + * @returns {Promise} + */ + + getCoins(id, account) { + return this.get(`/wallet/${id}/coin`, { account }); + } + + /** + * Get all unconfirmed transactions. + * @param {String} account + * @returns {Promise} + */ + + getPending(id, account) { + return this.get(`/wallet/${id}/tx/unconfirmed`, { account }); + } + + /** + * Calculate wallet balance. + * @param {String} account + * @returns {Promise} + */ + + getBalance(id, account) { + return this.get(`/wallet/${id}/balance`, { account }); + } + + /** + * Get last N wallet transactions. + * @param {String} account + * @param {Number} limit - Max number of transactions. + * @returns {Promise} + */ + + getLast(id, account, limit) { + return this.get(`/wallet/${id}/tx/last`, { account, limit }); + } + + /** + * Get wallet transactions by timestamp range. + * @param {String} account + * @param {Object} options + * @param {Number} options.start - Start time. + * @param {Number} options.end - End time. + * @param {Number?} options.limit - Max number of records. + * @param {Boolean?} options.reverse - Reverse order. + * @returns {Promise} + */ + + getRange(id, account, options) { + return this.get(`/wallet/${id}/tx/range`, { + account: account, + start: options.start, + end: options.end, + limit: options.limit, + reverse: options.reverse + }); + } + + /** + * Get transaction (only possible if the transaction + * is available in the wallet history). + * @param {Hash} hash + * @returns {Promise} + */ + + getTX(id, hash) { + return this.get(`/wallet/${id}/tx/${hash}`); + } + + /** + * Get wallet blocks. + * @param {Number} height + * @returns {Promise} + */ + + getBlocks(id) { + return this.get(`/wallet/${id}/block`); + } + + /** + * Get wallet block. + * @param {Number} height + * @returns {Promise} + */ + + getBlock(id, height) { + return this.get(`/wallet/${id}/block/${height}`); + } + + /** + * Get unspent coin (only possible if the transaction + * is available in the wallet history). + * @param {Hash} hash + * @param {Number} index + * @returns {Promise} + */ + + getCoin(id, hash, index) { + return this.get(`/wallet/${id}/coin/${hash}/${index}`); + } + + /** + * Get name state for the given name. + * {@see hsd.NameState} + * @param {String} id + * @param {String} name + * @returns {Promise} + */ + + getName(id, name) { + return this.get(`/wallet/${id}/name/${name}`); + } + + /** + * Get name state for all names + * that the wallet is managing. + * {@see hsd.NameState} + * @param {String} id + * @returns {Promise} + */ + + getNames(id) { + return this.get(`/wallet/${id}/name`); + } + + /** + * Get bids, reveals and name state + * for the given name. + * {@see hsd.NameState} + * {@see hsd.BlindBid} + * {@see hsd.BidReveal} + * @param {String} id + * @param {String} name + * @returns {Promise} + */ + + getAuctionByName(id, name) { + return this.get(`/wallet/${id}/auction/${name}`); + } + + /** + * Get bids, reveals and name state + * for all names the wallet manages. + * {@see hsd.NameState} + * {@see hsd.BlindBid} + * {@see hsd.BidReveal} + * @param {String} id + * @param {Object} options + * @returns {Promise} + */ + + getAuctions(id, options) { + return this.get(`/wallet/${id}/auction`, options); + } + + /** + * Get bids for a given name. + * {@see hsd.BlindBid} + * @param {String} id + * @param {String?} name + * @param {Object?} options + * @param {Boolean?} options.own + * @returns {Promise} + */ + + getBidsByName(id, name, options) { + return this.get(`/wallet/${id}/bid/${name}`, options); + } + + /** + * Get bids for all names. + * the wallet manages. + * {@see hsd.BlindBid} + * @param {String} id + * @param {Object?} options + * @param {Boolean?} options.own + * @returns {Promise} + */ + + getBids(id, options) { + return this.get(`/wallet/${id}/bid`, options); + } + + /** + * Get wallet reveal for a given name. + * {@see hsd.BidReveal} + * @param {String} id + * @param {String?} name + * @param {Object?} options + * @param {Boolean?} options.own + * @returns {Promise} + */ + + getRevealsByName(id, name, options) { + return this.get(`/wallet/${id}/reveal/${name}`, options); + } + + /** + * Get wallet reveals for all names + * the wallet manages. + * {@see hsd.BidReveal} + * @param {String} id + * @param {Object?} options + * @param {Boolean?} options.own + * @returns {Promise} + */ + + getReveals(id, options) { + return this.get(`/wallet/${id}/reveal`, options); + } + + /** + * Get name resource. + * {@see hsd.Resource} + * @param {String} id + * @param {String} name + * @returns {Promise} + */ + + getResource(id, name) { + return this.get(`/wallet/${id}/resource/${name}`); + } + + /* + * Deterministically regenerate a bid's nonce. + * @param {String} id + * @param {String} name + * @param {Object} options + * @param {String} options.address + * @param {Number} options.bid + * @returns {Promise} + */ + + getNonce(id, name, options) { + return this.get(`/wallet/${id}/nonce/${name}`, options); + } + + /** + * @param {Number} now - Current time. + * @param {Number} age - Age delta. + * @returns {Promise} + */ + + zap(id, account, age) { + return this.post(`/wallet/${id}/zap`, { account, age }); + } + + /** + * @param {Number} id + * @param {Hash} hash + * @returns {Promise} + */ + + abandon(id, hash) { + return this.del(`/wallet/${id}/tx/${hash}`); + } + + /** + * Create a transaction, fill. + * @param {Object} options + * @returns {Promise} + */ + + createTX(id, options) { + return this.post(`/wallet/${id}/create`, options); + } + + /** + * Create pre-signed bid and reveal txs, + * fill, and optionally sign and broadcast. + * @param {Object} options + * @param {String} options.name + * @param {Number} options.bid + * @param {Number} options.lockup + * @param {String} options.passphrase + * @param {Boolean} options.sign + * @param {Boolean} options.broadcastBid + * @returns {Promise} + */ + + createAuctionTxs(id, options) { + return this.post(`/wallet/${id}/auction`, options); + } + + /** + * Create a transaction, fill, sign, and broadcast. + * @param {Object} options + * @param {String} options.address + * @param {Amount} options.value + * @returns {Promise} + */ + + send(id, options) { + return this.post(`/wallet/${id}/send`, options); + } + + /** + * Create open transaction. + * @param {String} id + * @param {Object} options + * @returns {Promise} + */ + + createOpen(id, options) { + return this.post(`/wallet/${id}/open`, options); + } + + /** + * Create bid transaction. + * @param {String} id + * @param {Object} options + * @returns {Promise} + */ + + createBid(id, options) { + return this.post(`/wallet/${id}/bid`, options); + } + + /** + * Create reveal transaction. + * @param {String} id + * @param {Object} options + * @returns {Promise} + */ + + createReveal(id, options) { + return this.post(`/wallet/${id}/reveal`, options); + } + + /** + * Create redeem transaction. + * @param {String} id + * @param {Object} options + * @returns {Promise} + */ + + createRedeem(id, options) { + return this.post(`/wallet/${id}/redeem`, options); + } + + /** + * Create update transaction. + * @param {String} id + * @param {Object} options + * @returns {Promise} + */ + + createUpdate(id, options) { + return this.post(`/wallet/${id}/update`, options); + } + + /** + * Create renewal transaction. + * @param {String} id + * @param {Object} options + * @returns {Promise} + */ + + createRenewal(id, options) { + return this.post(`/wallet/${id}/renewal`, options); + } + + /** + * Create transfer transaction. + * @param {String} id + * @param {Object} options + * @returns {Promise} + */ + + createTransfer(id, options) { + return this.post(`/wallet/${id}/transfer`, options); + } + + /** + * Create cancel transaction. + * @param {String} id + * @param {Object} options + * @returns {Promise} + */ + + createCancel(id, options) { + return this.post(`/wallet/${id}/cancel`, options); + } + + /** + * Create finalize transaction. + * @param {String} id + * @param {Object} options + * @returns {Promise} + */ + + createFinalize(id, options) { + return this.post(`/wallet/${id}/finalize`, options); + } + + /** + * Create revoke transaction. + * @param {String} id + * @param {Object} options + * @returns {Promise} + */ + + createRevoke(id, options) { + return this.post(`/wallet/${id}/revoke`, options); + } + + /** + * Sign a transaction. + * @param {Object} options + * @returns {Promise} + */ + + sign(id, options) { + return this.post(`/wallet/${id}/sign`, options); + } + + /** + * Get the raw wallet JSON. + * @returns {Promise} + */ + + getInfo(id) { + return this.get(`/wallet/${id}`); + } + + /** + * Get wallet accounts. + * @returns {Promise} - Returns Array. + */ + + getAccounts(id) { + return this.get(`/wallet/${id}/account`); + } + + /** + * Get wallet master key. + * @returns {Promise} + */ + + getMaster(id) { + return this.get(`/wallet/${id}/master`); + } + + /** + * Get wallet account. + * @param {String} account + * @returns {Promise} + */ + + getAccount(id, account) { + return this.get(`/wallet/${id}/account/${account}`); + } + + /** + * Create account. + * @param {String} name + * @param {Object} options + * @returns {Promise} + */ + + createAccount(id, name, options) { + return this.put(`/wallet/${id}/account/${name}`, options); + } + + /** + * Create address. + * @param {Object} options + * @returns {Promise} + */ + + createAddress(id, account) { + return this.post(`/wallet/${id}/address`, { account }); + } + + /** + * Create change address. + * @param {Object} options + * @returns {Promise} + */ + + createChange(id, account) { + return this.post(`/wallet/${id}/change`, { account }); + } + + /** + * Change or set master key`s passphrase. + * @param {String|Buffer} passphrase + * @param {(String|Buffer)?} old + * @returns {Promise} + */ + + setPassphrase(id, passphrase, old) { + return this.post(`/wallet/${id}/passphrase`, { passphrase, old }); + } + + /** + * Generate a new token. + * @param {(String|Buffer)?} passphrase + * @returns {Promise} + */ + + retoken(id, passphrase) { + return this.post(`/wallet/${id}/retoken`, { + passphrase + }); + } + + /** + * Import private key. + * @param {Number|String} account + * @param {String} key + * @returns {Promise} + */ + + importPrivate(id, account, privateKey, passphrase) { + return this.post(`/wallet/${id}/import`, { + account, + privateKey, + passphrase + }); + } + + /** + * Import public key. + * @param {Number|String} account + * @param {String} key + * @returns {Promise} + */ + + importPublic(id, account, publicKey) { + return this.post(`/wallet/${id}/import`, { + account, + publicKey + }); + } + + /** + * Import address. + * @param {Number|String} account + * @param {String} address + * @returns {Promise} + */ + + importAddress(id, account, address) { + return this.post(`/wallet/${id}/import`, { account, address }); + } + + /** + * Lock a coin. + * @param {String} hash + * @param {Number} index + * @returns {Promise} + */ + + lockCoin(id, hash, index) { + return this.put(`/wallet/${id}/locked/${hash}/${index}`); + } + + /** + * Unlock a coin. + * @param {String} hash + * @param {Number} index + * @returns {Promise} + */ + + unlockCoin(id, hash, index) { + return this.del(`/wallet/${id}/locked/${hash}/${index}`); + } + + /** + * Get locked coins. + * @returns {Promise} + */ + + getLocked(id) { + return this.get(`/wallet/${id}/locked`); + } + + /** + * Lock wallet. + * @returns {Promise} + */ + + lock(id) { + return this.post(`/wallet/${id}/lock`); + } + + /** + * Unlock wallet. + * @param {String} passphrase + * @param {Number} timeout + * @returns {Promise} + */ + + unlock(id, passphrase, timeout) { + return this.post(`/wallet/${id}/unlock`, { passphrase, timeout }); + } + + /** + * Get wallet key. + * @param {String} address + * @returns {Promise} + */ + + getKey(id, address) { + return this.get(`/wallet/${id}/key/${address}`); + } + + /** + * Get wallet key WIF dump. + * @param {String} address + * @param {String?} passphrase + * @returns {Promise} + */ + + getWIF(id, address, passphrase) { + return this.get(`/wallet/${id}/wif/${address}`, { passphrase }); + } + + /** + * Add a public account key to the wallet for multisig. + * @param {String} account + * @param {String} key - Account (bip44) key (base58). + * @returns {Promise} + */ + + addSharedKey(id, account, accountKey) { + return this.put(`/wallet/${id}/shared-key`, { account, accountKey }); + } + + /** + * Remove a public account key to the wallet for multisig. + * @param {String} account + * @param {String} key - Account (bip44) key (base58). + * @returns {Promise} + */ + + removeSharedKey(id, account, accountKey) { + return this.del(`/wallet/${id}/shared-key`, { account, accountKey }); + } + + /** + * Resend wallet transactions. + * @returns {Promise} + */ + + resendWallet(id) { + return this.post(`/wallet/${id}/resend`); + } +} + +/** + * Wallet Instance + * @extends {EventEmitter} + */ + +class Wallet extends EventEmitter { + /** + * Create a wallet client. + * @param {Object?} options + */ + + constructor(parent, id, token) { + super(); + this.parent = parent; + this.client = parent.clone(); + this.client.token = token; + this.id = id; + this.token = token; + } + + /** + * Open wallet. + * @returns {Promise} + */ + + async open() { + await this.parent.join(this.id, this.token); + this.parent.wallets.set(this.id, this); + } + + /** + * Close wallet. + * @returns {Promise} + */ + + async close() { + await this.parent.leave(this.id); + this.parent.wallets.delete(this.id); + } + + /** + * Get wallet transaction history. + * @param {String} account + * @returns {Promise} + */ + + getHistory(account) { + return this.client.getHistory(this.id, account); + } + + /** + * Get wallet coins. + * @param {String} account + * @returns {Promise} + */ + + getCoins(account) { + return this.client.getCoins(this.id, account); + } + + /** + * Get all unconfirmed transactions. + * @param {String} account + * @returns {Promise} + */ + + getPending(account) { + return this.client.getPending(this.id, account); + } + + /** + * Calculate wallet balance. + * @param {String} account + * @returns {Promise} + */ + + getBalance(account) { + return this.client.getBalance(this.id, account); + } + + /** + * Get last N wallet transactions. + * @param {String} account + * @param {Number} limit - Max number of transactions. + * @returns {Promise} + */ + + getLast(account, limit) { + return this.client.getLast(this.id, account, limit); + } + + /** + * Get wallet transactions by timestamp range. + * @param {String} account + * @param {Object} options + * @param {Number} options.start - Start time. + * @param {Number} options.end - End time. + * @param {Number?} options.limit - Max number of records. + * @param {Boolean?} options.reverse - Reverse order. + * @returns {Promise} + */ + + getRange(account, options) { + return this.client.getRange(this.id, account, options); + } + + /** + * Get transaction (only possible if the transaction + * is available in the wallet history). + * @param {Hash} hash + * @returns {Promise} + */ + + getTX(hash) { + return this.client.getTX(this.id, hash); + } + + /** + * Get wallet blocks. + * @param {Number} height + * @returns {Promise} + */ + + getBlocks() { + return this.client.getBlocks(this.id); + } + + /** + * Get wallet block. + * @param {Number} height + * @returns {Promise} + */ + + getBlock(height) { + return this.client.getBlock(this.id, height); + } + + /** + * Get unspent coin (only possible if the transaction + * is available in the wallet history). + * @param {Hash} hash + * @param {Number} index + * @returns {Promise} + */ + + getCoin(hash, index) { + return this.client.getCoin(this.id, hash, index); + } + + /** + * Get name state for the given name. + * {@see hsd.NameState} + * @param {String} name + * @returns {Promise} + */ + + getName(name) { + return this.client.getName(this.id, name); + } + + /** + * Get name state for all names + * that the wallet is managing. + * {@see hsd.NameState} + * @returns {Promise} + */ + + getNames() { + return this.client.getNames(this.id); + } + + /** + * Get bids, reveals and name state + * for the given name. + * {@see hsd.NameState} + * {@see hsd.BlindBid} + * {@see hsd.BidReveal} + * @param {String} name + * @returns {Promise} + */ + + getAuctionByName(name) { + return this.client.getAuctionByName(this.id, name); + } + + /** + * Get bids, reveals and name state + * for all names the wallet manages. + * {@see hsd.NameState} + * {@see hsd.BlindBid} + * {@see hsd.BidReveal} + * @param {Object} options + * @returns {Promise} + */ + + getAuctions(options) { + return this.client.getAuctions(this.id, options); + } + + /** + * Get bids for a given name. + * {@see hsd.BlindBid} + * @param {String?} name + * @param {Object?} options + * @param {Boolean?} options.own + * @returns {Promise} + */ + + getBidsByName(name, options) { + return this.client.getBidsByName(this.id, name, options); + } + + /** + * Get bids for all names. + * the wallet manages. + * {@see hsd.BlindBid} + * @param {Object?} options + * @param {Boolean?} options.own + * @returns {Promise} + */ + + getBids(options) { + return this.client.getBids(this.id, options); + } + + /** + * Get wallet reveal for a given name. + * {@see hsd.BidReveal} + * @param {String?} name + * @param {Object?} options + * @param {Boolean?} options.own + * @returns {Promise} + */ + + getRevealsByName(name, options) { + return this.client.getRevealsByName(this.id, name, options); + } + + /** + * Get wallet reveals for all names + * the wallet manages. + * {@see hsd.BidReveal} + * @param {Object?} options + * @param {Boolean?} options.own + * @returns {Promise} + */ + + getReveals(options) { + return this.client.getReveals(this.id, options); + } + + /** + * Get name resource. + * {@see hsd.Resource} + * @param {String} name + * @returns {Promise} + */ + + getResource(name) { + return this.client.getResource(this.id, name); + } + + /* + * Deterministically regenerate a bid's nonce. + * @param {String} name + * @param {Object} options + * @param {String} options.address + * @param {Number} options.bid + * @returns {Promise} + */ + + getNonce(name, options) { + return this.client.getNonce(this.id, name, options); + } + + /** + * @param {Number} now - Current time. + * @param {Number} age - Age delta. + * @returns {Promise} + */ + + zap(account, age) { + return this.client.zap(this.id, account, age); + } + + /** + * Used to remove a pending transaction from the wallet. + * That is likely the case if it has a policy or low fee + * that prevents it from proper network propagation. + * @param {Hash} hash + * @returns {Promise} + */ + + abandon(hash) { + return this.client.abandon(this.id, hash); + } + + /** + * Create a transaction, fill. + * @param {Object} options + * @returns {Promise} + */ + + createTX(options) { + return this.client.createTX(this.id, options); + } + + /** + * Create pre-signed bid and reveal txs, + * fill, and optionally sign and broadcast. + * @param {Object} options + * @param {String} options.name + * @param {Number} options.bid + * @param {Number} options.lockup + * @param {String} options.passphrase + * @param {Boolean} options.sign + * @param {Boolean} options.broadcastBid + * @returns {Promise} + */ + + createAuctionTxs(options) { + return this.client.createAuctionTxs(this.id, options); + } + + /** + * Create a transaction, fill, sign, and broadcast. + * @param {Object} options + * @param {String} options.address + * @param {Amount} options.value + * @returns {Promise} + */ + + send(options) { + return this.client.send(this.id, options); + } + + /** + * Create open transaction. + * @param {Object} options + * @returns {Promise} + */ + + createOpen(options) { + return this.client.createOpen(this.id, options); + } + + /** + * Create bid transaction. + * @param {Object} options + * @returns {Promise} + */ + + createBid(options) { + return this.client.createBid(this.id, options); + } + + /** + * Create reveal transaction. + * @param {Object} options + * @returns {Promise} + */ + + createReveal(options) { + return this.client.createReveal(this.id, options); + } + + /** + * Create redeem transaction. + * @param {Object} options + * @returns {Promise} + */ + + createRedeem(options) { + return this.client.createRedeem(this.id, options); + } + + /** + * Create update transaction. + * @param {Object} options + * @returns {Promise} + */ + + createUpdate(options) { + return this.client.createUpdate(this.id, options); + } + + /** + * Create renewal transaction. + * @param {Object} options + * @returns {Promise} + */ + + createRenewal(options) { + return this.client.createRenewal(this.id, options); + } + + /** + * Create transfer transaction. + * @param {Object} options + * @returns {Promise} + */ + + createTransfer(options) { + return this.client.createTransfer(this.id, options); + } + + /** + * Create cancel transaction. + * @param {Object} options + * @returns {Promise} + */ + + createCancel(options) { + return this.client.createCancel(this.id, options); + } + + /** + * Create finalize transaction. + * @param {Object} options + * @returns {Promise} + */ + + createFinalize(options) { + return this.client.createFinalize(this.id, options); + } + + /** + * Create revoke transaction. + * @param {Object} options + * @returns {Promise} + */ + + createRevoke(options) { + return this.client.createRevoke(this.id, options); + } + + /** + * Sign a transaction. + * @param {Object} options + * @returns {Promise} + */ + + sign(options) { + return this.client.sign(this.id, options); + } + + /** + * Get the raw wallet JSON. + * @returns {Promise} + */ + + getInfo() { + return this.client.getInfo(this.id); + } + + /** + * Get wallet accounts. + * @returns {Promise} - Returns Array. + */ + + getAccounts() { + return this.client.getAccounts(this.id); + } + + /** + * Get wallet master key. + * @returns {Promise} + */ + + getMaster() { + return this.client.getMaster(this.id); + } + + /** + * Get wallet account. + * @param {String} account + * @returns {Promise} + */ + + getAccount(account) { + return this.client.getAccount(this.id, account); + } + + /** + * Create account. + * @param {String} name + * @param {Object} options + * @returns {Promise} + */ + + createAccount(name, options) { + if (name == null) + throw new Error('Account name is required.'); + + return this.client.createAccount(this.id, name, options); + } + + /** + * Create address. + * @param {Object} options + * @returns {Promise} + */ + + createAddress(account) { + return this.client.createAddress(this.id, account); + } + + /** + * Create change address. + * @param {Object} options + * @returns {Promise} + */ + + createChange(account) { + return this.client.createChange(this.id, account); + } + + /** + * Change or set master key`s passphrase. + * @param {String|Buffer} passphrase + * @param {(String|Buffer)?} old + * @returns {Promise} + */ + + setPassphrase(passphrase, old) { + return this.client.setPassphrase(this.id, passphrase, old); + } + + /** + * Generate a new token. + * @param {(String|Buffer)?} passphrase + * @returns {Promise} + */ + + async retoken(passphrase) { + const result = await this.client.retoken(this.id, passphrase); + + assert(result); + assert(typeof result.token === 'string'); + + this.token = result.token; + + return result; + } + + /** + * Import private key. + * @param {Number|String} account + * @param {String} key + * @returns {Promise} + */ + + importPrivate(account, privateKey, passphrase) { + return this.client.importPrivate(this.id, account, privateKey, passphrase); + } + + /** + * Import public key. + * @param {Number|String} account + * @param {String} key + * @returns {Promise} + */ + + importPublic(account, publicKey) { + return this.client.importPublic(this.id, account, publicKey); + } + + /** + * Import address. + * @param {Number|String} account + * @param {String} address + * @returns {Promise} + */ + + importAddress(account, address) { + return this.client.importAddress(this.id, account, address); + } + + /** + * Lock a coin. + * @param {String} hash + * @param {Number} index + * @returns {Promise} + */ + + lockCoin(hash, index) { + return this.client.lockCoin(this.id, hash, index); + } + + /** + * Unlock a coin. + * @param {String} hash + * @param {Number} index + * @returns {Promise} + */ + + unlockCoin(hash, index) { + return this.client.unlockCoin(this.id, hash, index); + } + + /** + * Get locked coins. + * @returns {Promise} + */ + + getLocked() { + return this.client.getLocked(this.id); + } + + /** + * Lock wallet. + * @returns {Promise} + */ + + lock() { + return this.client.lock(this.id); + } + + /** + * Unlock wallet. + * @param {String} passphrase + * @param {Number} timeout + * @returns {Promise} + */ + + unlock(passphrase, timeout) { + return this.client.unlock(this.id, passphrase, timeout); + } + + /** + * Get wallet key. + * @param {String} address + * @returns {Promise} + */ + + getKey(address) { + return this.client.getKey(this.id, address); + } + + /** + * Get wallet key WIF dump. + * @param {String} address + * @param {String?} passphrase + * @returns {Promise} + */ + + getWIF(address, passphrase) { + return this.client.getWIF(this.id, address, passphrase); + } + + /** + * Add a public account key to the wallet for multisig. + * @param {String} account + * @param {String} key - Account (bip44) key (base58). + * @returns {Promise} + */ + + addSharedKey(account, accountKey) { + return this.client.addSharedKey(this.id, account, accountKey); + } + + /** + * Remove a public account key to the wallet for multisig. + * @param {String} account + * @param {String} key - Account (bip44) key (base58). + * @returns {Promise} + */ + + removeSharedKey(account, accountKey) { + return this.client.removeSharedKey(this.id, account, accountKey); + } + + /** + * Resend wallet transactions. + * @returns {Promise} + */ + + resend() { + return this.client.resendWallet(this.id); + } +} + +/* + * Expose + */ + +module.exports = WalletClient; diff --git a/lib/hsd.js b/lib/hsd.js index e518d326..14abb159 100644 --- a/lib/hsd.js +++ b/lib/hsd.js @@ -56,6 +56,11 @@ hsd.define('blockchain', './blockchain'); hsd.define('Chain', './blockchain/chain'); hsd.define('ChainEntry', './blockchain/chainentry'); +// Client +hsd.define('client', './client'); +hsd.define('WalletClient', './client/wallet'); +hsd.define('NodeClient', './client/node'); + // Coins hsd.define('coins', './coins'); hsd.define('Coins', './coins/coins'); diff --git a/lib/wallet/client.js b/lib/wallet/client.js index c73f14e9..92bb9a9f 100644 --- a/lib/wallet/client.js +++ b/lib/wallet/client.js @@ -7,7 +7,7 @@ 'use strict'; const assert = require('bsert'); -const {NodeClient} = require('hs-client'); +const NodeClient = require('../client/node'); const TX = require('../primitives/tx'); const Coin = require('../primitives/coin'); const NameState = require('../covenants/namestate'); diff --git a/lib/wallet/nodeclient.js b/lib/wallet/nodeclient.js index 7144c307..40594d03 100644 --- a/lib/wallet/nodeclient.js +++ b/lib/wallet/nodeclient.js @@ -175,7 +175,7 @@ class NodeClient extends AsyncEmitter { // `data` is ignored because pool.spvFilter === walletDB.filter // and therefore is already updated. // Argument is kept here to be consistent with API in - // wallet/client.js (hs-client NodeClient) and wallet/nullclient.js + // wallet/client.js (client/node.js) and wallet/nullclient.js this.node.pool.queueFilterLoad(); } diff --git a/package-lock.json b/package-lock.json index 541f4a22..eef13942 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "dependencies": { "bcfg": "~0.1.7", "bcrypto": "~5.4.0", + "bcurl": "^0.2.0", "bdb": "~1.4.0", "bdns": "~0.1.5", "bevent": "~0.1.5", @@ -33,7 +34,6 @@ "bval": "~0.1.6", "bweb": "~0.1.11", "goosig": "~0.10.0", - "hs-client": "~0.0.13", "n64": "~0.2.10", "urkel": "~1.0.2" }, @@ -423,25 +423,6 @@ "node": ">=8.0.0" } }, - "node_modules/hs-client": { - "version": "0.0.13", - "resolved": "https://registry.npmjs.org/hs-client/-/hs-client-0.0.13.tgz", - "integrity": "sha512-3Vm/4S0TDstbOW+OfdTeP2EQ4dolPNqMulTSr31RihwX8cX1DyT4il1Fc9STXXToXTsZuFro2WD/+1m0MWi5Ag==", - "dependencies": { - "bcfg": "~0.1.7", - "bcurl": "~0.2.0", - "bsert": "~0.0.10" - }, - "bin": { - "hsd-cli": "bin/hsd-cli", - "hsd-rpc": "bin/hsd-rpc", - "hsw-cli": "bin/hsw-cli", - "hsw-rpc": "bin/hsw-rpc" - }, - "engines": { - "node": ">=8.0.0" - } - }, "node_modules/loady": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/loady/-/loady-0.0.5.tgz", @@ -754,16 +735,6 @@ "loady": "~0.0.5" } }, - "hs-client": { - "version": "0.0.13", - "resolved": "https://registry.npmjs.org/hs-client/-/hs-client-0.0.13.tgz", - "integrity": "sha512-3Vm/4S0TDstbOW+OfdTeP2EQ4dolPNqMulTSr31RihwX8cX1DyT4il1Fc9STXXToXTsZuFro2WD/+1m0MWi5Ag==", - "requires": { - "bcfg": "~0.1.7", - "bcurl": "~0.2.0", - "bsert": "~0.0.10" - } - }, "loady": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/loady/-/loady-0.0.5.tgz", diff --git a/package.json b/package.json index 7656b074..d9a7d5d1 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "dependencies": { "bcfg": "~0.1.7", "bcrypto": "~5.4.0", + "bcurl": "^0.2.0", "bdb": "~1.4.0", "bdns": "~0.1.5", "bevent": "~0.1.5", @@ -44,7 +45,6 @@ "bval": "~0.1.6", "bweb": "~0.1.11", "goosig": "~0.10.0", - "hs-client": "~0.0.13", "n64": "~0.2.10", "urkel": "~1.0.2" }, diff --git a/scripts/gen-hsclient.js b/scripts/gen-hsclient.js new file mode 100755 index 00000000..35b61e66 --- /dev/null +++ b/scripts/gen-hsclient.js @@ -0,0 +1,200 @@ +#!/usr/bin/env node + +'use strict'; + +const assert = require('assert'); +const path = require('path'); +const fs = require('bfile'); +const os = require('os'); +const util = require('util'); +const cp = require('child_process'); +const exec = util.promisify(cp.exec); + +const ROOT = path.dirname(__dirname); +const HSD_PKG = require(path.join(ROOT, 'package.json')); + +const REMOTE = 'git@github.com:handshake-org/hs-client.git'; + +const INIT_HS_CLIENT_PKG = { + name: "hs-client", + description: "HSD node and wallet client", + keywords: [ + "http", + "request", + "socket.io", + "websockets" + ], + main: "./lib/client/index.js", + bin: { + "hsd-cli": "./bin/hsd-cli", + "hsd-rpc": "./bin/hsd-rpc", + "hsw-cli": "./bin/hsw-cli", + "hsw-rpc": "./bin/hsw-rpc" + }, + engines: { + node: ">=8.0.0" + } +} + +const INHERIT_PROPERTIES = [ + "version", + "license", + "repository", + "homepage", + "bugs", + "author" +]; + +const DEPENDENCIES = [ + "bcfg", + "bcurl", + "bsert" +]; + +const COPY_FILES = [ + ".npmignore", + ".gitignore", + "bin/hsd-cli", + "bin/hsw-cli", + "bin/hsd-rpc", + "bin/hsw-rpc", + "lib/client/index.js", + "lib/client/wallet.js", + "lib/client/node.js", +]; + +const README = ` +hs-client +========= + +Autogenerated from https://github.com/handshake-org/hsd. + +REST and RPC client for handshake. + +## Usage + +\`\`\` js +const {NodeClient, WalletClient} = require('hs-client'); +\`\`\` +`; + +async function ensureDir() { + if (!await fs.exists(ROOT)) + throw new Error(`${ROOT} does not exist.`); + + const {HS_CLIENT_DIR} = process.env; + + let HS_PKG = HS_CLIENT_DIR ? path.resolve(HS_CLIENT_DIR) : null; + + if (!HS_PKG) + HS_PKG = path.join(os.tmpdir(), `hs-client`); + + + if (HS_PKG.startsWith(ROOT)) + throw new Error(`hs-client needs to be outside of the hsd. ${HS_PKG}`); + + console.log('hs-client directory: ', HS_PKG); + + if (await fs.exists(HS_PKG)) { + throw new Error( + `Directory ${HS_PKG} already exists.` + + ' Please remove to proceed or choose different directory.' + ); + } + + await fs.mkdir(HS_PKG); + + return HS_PKG; +} + +async function setupPackageContent(dir) { + for (const file of COPY_FILES) { + const src = path.join(ROOT, file); + const dst = path.join(dir, file); + const dstDir = path.dirname(dst); + + if (!await fs.exists(dstDir)) + await fs.mkdirp(dstDir); + + await fs.copy(src, dst); + } + + const hsClientPkg = { + ...INIT_HS_CLIENT_PKG, + }; + + for (const name of INHERIT_PROPERTIES) { + assert(HSD_PKG[name]); + hsClientPkg[name] = HSD_PKG[name]; + } + + hsClientPkg.dependencies = {}; + for (const dep of DEPENDENCIES) { + assert(HSD_PKG.dependencies[dep], `Dependency "${dep}" not found for hsd.`); + hsClientPkg.dependencies[dep] = HSD_PKG.dependencies[dep]; + } + + await fs.writeJSON(path.join(dir, 'package.json'), hsClientPkg); + await fs.writeFile(path.join(dir, 'README.md'), README); + + return hsClientPkg; +} + +async function setupGit(dir, version) { + console.log('Setting up git: ', dir); + const commands = [ + 'git init -b master', + `git remote add origin ${REMOTE}`, + 'git add .', + `git commit --gpg-sign -m "v${version}"`, + `git tag --sign v${version} -m "v${version}"` + ]; + + const manualCommands = [ + 'git push -f origin master', + `git push -f origin v${version}` + ]; + + for (const cmd of [...commands]) { + console.log(`executing: ${cmd} in ${dir}.`); + + try { + console.log(await execCmd(cmd, dir)); + } catch (e) { + console.log(`Failed to execute: ${cmd}.`); + console.log(e.message); + console.log(' You can proceed manually'); + break; + } + + commands.shift(); + } + + for (const command of [...commands, ...manualCommands]) + console.log(`Needs exec: ${command}`); +} + +(async () => { + const HS_PKG = await ensureDir(); + const pkg = await setupPackageContent(HS_PKG); + + await setupGit(HS_PKG, pkg.version); + console.log('Needs: npm publish'); +})().catch((err) => { + console.error(err.stack); + process.exit(1); +}); + +async function execCmd(cmd, cwd, timeout = 2000) { + assert(cwd, 'CWD is required.'); + + const {stdout, stderr} = await exec(cmd, { + cwd, + timeout + }); + + if (stderr.length != 0) + throw new Error(stderr); + + return stdout; +} diff --git a/test/auction-rpc-test.js b/test/auction-rpc-test.js index e152cf34..6e27efda 100644 --- a/test/auction-rpc-test.js +++ b/test/auction-rpc-test.js @@ -14,7 +14,7 @@ const { Network, Path } = require('..'); -const {NodeClient, WalletClient} = require('hs-client'); +const {NodeClient, WalletClient} = require('../lib/client'); const {forValue} = require('./util/common'); class TestUtil { diff --git a/test/http-test.js b/test/http-test.js index b5c6a978..fdb1c49d 100644 --- a/test/http-test.js +++ b/test/http-test.js @@ -21,7 +21,7 @@ const node = new FullNode({ plugins: [require('../lib/wallet/plugin')] }); -const {NodeClient, WalletClient} = require('hs-client'); +const {NodeClient, WalletClient} = require('../lib/client'); const nclient = new NodeClient({ port: network.rpcPort, diff --git a/test/interactive-swap-test.js b/test/interactive-swap-test.js index 13aa28e1..c2bfd8fb 100644 --- a/test/interactive-swap-test.js +++ b/test/interactive-swap-test.js @@ -10,7 +10,7 @@ const Script = require('../lib/script/script'); const rules = require('../lib/covenants/rules'); const {types} = rules; const {Resource} = require('../lib/dns/resource'); -const {WalletClient} = require('hs-client'); +const WalletClient = require('../lib/client/wallet'); const network = Network.get('regtest'); diff --git a/test/node-http-test.js b/test/node-http-test.js index b7335a88..ac626e2e 100644 --- a/test/node-http-test.js +++ b/test/node-http-test.js @@ -2,7 +2,7 @@ const assert = require('bsert'); const bio = require('bufio'); -const {NodeClient} = require('hs-client'); +const NodeClient = require('../lib/client/node'); const Network = require('../lib/protocol/network'); const FullNode = require('../lib/node/fullnode'); const Address = require('../lib/primitives/address'); diff --git a/test/node-rpc-test.js b/test/node-rpc-test.js index 1bc8c793..f61442f2 100644 --- a/test/node-rpc-test.js +++ b/test/node-rpc-test.js @@ -7,7 +7,7 @@ const Network = require('../lib/protocol/network'); const consensus = require('../lib/protocol/consensus'); const MemWallet = require('./util/memwallet'); const TX = require('../lib/primitives/tx'); -const {NodeClient} = require('hs-client'); +const NodeClient = require('../lib/client/node'); const TIMEOUT = 15000; const API_KEY = 'foo'; diff --git a/test/wallet-accounts-auction-test.js b/test/wallet-accounts-auction-test.js index f370a447..892bfac9 100644 --- a/test/wallet-accounts-auction-test.js +++ b/test/wallet-accounts-auction-test.js @@ -6,7 +6,7 @@ const FullNode = require('../lib/node/fullnode'); const Address = require('../lib/primitives/address'); const rules = require('../lib/covenants/rules'); const Resource = require('../lib/dns/resource'); -const {WalletClient} = require('hs-client'); +const WalletClient = require('../lib/client/wallet'); const network = Network.get('regtest'); diff --git a/test/wallet-http-test.js b/test/wallet-http-test.js index a633214e..9d542c47 100644 --- a/test/wallet-http-test.js +++ b/test/wallet-http-test.js @@ -1,6 +1,6 @@ 'use strict'; -const {NodeClient, WalletClient} = require('hs-client'); +const {NodeClient, WalletClient} = require('../lib/client'); const Network = require('../lib/protocol/network'); const FullNode = require('../lib/node/fullnode'); const MTX = require('../lib/primitives/mtx'); diff --git a/test/wallet-importname-test.js b/test/wallet-importname-test.js index f6eb17e2..088a63d0 100644 --- a/test/wallet-importname-test.js +++ b/test/wallet-importname-test.js @@ -5,7 +5,7 @@ const Network = require('../lib/protocol/network'); const FullNode = require('../lib/node/fullnode'); const Address = require('../lib/primitives/address'); const rules = require('../lib/covenants/rules'); -const {WalletClient} = require('hs-client'); +const WalletClient = require('../lib/client/wallet'); const {forValue} = require('./util/common'); const network = Network.get('regtest'); diff --git a/test/wallet-rpc-test.js b/test/wallet-rpc-test.js index 9ab9f787..385126f3 100644 --- a/test/wallet-rpc-test.js +++ b/test/wallet-rpc-test.js @@ -1,7 +1,7 @@ 'use strict'; -const {NodeClient,WalletClient} = require('hs-client'); const assert = require('bsert'); +const {NodeClient, WalletClient} = require('../lib/client'); const FullNode = require('../lib/node/fullnode'); const Network = require('../lib/protocol/network'); const Mnemonic = require('../lib/hd/mnemonic'); diff --git a/test/wallet-test.js b/test/wallet-test.js index d6d90f48..9f2bda81 100644 --- a/test/wallet-test.js +++ b/test/wallet-test.js @@ -1,7 +1,7 @@ 'use strict'; const assert = require('bsert'); -const {WalletClient} = require('hs-client'); +const WalletClient = require('../lib/client/wallet'); const consensus = require('../lib/protocol/consensus'); const Network = require('../lib/protocol/network'); const util = require('../lib/utils/util');