Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/bcoin-org/bsigner
hardware management and signing
https://github.com/bcoin-org/bsigner
Last synced: 6 days ago
JSON representation
hardware management and signing
- Host: GitHub
- URL: https://github.com/bcoin-org/bsigner
- Owner: bcoin-org
- License: other
- Created: 2019-02-28T19:13:29.000Z (over 5 years ago)
- Default Branch: master
- Last Pushed: 2020-05-25T14:48:39.000Z (over 4 years ago)
- Last Synced: 2023-10-20T18:09:20.249Z (about 1 year ago)
- Language: JavaScript
- Size: 573 KB
- Stars: 6
- Watchers: 11
- Forks: 3
- Open Issues: 8
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# bsigner
Manage watch only wallets with bcoin
## Features
- Node.js `Signer` Class with Ledger and Trezor support.
- CLI tooling for end to end work with `bcoin`.
- Pull extended public keys, create watch only wallets/accounts.
- Sign transactions, broadcast to the network.
- Manage multisignature wallets.## Library Usage
`bsigner` helps to manage hardware signing using `bcoin`.
### Exposed Classes/Functions
##### Signer
A class to manage multiple devices/vendors and do signing.```javascript
const {Signer, Path} = require('bsigner');
(async () => {
// create bip44 xpub path
const path = Path.fromList([44,0,0], true);const manager = Signer.fromOptions({
vendor: 'ledger', // enabled vendors, supports ledger and trezor
network: 'regtest' // main, testnet, regtest, or simnet
});await manager.open();
// select device with vendor.
await manager.selectDevice('ledger');const hdpubkey = await manager.getPublicKey(path);
})().catch(e => {
console.log(e.stack);
process.exit(1);
});```
The `Signer` class is an `eventemitter` and emits on 4 topics.
`connect`, `disconnect`, `select`, `deselect`, a `device` object is passed along.Use in conjunction with [bcoin](https://github.com/bcoin-org/bcoin/)
to sign transactions using the hardware wallet device.```javascript
const {WalletClient} = require('bclient');
const {Newtork} = require('bcoin');
const {Path, prepareSign, Signer} = require('bsigner');const network = Network.get('regtest');
const client = new WalletClient({
port: network.walletPort,
network: network.type
});const wallet = client.wallet('mywallet');
const manager = Signer.fromOptions({
vendor: 'ledger',
network: 'regtest'
});const wallet = client.wallet('primary');
const path = Path.fromList([44,0,0], true);const tx = await wallet.createTX({
account: 'default',
rate: 1e3,
outputs: [{ value: 1e4, address: 'REaoV1gcgqDSQCkdZpjFZptGnutGEat4DR' }],
sign: false
});const {mtx, inputData} = await prepareSign({
tx: tx,
wallet: walletClient.wallet(walletId),
path: path.clone(),
network: network
});const signed = await manager.signTransaction(mtx, inputData);
console.log(signed.verify());
// true
```Also use in conjunction with [bmultisig](https://github.com/bcoin-org/bmultisig)
to manage signing multisignature transactions```javascript
const {WalletClient} = require('bclient');
const {Newtork} = require('bcoin');
const {Path, prepareSignMultisig, Signer} = require('bsigner');const network = Network.get('regtest');
const client = new WalletClient({
port: network.walletPort,
network: network.type
});const wallet = client.wallet('primary');
const proposalId = 0;
const path = Path.fromList([44,0,0], true);const {mtx, inputData} = prepareSignMultisig({
proposalId,
path: path.clone(),
wallet: wallet,
network: network
});const signatures = await manager.getSignature(mtx, inputData);
const approval = await wallet.approveProposal(proposalId, signatures);```
##### Path
A class to manage [bip44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki)
wallets. This class can be used in conjunction with the `Hardware` class
to make deriving keys on the device more simple.- Create abstractions over hardened indices (no more manual bitwise or)
- Represent as string or list of uint256
- Throw errors in "strict" mode, when path depth exceeds 5
- Infer path from extended [public key](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#serialization-format)Commonly seen notation for a hardened index includes `0'` or `0h`. Under the hood,
the hardened index is not `0`, its representations are shown below:- `0 | 0x80000000`
- `1 << 31`
- `2147483648`
- `0b10000000000000000000000000000000`Different paths correspond to different coins. See [slip44](https://github.com/satoshilabs/slips/blob/master/slip-0044.md)
to learn the mapping between coin types and coins.Create a `Path` that represents the path to the
keypair that locks a particular utxo```javascript
const {Path} = require('bsigner');// create a Path instance for bitcoin mainnet
const path = Path.fromList([44,0,0], true);console.log(path.toString());
// 'm\'/44\'/0\'/0\''console.log(path.toList());
// [ 2147483692, 2147483648, 2147483648 ]// clone path to reuse the same
// account depth path for another tx
// from same account
let myTXPath = path.clone();// fetch branch and index from someplace
const branch = 0;
const index = 0;myTXPath = myTXPath.push(branch).push(index);
console.log(myTXPath.toString());
// 'm\'/44\'/0\'/0\'/0/0'console.log(myTXPath.toList());
// [ 2147483692, 2147483648, 2147483648, 0, 0 ]```
## CLI Usage
### pubkeys.js
Quickly pull [bip 32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#serialization-format)
extended public keys from your hardware devicesNote that [email protected] uses the extended key prefix `rpub` for regtest
extended account public keys (`m/44'/1'/{i}'`), the 2.x.x release
will use `tpub` and be compatible with bitcoind.```bash
$ ./bin/pubkeys.js -v ledger -n regtest -i 0h
{
"network": "regtest",
"vendor": "ledger",
"path": "m'/44'/1'/0'",
"xkey": "rpubKBA5VcKMuu9dL73dKJSAMNx8FkPAURAsJUr2mTTJWgAGQxuwB9Nj3VHCzwEtqUQhUWnEJSHFzGGxrzTgdYQL46fekWEbFeSsruRQn3wDujaC",
"publicKey": "028b42cd4776376c82791b494155151f56c2d7b471e0c7a526a7ce60dd872e3867",
"receive": {
"legacy": [
"REaoV1gcgqDSQCkdZpjFZptGnutGEat4DR",
"RUaqJ3PnCZPFRcdV4PBYvgmbLjWhqrBKX3",
"RGDzkAB4UkUnATjpP2d9AKBxyFGMimaC1r"
],
"segwit": [
"rb1q8gk5z3dy7zv9ywe7synlrk58elz4hrnearrkd8",
"rb1q60qgwr5wzw57cvs0z2qg3yf84g26fs9pjcjacf",
"rb1qfshzhu5qdyz94r4kylyrnlerq6mnhw3s9y9e85"
]
},
"change": {
"legacy": [
"RBu2VTMz4MnCziyo9tccAkjjFVWkEeMwV1",
"RTuXStuGuqQURBGiMGq5zN75W1fg3exBTc",
"RGXwdbMLoaVaXFzLifkZLJFND14KcvdyVA"
],
"segwit": [
"rb1qrjmnjg944su0gc8r3h4ksjuuffqglu7q3yrsyp",
"rb1qe3gksfnc76gujkqsxqxh79t9nqe4ervwhgqu2h",
"rb1qf7fs76w04gdtwrg6cktw52agqzvdttvzv8k2g5"
]
}
}
```### sign.js
Keep private keys on a hardware security module instead of any old machine.
Sign transactions that the bcoin wallet assmebles for watch only wallets.
Then broadcast them to the network.##### Flags
Use the `--help` flag to see in depth details.
- `-i` - bip44 account index, must specify hardened with either `h` or `'`
- `-n` - bitcoin network, one of main, testnet, regtest, simnet
- `-v` - signing vendor: `ledger` or `trezor`Lets start by verifying. Grab the first receive address of the first account.
This address corresponds to `m/44'/1'/0'/0/0`. Using `jq`, it is possible to
index into the returned list of addresses and they are indexed in ascending order.```bash
$ receive=$(./bin/pubkeys.js -v ledger -i 0h -n regtest | jq -r .receive.legacy[0])
```Now we can create a wallet using the extended public key `44h/0h/0h`.
```bash
$ ./bin/pubkeys.js -v ledger -i 0h -n regtest -w foo --create-wallet
```Now lets compare the receive address that bcoin created against
the one that we derived locally```bash
$ bwallet-cli --id foo account get default | jq -r .receiveAddress
REaoV1gcgqDSQCkdZpjFZptGnutGEat4DR
```Sanity check to make sure they match
```bash
$ echo $receive
REaoV1gcgqDSQCkdZpjFZptGnutGEat4DR
```If you don't already have a ton of BTC at that address, mine some real quick
```bash
$ bcoin-cli rpc generatetoaddress 300 REaoV1gcgqDSQCkdZpjFZptGnutGEat4DR
```Now create a transaction and sign it. It will broadcast it to the network
automatically.```bash
$ ./bin/sign.js -v ledger -w foo -n regtest --value 10000 --recipient REaoV1gcgqDSQCkdZpjFZptGnutGEat4DR
{
"vendor": "ledger",
"network": "regtest",
"wallet": "foo",
"account": "default",
"valid": true,
"broadcast": true,
"hex": "010000000174fa5c5c4d870b04c47dea06f97422962d80be048413d5e787bfdc6e12c07bd0000000006b483045022100a16f35b7e7a414e5c100f362bcdc02e526ac6a962a03b955098ca5949caddd4a0220256d1d3aef9e7ea89402e3519d97d7e99c0a38022288e66363ab8a4715089c5e012102a7451395735369f2ecdfc829c0f774e88ef1303dfe5b2f04dbaab30a535dfdd6ffffffff022d260000000000001976a9143a2d4145a4f098523b3e8127f1da87cfc55b8e7988ace2de2901000000001976a914033e299551bd538711fb536beb7f99a726f24cb988ac00000000",
"response": {
"success": true
}
}
```### multisig.js
Docs coming soon
## TODO
- Separate tests so that they can more easily run
## Disclaimer
This is experimental software for an experimental protocol.
Please do your own research and understand the code if you
decide to use it with real money.