{"id":16325472,"url":"https://github.com/tynes/libsigner","last_synced_at":"2026-05-08T04:43:03.837Z","repository":{"id":104848516,"uuid":"169314198","full_name":"tynes/libsigner","owner":"tynes","description":"manage watch only bitcoin wallets with bcoin","archived":false,"fork":false,"pushed_at":"2019-02-27T23:44:36.000Z","size":298,"stargazers_count":3,"open_issues_count":8,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-06-05T12:39:19.774Z","etag":null,"topics":["bcoin","bitcoin","cryptography","ledger","nodejs","trezor"],"latest_commit_sha":null,"homepage":"http://bcoin.io","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tynes.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-02-05T21:16:29.000Z","updated_at":"2022-11-06T00:24:50.000Z","dependencies_parsed_at":"2023-07-04T22:50:27.918Z","dependency_job_id":null,"html_url":"https://github.com/tynes/libsigner","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/tynes/libsigner","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tynes%2Flibsigner","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tynes%2Flibsigner/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tynes%2Flibsigner/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tynes%2Flibsigner/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tynes","download_url":"https://codeload.github.com/tynes/libsigner/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tynes%2Flibsigner/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32767585,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-08T02:36:36.067Z","status":"ssl_error","status_checked_at":"2026-05-08T02:36:07.210Z","response_time":54,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bcoin","bitcoin","cryptography","ledger","nodejs","trezor"],"created_at":"2024-10-10T23:05:07.154Z","updated_at":"2026-05-08T04:43:03.832Z","avatar_url":"https://github.com/tynes.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# libsigner\n\nManage watch only wallets with bcoin\n\n## Features\n\n- Node.js `Hardware` Class with Ledger Support\n- CLI tooling for end to end work with `bcoin`\n- Pull extended public keys, create watch only wallets/accounts\n- Sign transactions, broadcast to the network\n- Manage multisignature wallets\n\n## Library Usage\n\n`libsigner` helps to manage watch only wallets using `bcoin`.\n\n### Exposed Classes/Functions\n\n##### Hardware\n\nA class to manage signing. Currently only supports Hardware devices,\nbut will be generalized into an abstract `Signer` in the future.\n\n```javascript\n\nconst {Hardware,Path} = require('libsigner');\n\n(async () =\u003e {\n\n  // create bip44 xpub path\n  const path = Path.fromList([44,0,0], true);\n\n  const hardware = Hardware.fromOptions({\n    vendor: 'ledger',    // supports ledger\n    network: 'regtest',  // main, testnet, regtest, or simnet\n  });\n  \n  const hdpubkey = await hardware.getPublicKey(path);\n\n})().catch(e =\u003e {\n  console.log(e.stack);\n  process.exit(1);\n});\n\n```\n\nThe `Hardware` class is an `eventemitter` and emits on 2 topics.\n`connect` and `disconnect`, an `options` object is passed along\nand has the device fingerprint (defined as the bip174 master public\nkey fingerprint) and the device vendor. See `examples/events.js`\n\nUse in conjunction with [bcoin](https://github.com/bcoin-org/bcoin/)\nto sign transactions using the hardware wallet device.\n\n\n```javascript\nconst {WalletClient} = require('bclient');\nconst {Newtork} = require('bcoin');\nconst {Path,prepareSign,Hardware} = require('libsigner');\n\nconst network = Network.get('regtest');\n\nconst client = new WalletClient({\n  port: network.walletPort,\n  network: network.type,\n});\n\nconst wallet = client.wallet('mywallet');\n\nconst hardware = Hardware.fromOptions({\n  vendor: 'ledger',\n  network: 'regtest',\n});\n\nconst wallet = client.wallet('primary');\nconst path = Path.fromList([44,0,0], true);\n\nconst tx = await wallet.createTX({\n  account: 'default',\n  rate: 1e3,\n  outputs: [{ value: 1e4, address: REaoV1gcgqDSQCkdZpjFZptGnutGEat4DR }],\n  sign: false,\n});\n\nconst {coins,inputTXs,paths,mtx} = await prepareSign({\n  tx: tx,\n  wallet: walletClient.wallet(walletId),\n  path: path.clone(),\n});\n\nconst signed = await hardware.signTransaction(mtx, {\n  paths,\n  inputTXs,\n  coins,\n});\n\nconsole.log(signed.verify());\n// true\n```\n\nAlso use in conjunction with [bmultisig](https://github.com/bcoin-org/bmultisig)\nto manage signing multisignature transactions\n\n```javascript\nconst {WalletClient} = require('bclient');\nconst {Newtork} = require('bcoin');\nconst {Path,prepareSignMultisig,Hardware} = require('libsigner');\n\nconst network = Network.get('regtest');\n\nconst client = new WalletClient({\n  port: network.walletPort,\n  network: network.type,\n});\n\nconst wallet = client.wallet('primary');\n\nconst proposalId = 0;\nconst path = Path.fromList([44,0,0], true);\n\nconst pmtx = await wallet.getProposalMTX(proposalId, {\n  paths: true,\n  scripts: true,\n  txs: true,\n});\n\nconst {paths,inputTXs,coins,scripts,mtx} = prepareSignMultisig({\n  pmtx,\n  path: path.clone(),\n});\n\nconst signatures = await hardware.getSignature(mtx, {\n  paths,\n  inputTXs,\n  coins,\n  scripts,\n  enc: 'hex',\n});\n\nconst approval = await wallet.approveProposal(proposalId, signatures);\n\n```\n\n##### Path\n\nA class to manage [bip44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki)\nwallets. This class can be used in conjunction with the `Hardware` class\nto make deriving keys on the device more simple.\n\n- Create abstractions over hardened indices (no more manual bitwise or)\n- Represent as string or list of uint256\n- Throw errors in \"strict\" mode, when path depth exceeds 5\n- Infer path from extended [public key](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#serialization-format)\n\nCommonly seen notation for a hardened index includes `0'` or `0h`. Under the hood,\nthe hardened index is not `0`, its representations are shown below:\n\n- `0 | 0x80000000`\n- `1 \u003c\u003c 31`\n- `2147483648`\n- `0b10000000000000000000000000000000`\n\nDifferent paths correspond to different coins. See [slip44](https://github.com/satoshilabs/slips/blob/master/slip-0044.md)\nto learn the mapping between coin types and coins.\n\nCreate a `Path` that represents the path to the\nkeypair that locks a particular utxo\n\n```javascript\nconst {Path} = require('libsigner');\n\n// create a Path instance for bitcoin mainnet\nconst path = Path.fromList([44,0,0], true);\n\nconsole.log(path.toString());\n// 'm\\'/44\\'/0\\'/0\\''\n\nconsole.log(path.toList());\n// [ 2147483692, 2147483648, 2147483648 ]\n\n// clone path to reuse the same\n// account depth path for another tx\n// from same account\nlet myTXPath = path.clone();\n\n// fetch branch and index from someplace\nconst branch = 0;\nconst index = 0;\n\nmyTXPath = myTXPath.push(branch).push(index);\n\nconsole.log(myTXPath.toString());\n// 'm\\'/44\\'/0\\'/0\\'/0/0'\n\nconsole.log(myTXPath.toList());\n// [ 2147483692, 2147483648, 2147483648, 0, 0 ]\n\n```\n\n## CLI Usage\n\n### pubkeys.js\n\nQuickly pull [bip 32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#serialization-format)\nextended public keys from your hardware devices\n\nNote that bcoin@1.x.x uses the extended key prefix `rpub` for regtest\nextended account public keys (`m/44'/1'/{i}'`), the 2.x.x release\nwill use `tpub` and be compatible with bitcoind.\n\n```bash\n$ ./bin/pubkeys.js -v ledger -n regtest -i 0h\n{\n  \"network\": \"regtest\",\n  \"vendor\": \"ledger\",\n  \"path\": \"m'/44'/1'/0'\",\n  \"xkey\": \"rpubKBA5VcKMuu9dL73dKJSAMNx8FkPAURAsJUr2mTTJWgAGQxuwB9Nj3VHCzwEtqUQhUWnEJSHFzGGxrzTgdYQL46fekWEbFeSsruRQn3wDujaC\",\n  \"publicKey\": \"028b42cd4776376c82791b494155151f56c2d7b471e0c7a526a7ce60dd872e3867\",\n  \"receive\": {\n    \"legacy\": [\n      \"REaoV1gcgqDSQCkdZpjFZptGnutGEat4DR\",\n      \"RUaqJ3PnCZPFRcdV4PBYvgmbLjWhqrBKX3\",\n      \"RGDzkAB4UkUnATjpP2d9AKBxyFGMimaC1r\"\n    ],\n    \"segwit\": [\n      \"rb1q8gk5z3dy7zv9ywe7synlrk58elz4hrnearrkd8\",\n      \"rb1q60qgwr5wzw57cvs0z2qg3yf84g26fs9pjcjacf\",\n      \"rb1qfshzhu5qdyz94r4kylyrnlerq6mnhw3s9y9e85\"\n    ]\n  },\n  \"change\": {\n    \"legacy\": [\n      \"RBu2VTMz4MnCziyo9tccAkjjFVWkEeMwV1\",\n      \"RTuXStuGuqQURBGiMGq5zN75W1fg3exBTc\",\n      \"RGXwdbMLoaVaXFzLifkZLJFND14KcvdyVA\"\n    ],\n    \"segwit\": [\n      \"rb1qrjmnjg944su0gc8r3h4ksjuuffqglu7q3yrsyp\",\n      \"rb1qe3gksfnc76gujkqsxqxh79t9nqe4ervwhgqu2h\",\n      \"rb1qf7fs76w04gdtwrg6cktw52agqzvdttvzv8k2g5\"\n    ]\n  }\n}\n```\n\n### sign.js\n\nKeep private keys on a hardware security module instead of any old machine.\nSign transactions that the bcoin wallet assmebles for watch only wallets.\nThen broadcast them to the network.\n\n##### Flags\n\nUse the `--help` flag to see in depth details.\n\n- `-i` - bip44 account index, must specify hardened with either `h` or `'`\n- `-n` - bitcoin network, one of main, testnet, regtest, simnet\n- `-v` - signing vendor, one of ledger or trezor\n\nLets start by verifying. Grab the first receive address of the first account.\nThis address corresponds to `m/44'/1'/0'/0/0`. Using `jq`, it is possible to\nindex into the returned list of addresses and they are indexed in ascending order.\n\n```bash\n$ receive=$(./bin/pubkeys.js -v ledger -i 0h -n regtest | jq -r .receive.legacy[0])\n```\n\nNow we can create a wallet using the extended public key `44h/0h/0h`.\n\n```bash\n$ ./bin/pubkeys.js -v ledger -i 0h -n regtest -w foo --create-wallet\n```\n\nNow lets compare the receive address that bcoin created against\nthe one that we derived locally\n\n```bash\n$ bwallet-cli --id foo account get default | jq -r .receiveAddress\nREaoV1gcgqDSQCkdZpjFZptGnutGEat4DR\n```\n\nSanity check to make sure they match\n\n```bash\n$ echo $receive\nREaoV1gcgqDSQCkdZpjFZptGnutGEat4DR\n```\n\nIf you don't already have a ton of BTC at that address, mine some real quick\n\n```bash\n$ bcoin-cli rpc generatetoaddress 300 REaoV1gcgqDSQCkdZpjFZptGnutGEat4DR\n```\n\nNow create a transaction and sign it. It will broadcast it to the network\nautomatically.\n\n```bash\n$ ./bin/sign.js -v ledger -w foo -n regtest --value 10000 --recipient REaoV1gcgqDSQCkdZpjFZptGnutGEat4DR\n{\n  \"vendor\": \"ledger\",\n  \"network\": \"regtest\",\n  \"wallet\": \"foo\",\n  \"account\": \"default\",\n  \"valid\": true,\n  \"broadcast\": true,\n  \"hex\": \"010000000174fa5c5c4d870b04c47dea06f97422962d80be048413d5e787bfdc6e12c07bd0000000006b483045022100a16f35b7e7a414e5c100f362bcdc02e526ac6a962a03b955098ca5949caddd4a0220256d1d3aef9e7ea89402e3519d97d7e99c0a38022288e66363ab8a4715089c5e012102a7451395735369f2ecdfc829c0f774e88ef1303dfe5b2f04dbaab30a535dfdd6ffffffff022d260000000000001976a9143a2d4145a4f098523b3e8127f1da87cfc55b8e7988ace2de2901000000001976a914033e299551bd538711fb536beb7f99a726f24cb988ac00000000\",\n  \"response\": {\n    \"success\": true\n  }\n}\n```\n\n### multisig.js\n\nDocs coming soon\n\n## Notes\n\nSigning transactions with both legacy and segwit\ninputs will not work on ledger and trezor hardware \ndevices due to their firmware. It is possible\nto craft such transactions with bcoin, so please\nbe careful not to do so.\n\nbcoin is pinned to a specific commit `a2e176d4`\nbecause it is right before a change in the\nregtest keyprefixes, which will break its compatibility\nwith `bmultisig`, since it relies on `bcoin@1.0.2`\n\n## TODO\n\n- Separate tests so that they can more easily run\n- prepackage `trezor.js` post babelified, so that we do not need to include `babel-runtime` as a dependency.\n\n## Disclaimer\n\nThis is experimental software for an experimental protocol.\nPlease do your own research and understand the code if you\ndecide to use it with real money.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftynes%2Flibsigner","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftynes%2Flibsigner","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftynes%2Flibsigner/lists"}