You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

index.ts 4.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. const HDKey = require('hdkey');
  2. const bitcoin = require('bitcoinjs-lib');
  3. const bip39 = require('bip39')
  4. const assert = require('bsert');
  5. export type network = 'testnet' | 'mainnet'
  6. export type keyType = "public" | "private"
  7. /**
  8. * Generate a BIP39 menemonic
  9. */
  10. function randomMenemonic():string{
  11. return bip39.generateMnemonic()
  12. }
  13. /**
  14. * Generate a pseudo-random seed from BIP39 menemonic
  15. * @param menemonic
  16. */
  17. function seedFromMenemonic(menemonic:string):string{
  18. assert(bip39.validateMnemonic(menemonic))
  19. return bip39.mnemonicToSeedSync(menemonic).toString('hex')
  20. }
  21. /**
  22. * Derive an extended keypair from seed
  23. * @param seed The seed-string to use for generating the HDKey
  24. * @param net Network to use ("testnet", "mainnet")
  25. * @param n n-th derived keypair default:0
  26. */
  27. function deriveAccount(seed:string, net:network = "mainnet", n:number = 0):{publicExtendedKey:string, privateExtendedKey:string}{
  28. assert(n >= 0)
  29. let version
  30. if(net === 'testnet'){
  31. version = {private: 0x04358394, public: 0x043587CF} // HDKey does not support testnet keys out of the box
  32. }
  33. let rootKey = HDKey.fromMasterSeed(seed, version)
  34. let childKey = rootKey.derive('m/'+n+'\'')
  35. childKey.network = version
  36. return childKey
  37. }
  38. //doc https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
  39. //lib https://github.com/cryptocoinjs/hdkey
  40. //gen http://bip32.org/
  41. // enter bip32 key of the following formats:
  42. // - extended public mainnet key (xpub prefix)
  43. // - extended private mainnet key (xprv prefix) (not reccomended)
  44. // - extended public testnet key (tpub prefix)
  45. // - extended private testnet key (tprv prefix) (not reccomended)
  46. /**
  47. *
  48. * @param extendedKey Extended key to generate address from
  49. * @param networkName Network to use ("testnet", "mainnet")
  50. * @param n n-th derived address default:0
  51. */
  52. function generateAddress(extendedKey:string, n:number = 0):string{
  53. assert(n >= 0)
  54. let version
  55. let t = checkHDKey(extendedKey)
  56. if(!t){
  57. throw new Error("Not an extended key: "+extendedKey)
  58. }
  59. if(t.net == "testnet"){
  60. version = {private: 0x04358394, public: 0x043587CF} //HDKey does not support testnet keys out of the box
  61. }
  62. const hdkey = HDKey.fromExtendedKey(extendedKey, version)
  63. const childkey = hdkey.derive('m/0/'+n)
  64. const address = bitcoin.payments.p2pkh({ pubkey: childkey._publicKey, network: bitcoin.networks[t.net] }).address!
  65. return address
  66. }
  67. function HDKeyFromExtendedKey(extendedKeyB58: string): any | false{
  68. let hdkey
  69. let version
  70. let t = checkHDKey(extendedKeyB58)
  71. if(!t){
  72. return false
  73. }
  74. if(t.net === 'testnet'){
  75. version = {private: 0x04358394, public: 0x043587CF} // HDKey does not support testnet keys out of the box
  76. }
  77. if(t.type === 'public'){
  78. hdkey = HDKey.fromExtendedKey(extendedKeyB58, version)
  79. }else{
  80. hdkey = HDKey.fromExtendedKey(extendedKeyB58, version)
  81. }
  82. return hdkey
  83. }
  84. function checkHDKey(key: string): {net: network, type: keyType} | false{
  85. if(key.startsWith('x')){
  86. if(key.startsWith('xpub')){
  87. return {net:'mainnet', type: 'public'}
  88. }else{
  89. return {net:'mainnet', type: 'private'}
  90. }
  91. }
  92. if(key.startsWith('t')){
  93. if(key.startsWith('tpub')){
  94. return {net:'testnet', type: 'public'}
  95. }else{
  96. return {net:'testnet', type: 'private'}
  97. }
  98. }
  99. return false
  100. }
  101. function deriveAddress(extendedKey: string, n: number, derivationPrefix = 'm/0/'): string | false{
  102. let t = checkHDKey(extendedKey)
  103. let childkey = deriveKey(extendedKey, n, derivationPrefix)
  104. if(!t || !childkey){
  105. return false
  106. }
  107. return addressFromHDKey(childkey._publicKey, t.net)
  108. }
  109. function deriveKey(extendedKey: string, n: number, derivationPrefix = 'm/0/'): any | false{
  110. let t = checkHDKey(extendedKey)
  111. let hdkey = HDKeyFromExtendedKey(extendedKey)
  112. if(!t || !hdkey){
  113. return false
  114. }
  115. return hdkey.derive(derivationPrefix+n)
  116. }
  117. function addressFromHDKey(hdkey:string, net: network = "mainnet"){
  118. return <string>bitcoin.payments.p2pkh({ pubkey: Buffer.from(hdkey), network: bitcoin.networks[net] }).address
  119. }
  120. export const exprt = {
  121. addressFromHDKey: addressFromHDKey,
  122. deriveAccount: deriveAccount,
  123. deriveAddress: deriveAddress,
  124. generateAddress: generateAddress,
  125. HDKeyFromExtendedKey: HDKeyFromExtendedKey,
  126. seedFromMenemonic: seedFromMenemonic,
  127. randomMenemonic: randomMenemonic
  128. }
  129. module.exports = exprt