A set of utilities for working with BIP32.
Compatible with bitcoinjs-lib ^2.0.0 and ^3.0.0.
constbip39=require('bip39')constbitcoin=require('bitcoinjs-lib')constbip32utils=require('bip32-utils')letmnemonic=bip39.generateMnemonic()letseed=bip39.mnemonicToSeedSync(mnemonic)lethdNode=bitcoin.bip32.fromSeed(seed)letchildNode=hdNode.deriveHardened(0)letexternal=childNode.derive(0)letinternal=childNode.derive(1)letaccount=newbip32utils.Account([newbip32utils.Chain(external.neutered()),newbip32utils.Chain(internal.neutered())])console.log(account.getChainAddress(0))// => 1QEj2WQD9vxTzsGEvnmLpvzeLVrpzyKkGtaccount.nextChainAddress(0)console.log(account.getChainAddress(1))// => 1DAi282VN7Ack9o5BqWYkiEsS8Vgx1rLnconsole.log(account.nextChainAddress(1))// => 1CXKM323V3kkrHmZQYPUTftGh9VrAWuAYXconsole.log(account.derive('1QEj2WQD9vxTzsGEvnmLpvzeLVrpzyKkGt'))// => xpub6A5Fz4JZg4kd8pLTTaMBKsvVgzRBrvai6ChoxWNTtYQ3UDVG1VyAWQqi6SNqkpsfsx9F8pRqwtKUbU4j4gqpuN2gpgQs4DiJxsJQvTjdzfA// NOTE: passing in the parent nodes allows for private key escalation (see xprv vs xpub)console.log(account.derive('1QEj2WQD9vxTzsGEvnmLpvzeLVrpzyKkGt',[external,internal]))// => xprv9vodQPEygdPGUWeKUVNd6M2N533PvEYP21tYxznauyhrYBBCmdKxRJzmnsTsSNqfTJPrDF98GbLCm6xRnjceZ238Qkf5GQGHk79CrFqtG4dconstbip39=require('bip39')constbitcoin=require('bitcoinjs-lib')constbip32utils=require('bip32-utils')letmnemonic=bip39.generateMnemonic()letseed=bip39.mnemonicToSeedSync(mnemonic)lethdNode=bitcoin.bip32.fromSeed(seed)letchain=newbip32utils.Chain(hdNode)letaddress=chain.get()console.log(chain.find(address))// => 0for(letk=0;k<10;++k)chain.next()address=chain.get()console.log(chain.find(address))// => 10console.log(chain.pop())// => pops the 11th addressletbip32utils=require('bip32-utils')letbitcoin=require('bitcoinjs-lib')letBlockchain=require('cb-blockr')// ...letblockchain=newBlockchain('testnet')lethdNode=bitcoin.HDNode.fromSeedHex(seedHex)letchain=bip32utils.Chain(hdNode)letGAP_LIMIT=20bip32utils.discovery(chain,GAP_LIMIT,function(addresses,callback){blockchain.addresses.summary(addresses,function(err,results){if(err)returncallback(err)letareUsed=results.map(function(result){returnresult.totalReceived>0})callback(undefined,areUsed)})},function(err,used,checked){if(err)throwerrconsole.log('Discovered at most '+used+' used addresses')console.log('Checked '+checked+' addresses')console.log('With at least '+(checked-used)+' unused addresses')// throw away ALL unused addresses AFTER the last unused addressletunused=checked-usedfor(leti=1;i<unused;++i)chain.pop()// remember used !== total, chain may have started at a k-index > 0console.log('Total number of addresses (after prune): ',chain.addresses.length)})