sendBch.ts 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. /*
  2. Consolidate all UTXOs in an address into a single UTXO
  3. */
  4. // REST API servers.
  5. const BCHN_MAINNET = 'https://bchn.fullstack.cash/v5/'
  6. // bch-js-examples require code from the main bch-js repo
  7. import BCHJS from '@psf/bch-js'
  8. // Instantiate bch-js based on the network.
  9. const bchjs = new BCHJS({ restURL: BCHN_MAINNET })
  10. const SEND_ADDR = walletInfo.cashAddress
  11. const SEND_MNEMONIC = walletInfo.mnemonic
  12. const MAX_NUM_UTXOS = 100
  13. async function consolidateUtxos () {
  14. try {
  15. // instance of transaction builder
  16. const transactionBuilder = new bchjs.TransactionBuilder()
  17. let sendAmount = 0
  18. const inputs = []
  19. const data = await bchjs.Electrumx.utxo(SEND_ADDR)
  20. const utxos = data.utxos
  21. let maxLen = utxos.length
  22. console.log(`There are ${maxLen} UTXOs to consolidate.`)
  23. if(maxLen > MAX_NUM_UTXOS) maxLen = MAX_NUM_UTXOS
  24. // Loop through each UTXO assigned to this address.
  25. for (let i = 0; i < maxLen; i++) {
  26. const thisUtxo = utxos[i]
  27. inputs.push(thisUtxo)
  28. sendAmount += thisUtxo.value
  29. // ..Add the utxo as an input to the transaction.
  30. transactionBuilder.addInput(thisUtxo.tx_hash, thisUtxo.tx_pos)
  31. }
  32. // get byte count to calculate fee. paying 1.2 sat/byte
  33. const byteCount = bchjs.BitcoinCash.getByteCount(
  34. { P2PKH: inputs.length },
  35. { P2PKH: 1 }
  36. )
  37. console.log(`byteCount: ${byteCount}`)
  38. const satoshisPerByte = 1.0
  39. const txFee = Math.ceil(satoshisPerByte * byteCount)
  40. console.log(`txFee: ${txFee}`)
  41. // Exit if the transaction costs too much to send.
  42. if (sendAmount - txFee < 0) {
  43. console.log(
  44. "Transaction fee costs more combined UTXOs. Can't send transaction."
  45. )
  46. return
  47. }
  48. // add output w/ address and amount to send
  49. transactionBuilder.addOutput(SEND_ADDR, sendAmount - txFee)
  50. // Generate a change address from a Mnemonic of a private key.
  51. const change = await changeAddrFromMnemonic(SEND_MNEMONIC)
  52. // Generate a keypair from the change address.
  53. const keyPair = bchjs.HDNode.toKeyPair(change)
  54. // sign w/ HDNode
  55. let redeemScript
  56. inputs.forEach((input, index) => {
  57. transactionBuilder.sign(
  58. index,
  59. keyPair,
  60. redeemScript,
  61. transactionBuilder.hashTypes.SIGHASH_ALL,
  62. input.value
  63. )
  64. })
  65. // build tx
  66. const tx = transactionBuilder.build()
  67. // output rawhex
  68. const hex = tx.toHex()
  69. // console.log(`TX hex: ${hex}`)
  70. console.log(' ')
  71. // Broadcast transation to the network
  72. const txid = await bchjs.RawTransactions.sendRawTransaction([hex])
  73. // import from util.js file
  74. const util = require('../util.js')
  75. console.log(`Transaction ID: ${txid}`)
  76. console.log('Check the status of your transaction on this block explorer:')
  77. util.transactionStatus(txid, 'mainnet')
  78. } catch (err) {
  79. console.log('error: ', err)
  80. }
  81. }
  82. consolidateUtxos()
  83. // Generate a change address from a Mnemonic of a private key.
  84. async function changeAddrFromMnemonic (mnemonic) {
  85. // root seed buffer
  86. const rootSeed = await bchjs.Mnemonic.toSeed(mnemonic)
  87. // master HDNode
  88. const masterHDNode = bchjs.HDNode.fromSeed(rootSeed)
  89. // HDNode of BIP44 account
  90. const account = bchjs.HDNode.derivePath(masterHDNode, "m/44'/145'/0'")
  91. // derive the first external change address HDNode which is going to spend utxo
  92. const change = bchjs.HDNode.derivePath(account, '0/0')
  93. return change
  94. }