UNPKG

@xchainjs/xchain-bitcoincash

Version:

Custom bitcoincash client and utilities used by XChainJS clients

1,995 lines (1,817 loc) 59.8 kB
'use strict'; var bitcash = require('@psf/bitcoincashjs-lib'); var xchainClient = require('@xchainjs/xchain-client'); var xchainCrypto = require('@xchainjs/xchain-crypto'); var xchainUtxo = require('@xchainjs/xchain-utxo'); var xchainUtil = require('@xchainjs/xchain-util'); var xchainUtxoProviders = require('@xchainjs/xchain-utxo-providers'); var bchaddr = require('bchaddrjs'); var require$$0 = require('buffer'); var AppBtc = require('@ledgerhq/hw-app-btc'); function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; } function _interopNamespace(e) { if (e && e.__esModule) return e; var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n.default = e; return Object.freeze(n); } var bitcash__namespace = /*#__PURE__*/_interopNamespace(bitcash); var bchaddr__namespace = /*#__PURE__*/_interopNamespace(bchaddr); var require$$0__default = /*#__PURE__*/_interopDefault(require$$0); var AppBtc__default = /*#__PURE__*/_interopDefault(AppBtc); /****************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */ function __awaiter(thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); } typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { var e = new Error(message); return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; }; function getDefaultExportFromCjs (x) { return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; } var utils; var hasRequiredUtils; function requireUtils () { if (hasRequiredUtils) return utils; hasRequiredUtils = 1; // baseline estimates, used to improve performance var TX_EMPTY_SIZE = 4 + 1 + 1 + 4; var TX_INPUT_BASE = 32 + 4 + 1 + 4; var TX_INPUT_PUBKEYHASH = 107; var TX_OUTPUT_BASE = 8 + 1; var TX_OUTPUT_PUBKEYHASH = 25; function inputBytes (input) { return TX_INPUT_BASE + (input.script ? input.script.length : TX_INPUT_PUBKEYHASH) } function outputBytes (output) { return TX_OUTPUT_BASE + (output.script ? output.script.length : TX_OUTPUT_PUBKEYHASH) } function dustThreshold (output, feeRate) { /* ... classify the output for input estimate */ return inputBytes({}) * feeRate } function transactionBytes (inputs, outputs) { return TX_EMPTY_SIZE + inputs.reduce(function (a, x) { return a + inputBytes(x) }, 0) + outputs.reduce(function (a, x) { return a + outputBytes(x) }, 0) } function uintOrNaN (v) { if (typeof v !== 'number') return NaN if (!isFinite(v)) return NaN if (Math.floor(v) !== v) return NaN if (v < 0) return NaN return v } function sumForgiving (range) { return range.reduce(function (a, x) { return a + (isFinite(x.value) ? x.value : 0) }, 0) } function sumOrNaN (range) { return range.reduce(function (a, x) { return a + uintOrNaN(x.value) }, 0) } var BLANK_OUTPUT = outputBytes({}); function finalize (inputs, outputs, feeRate) { var bytesAccum = transactionBytes(inputs, outputs); var feeAfterExtraOutput = feeRate * (bytesAccum + BLANK_OUTPUT); var remainderAfterExtraOutput = sumOrNaN(inputs) - (sumOrNaN(outputs) + feeAfterExtraOutput); // is it worth a change output? if (remainderAfterExtraOutput > dustThreshold({}, feeRate)) { outputs = outputs.concat({ value: remainderAfterExtraOutput }); } var fee = sumOrNaN(inputs) - sumOrNaN(outputs); if (!isFinite(fee)) return { fee: feeRate * bytesAccum } return { inputs: inputs, outputs: outputs, fee: fee } } utils = { dustThreshold: dustThreshold, finalize: finalize, inputBytes: inputBytes, outputBytes: outputBytes, sumOrNaN: sumOrNaN, sumForgiving: sumForgiving, transactionBytes: transactionBytes, uintOrNaN: uintOrNaN }; return utils; } var accumulative$1; var hasRequiredAccumulative; function requireAccumulative () { if (hasRequiredAccumulative) return accumulative$1; hasRequiredAccumulative = 1; var utils = requireUtils(); // add inputs until we reach or surpass the target value (or deplete) // worst-case: O(n) accumulative$1 = function accumulative (utxos, outputs, feeRate) { if (!isFinite(utils.uintOrNaN(feeRate))) return {} var bytesAccum = utils.transactionBytes([], outputs); var inAccum = 0; var inputs = []; var outAccum = utils.sumOrNaN(outputs); for (var i = 0; i < utxos.length; ++i) { var utxo = utxos[i]; var utxoBytes = utils.inputBytes(utxo); var utxoFee = feeRate * utxoBytes; var utxoValue = utils.uintOrNaN(utxo.value); // skip detrimental input if (utxoFee > utxo.value) { if (i === utxos.length - 1) return { fee: feeRate * (bytesAccum + utxoBytes) } continue } bytesAccum += utxoBytes; inAccum += utxoValue; inputs.push(utxo); var fee = feeRate * bytesAccum; // go again? if (inAccum < outAccum + fee) continue return utils.finalize(inputs, outputs, feeRate) } return { fee: feeRate * bytesAccum } }; return accumulative$1; } var accumulativeExports = requireAccumulative(); var accumulative = /*@__PURE__*/getDefaultExportFromCjs(accumulativeExports); /** * Lower bound for transaction fee rate. */ const LOWER_FEE_BOUND = 1; /** * Upper bound for transaction fee rate. */ const UPPER_FEE_BOUND = 500; /** * Decimal places for Bitcoin Cash. */ const BCH_DECIMAL = 8; /** * Chain identifier for Bitcoin Cash. */ const BCHChain = 'BCH'; /** * Base "chain" asset on Bitcoin Cash mainnet. * Defined according to Thorchain's asset structure. * @see https://gitlab.com/thorchain/thornode/-/blob/master/common/asset.go#L12-24 */ const AssetBCH = { chain: BCHChain, symbol: 'BCH', ticker: 'BCH', type: xchainUtil.AssetType.NATIVE }; /** * Explorer provider URLs for Bitcoin Cash. */ const BCH_MAINNET_EXPLORER = new xchainClient.ExplorerProvider('https://www.blockchain.com/bch/', 'https://www.blockchain.com/bch/address/%%ADDRESS%%', 'https://www.blockchain.com/bch/tx/%%TX_ID%%'); const BCH_TESTNET_EXPLORER = new xchainClient.ExplorerProvider('https://www.blockchain.com/bch-testnet/', 'https://www.blockchain.com/bch-testnet/address/%%ADDRESS%%', 'https://www.blockchain.com/bch-testnet/tx/%%TX_ID%%'); const explorerProviders = { [xchainClient.Network.Testnet]: BCH_TESTNET_EXPLORER, [xchainClient.Network.Stagenet]: BCH_MAINNET_EXPLORER, [xchainClient.Network.Mainnet]: BCH_MAINNET_EXPLORER, }; /** * Haskoin data providers for Bitcoin Cash. */ const testnetHaskoinProvider = new xchainUtxoProviders.HaskoinProvider('https://api.haskoin.com', BCHChain, AssetBCH, 8, xchainUtxoProviders.HaskoinNetwork.BCHTEST); const mainnetHaskoinProvider = new xchainUtxoProviders.HaskoinProvider('https://haskoin.ninerealms.com', BCHChain, AssetBCH, 8, xchainUtxoProviders.HaskoinNetwork.BCH); const HaskoinDataProviders = { [xchainClient.Network.Testnet]: testnetHaskoinProvider, [xchainClient.Network.Stagenet]: mainnetHaskoinProvider, [xchainClient.Network.Mainnet]: mainnetHaskoinProvider, }; /** * Bitgo data providers for Bitcoin Cash. */ const mainnetBitgoProvider = new xchainUtxoProviders.BitgoProvider({ baseUrl: 'https://app.bitgo.com', chain: BCHChain, }); const BitgoProviders = { [xchainClient.Network.Testnet]: undefined, [xchainClient.Network.Stagenet]: mainnetBitgoProvider, [xchainClient.Network.Mainnet]: mainnetBitgoProvider, }; var safeBuffer = {exports: {}}; /*! safe-buffer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */ var hasRequiredSafeBuffer; function requireSafeBuffer () { if (hasRequiredSafeBuffer) return safeBuffer.exports; hasRequiredSafeBuffer = 1; (function (module, exports) { /* eslint-disable node/no-deprecated-api */ var buffer = require$$0__default.default; var Buffer = buffer.Buffer; // alternative to using Object.keys for old browsers function copyProps (src, dst) { for (var key in src) { dst[key] = src[key]; } } if (Buffer.from && Buffer.alloc && Buffer.allocUnsafe && Buffer.allocUnsafeSlow) { module.exports = buffer; } else { // Copy properties from require('buffer') copyProps(buffer, exports); exports.Buffer = SafeBuffer; } function SafeBuffer (arg, encodingOrOffset, length) { return Buffer(arg, encodingOrOffset, length) } SafeBuffer.prototype = Object.create(Buffer.prototype); // Copy static methods from Buffer copyProps(Buffer, SafeBuffer); SafeBuffer.from = function (arg, encodingOrOffset, length) { if (typeof arg === 'number') { throw new TypeError('Argument must not be a number') } return Buffer(arg, encodingOrOffset, length) }; SafeBuffer.alloc = function (size, fill, encoding) { if (typeof size !== 'number') { throw new TypeError('Argument must be a number') } var buf = Buffer(size); if (fill !== undefined) { if (typeof encoding === 'string') { buf.fill(fill, encoding); } else { buf.fill(fill); } } else { buf.fill(0); } return buf }; SafeBuffer.allocUnsafe = function (size) { if (typeof size !== 'number') { throw new TypeError('Argument must be a number') } return Buffer(size) }; SafeBuffer.allocUnsafeSlow = function (size) { if (typeof size !== 'number') { throw new TypeError('Argument must be a number') } return buffer.SlowBuffer(size) }; } (safeBuffer, safeBuffer.exports)); return safeBuffer.exports; } /* info from: https://github.com/Bitcoin-ABC/bitcoin-abc/blob/master/src/chainparams.cpp */ var bch; var hasRequiredBch; function requireBch () { if (hasRequiredBch) return bch; hasRequiredBch = 1; var common = { name: 'BitcoinCash', per1: 1e8, unit: 'BCH' }; var main = Object.assign({}, { hashGenesisBlock: '000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f', // nDefaultPort port: 8333, portRpc: 8332, protocol: { // pchMessageStart magic: 0xe8f3e1e3 // careful, sent over wire as little endian }, // vSeeds seedsDns: [ 'seed.bitcoinabc.org', 'seed-abc.bitcoinforks.org', 'btccash-seeder.bitcoinunlimited.info', 'seed.bitprim.org', 'seed.deadalnix.me', 'seeder.criptolayer.net' ], // base58Prefixes versions: { bip32: { private: 0x0488ade4, public: 0x0488b21e }, bip44: 145, private: 0x80, public: 0x00, scripthash: 0x05 } }, common); var test = Object.assign({}, { hashGenesisBlock: '000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943', port: 18333, portRpc: 18332, protocol: { magic: 0xf4f3e5f4 }, seedsDns: [ 'testnet-seed.bitcoinabc.org', 'testnet-seed-abc.bitcoinforks.org', 'testnet-seed.bitprim.org', 'testnet-seed.deadalnix.me', 'testnet-seeder.criptolayer.net' ], versions: { bip32: { private: 0x04358394, public: 0x043587cf }, bip44: 1, private: 0xef, public: 0x6f, scripthash: 0xc4 } }, common); var regtest = Object.assign({}, { hashGenesisBlock: '0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206', port: 18444, portRpc: 18332, protocol: { magic: 0xfabfb5da }, seedsDns: [], versions: { bip32: { private: 0x04358394, public: 0x043587cf }, bip44: 1, private: 0xef, public: 0x6f, scripthash: 0xc4 } }, common); bch = { main: main, test: test, regtest: regtest }; return bch; } /* info from: https://github.com/rat4/blackcoin/blob/master/src/chainparams.cpp */ var blk; var hasRequiredBlk; function requireBlk () { if (hasRequiredBlk) return blk; hasRequiredBlk = 1; var common = { name: 'BlackCoin', per1: 1e8, unit: 'BLK' }; var main = Object.assign({}, { hashGenesisBlock: '000001faef25dec4fbcf906e6242621df2c183bf232f263d0ba5b101911e4563', port: 15714, portRpc: 15715, protocol: { magic: 0x05223570 // careful, sent over wire as little endian }, seedsDns: [ 'rat4.blackcoin.co', 'seed.blackcoin.co', 'archon.darkfox.id.au', 'foxy.seeds.darkfox.id.au', '6.syllabear.us.to', 'bcseed.syllabear.us.to' ], versions: { bip32: { private: 0x0488ade4, public: 0x0488b21e }, bip44: 0xa, private: 0x99, public: 0x19, scripthash: 0x55 } }, common); blk = { main: main, test: null }; return blk; } /* info from: https://github.com/bitcoin/bitcoin/blob/master/src/chainparams.cpp */ var btc; var hasRequiredBtc; function requireBtc () { if (hasRequiredBtc) return btc; hasRequiredBtc = 1; var common = { name: 'Bitcoin', per1: 1e8, unit: 'BTC', messagePrefix: '\x18Bitcoin Signed Message:\n' }; var main = Object.assign({}, { hashGenesisBlock: '000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f', // nDefaultPort port: 8333, portRpc: 8332, protocol: { // pchMessageStart magic: 0xd9b4bef9 // careful, sent over wire as little endian }, bech32: 'bc', // vSeeds seedsDns: [ 'seed.bitcoin.sipa.be', 'dnsseed.bluematt.me', 'seed.bitcoinstats.com', 'seed.bitcoin.jonasschnelli.ch', 'seed.btc.petertodd.org', 'seed.bitcoin.sprovoost.nl', 'dnsseed.emzy.de' ], // base58Prefixes versions: { bip32: { private: 0x0488ade4, public: 0x0488b21e }, bip44: 0, private: 0x80, public: 0x00, scripthash: 0x05 } }, common); var test = Object.assign({}, { hashGenesisBlock: '000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943', port: 18333, portRpc: 18332, protocol: { magic: 0x0709110b }, bech32: 'tb', seedsDns: [ 'testnet-seed.alexykot.me', 'testnet-seed.bitcoin.schildbach.de', 'testnet-seed.bitcoin.petertodd.org', 'testnet-seed.bluematt.me' ], versions: { bip32: { private: 0x04358394, public: 0x043587cf }, bip44: 1, private: 0xef, public: 0x6f, scripthash: 0xc4 } }, common); var regtest = Object.assign({}, { hashGenesisBlock: '0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206', port: 18444, portRpc: 18332, protocol: { magic: 0xdab5bffa }, bech32: 'bcrt', seedsDns: [], versions: { bip32: { private: 0x04358394, public: 0x043587cf }, bip44: 1, private: 0xef, public: 0x6f, scripthash: 0xc4 } }, common); btc = { main: main, test: test, regtest: regtest }; return btc; } /* info from: https://github.com/BTCGPU/BTCGPU/blob/master/src/chainparams.cpp */ var btg; var hasRequiredBtg; function requireBtg () { if (hasRequiredBtg) return btg; hasRequiredBtg = 1; var common = { name: 'Bitcoin Gold', unit: 'BTG' }; var main = Object.assign({}, { hashGenesisBlock: '000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f', // nDefaultPort port: 8338, protocol: { // pchMessageStart magic: 0x446d47e1 // careful, sent over wire as little endian }, bech32: 'btg', // vSeeds seedsDns: [ 'eu-dnsseed.bitcoingold-official.org', 'dnsseed.bitcoingold.org', 'dnsseed.btcgpu.org' ], // base58Prefixes versions: { bip32: { private: 0x0488ade4, public: 0x0488b21e }, bip44: 156, private: 0x80, public: 0x26, scripthash: 0x17 } }, common); var test = Object.assign({}, { hashGenesisBlock: '0x00000000e0781ebe24b91eedc293adfea2f557b53ec379e78959de3853e6f9f6', port: 18338, portRpc: 18332, protocol: { magic: 0x456e48e2 }, bech32: 'tbtg', seedsDns: [ 'test-dnsseed.bitcoingold.org', 'test-dnsseed.btcgpu.org', 'eu-test-dnsseed.bitcoingold-official.org' ], versions: { bip32: { private: 0x04358394, public: 0x043587cf }, bip44: 156, private: 0xef, public: 0x6f, scripthash: 0xc4 } }, common); btg = { main: main, test: test }; return btg; } /* info from: https://github.com/dashpay/dash/blob/master/src/chainparams.cpp */ var dash; var hasRequiredDash; function requireDash () { if (hasRequiredDash) return dash; hasRequiredDash = 1; var common = { name: 'Dash', unit: 'DASH' }; var main = Object.assign({}, { hashGenesisBlock: '00000ffd590b1485b3caadc19b22e6379c733355108f107a430458cdf3407ab6', // nDefaultPort port: 9999, portRpc: 9998, protocol: { magic: 0xbd6b0cbf // careful, sent over wire as little endian }, // vSeeds seedsDns: [ 'dash.org', 'dnsseed.dash.org', 'dashdot.io', 'dnsseed.dashdot.io', 'masternode.io', 'dnsseed.masternode.io', 'dashpay.io', 'dnsseed.dashpay.io' ], // base58Prefixes versions: { bip32: { private: 0x0488ade4, public: 0x0488b21e }, bip44: 5, private: 0xcc, public: 0x4c, scripthash: 0x10 } }, common); var test = Object.assign({}, { hashGenesisBlock: '00000bafbc94add76cb75e2ec92894837288a481e5c005f6563d91623bf8bc2c', port: 19999, portRpc: 19998, seedsDns: [ 'dashdot.io', 'testnet-seed.dashdot.io', 'masternode.io', 'test.dnsseed.masternode.io' ], versions: { bip32: { private: 0x04358394, public: 0x043587cf }, bip44: 1, private: 0xef, public: 0x8c, scripthash: 0x13 } }, common); dash = { main: main, test: test }; return dash; } var dcr; var hasRequiredDcr; function requireDcr () { if (hasRequiredDcr) return dcr; hasRequiredDcr = 1; var common = { name: 'Decred', unit: 'DCR' }; // https://github.com/decred/dcrd/blob/ef71103c95cbf77e5a0418e3d413b5906e710b25/chaincfg/params.go // https://github.com/decred/bitcore/blob/a92381b2b0023b28a1b7eb03e6cb0bfb7800200d/lib/networks.js var main = Object.assign({}, { hashGenesisBlock: '298e5cc3d985bfe7f81dc135f360abe089edd4396b86d2de66b0cef42b21d980', port: 9108, portRpc: 9109, protocol: { magic: 0xf900b4d9 }, seedsDns: [ 'mainnet-seed.decred.mindcry.org', 'mainnet-seed.decred.netpurgatory.com', 'mainnet.decredseed.org', 'mainnet-seed.decred.org' ], versions: { bip32: { private: 0x02fda4e8, public: 0x02fda926 }, bip44: 42, private: 0x22de, public: 0x073f, scripthash: 0x071a } }, common); var test = Object.assign({}, { hashGenesisBlock: '5b7466edf6739adc9b32aaedc54e24bdc59a05f0ced855088835fe3cbe58375f', port: 19108, portRpc: 19109, protocol: { magic: 0x48e7a065 }, seedsDns: [ 'testnet-seed.decred.mindcry.org', 'testnet-seed.decred.netpurgatory.org', 'testnet.decredseed.org', 'testnet-seed.decred.org' ], versions: { bip32: { private: 0x04358397, public: 0x043587d1 }, bip44: 42, private: 0x230e, public: 0x0f21, scripthash: 0x0efc } }, common); dcr = { main: main, test: test }; return dcr; } /* info from: https://github.com/digibyte/digibyte/blob/9e4c0b3ddfd10a7ab852240ff716a7b93af89a07/src/chainparams.cpp */ var dgb; var hasRequiredDgb; function requireDgb () { if (hasRequiredDgb) return dgb; hasRequiredDgb = 1; var common = { name: 'DigiByte', per1: 1e8, unit: 'DGB' }; var main = Object.assign({}, { hashGenesisBlock: '000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f', // nDefaultPort port: 12024, portRpc: 14022, protocol: { // pchMessageStart magic: 0xfac3b6da // careful, sent over wire as little endian }, bech32: 'dgb', // vSeeds seedsDns: [ 'seed.digibyte.io', 'digiexplorer.info', 'digihash.co' ], // base58Prefixes versions: { bip44: 0x80000014, private: 0x80, public: 0x1e, scripthash: 0x3f, // new 'S' prefix scripthash2: 0x05 // old '3' prefix } }, common); dgb = { main: main }; return dgb; } var doge; var hasRequiredDoge; function requireDoge () { if (hasRequiredDoge) return doge; hasRequiredDoge = 1; // https://github.com/dogecoin/dogecoin/blob/master/src/chainparams.cpp var common = { name: 'Dogecoin', unit: 'DOGE' }; var main = Object.assign({}, { hashGenesisBlock: '1a91e3dace36e2be3bf030a65679fe821aa1d6ef92e7c9902eb318182c355691', port: 22556, protocol: { magic: 0xc0c0c0c0 }, seedsDns: [ 'seed.dogecoin.com', 'seed.multidoge.org', 'seed2.multidoge.org', 'seed.doger.dogecoin.com' ], versions: { bip32: { private: 0x02fac398, public: 0x02facafd }, bip44: 3, private: 0x9e, public: 0x1e, scripthash: 0x16 } }, common); var test = Object.assign({}, { hashGenesisBlock: 'bb0a78264637406b6360aad926284d544d7049f45189db5664f3c4d07350559e', versions: { bip44: 1, private: 0xf1, public: 0x71, scripthash: 0xc4 } }, common); doge = { main: main, test: test }; return doge; } var ltc; var hasRequiredLtc; function requireLtc () { if (hasRequiredLtc) return ltc; hasRequiredLtc = 1; // https://github.com/litecoin-project/litecoin/blob/master-0.10/src/chainparams.cpp var common = { name: 'Litecoin', unit: 'LTC' }; var main = Object.assign({}, { hashGenesisBlock: '12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2', port: 9333, protocol: { magic: 0xdbb6c0fb }, bech32: 'ltc', seedsDns: [ 'dnsseed.litecointools.com', 'dnsseed.litecoinpool.org', 'dnsseed.ltc.xurious.com', 'dnsseed.koin-project.com', 'dnsseed.weminemnc.com' ], versions: { bip32: { private: 0x019d9cfe, public: 0x019da462 }, bip44: 2, private: 0xb0, public: 0x30, scripthash: 0x32, scripthash2: 0x05 // old '3' prefix. available for backward compatibility. } }, common); var test = Object.assign({}, { hashGenesisBlock: 'f5ae71e26c74beacc88382716aced69cddf3dffff24f384e1808905e0188f68f', bech32: 'tltc', versions: { bip32: { private: 0x0436ef7d, public: 0x0436f6e1 }, bip44: 1, private: 0xef, public: 0x6f, scripthash: 0x3a, scripthash2: 0xc4 } }, common); ltc = { main: main, test: test }; return ltc; } var via; var hasRequiredVia; function requireVia () { if (hasRequiredVia) return via; hasRequiredVia = 1; // https://github.com/viacoin/viacoin/blob/master/src/chainparams.cpp var common = { name: 'Viacoin', unit: 'VIA' }; var main = Object.assign({}, { hashGenesisBlock: '4e9b54001f9976049830128ec0331515eaabe35a70970d79971da1539a400ba1', port: 5223, protocol: { magic: 0xcbc6680f }, seedsDns: [ 'seed.viacoin.net', 'viaseeder.barbatos.fr', 'mainnet.viacoin.net' ], versions: { bip32: { private: 0x0488ade4, public: 0x0488b21e }, bip44: 14, private: 0xc7, public: 0x47, scripthash: 0x21 } }, common); var test = Object.assign({}, { hashGenesisBlock: '770aa712aa08fdcbdecc1c8df1b3e2d4e17a7cf6e63a28b785b32e74c96cb27d', port: 25223, protocol: { magic: 0x92efc5a9 }, seedsDns: [ 'testnet.viacoin.net', 'seed-testnet.viacoin.net' ], versions: { bip32: { private: 0x04358394, public: 0x043587cf }, bip44: 1, private: 0xff, public: 0x7f, scripthash: 0xc4 } }, common); via = { main: main, test: test }; return via; } var mona; var hasRequiredMona; function requireMona () { if (hasRequiredMona) return mona; hasRequiredMona = 1; // https://github.com/monacoinproject/monacoin/blob/master-0.13/src/chainparams.cpp var common = { name: 'Monacoin', unit: 'MONA' }; var main = Object.assign({}, { hashGenesisBlock: 'ff9f1c0116d19de7c9963845e129f9ed1bfc0b376eb54fd7afa42e0d418c8bb6', port: 9401, portRpc: 9402, protocol: { magic: 0xdbb6c0fb }, bech32: 'mona', seedsDns: [ 'dnsseed.monacoin.org' ], versions: { bip32: { private: 0x0488ade4, public: 0x0488b21e }, bip44: 22, private: 0xb0, private2: 0xb2, // old wif public: 0x32, scripthash: 0x37, scripthash2: 0x05 // old '3' prefix. available for backward compatibility. } }, common); var test = Object.assign({}, { hashGenesisBlock: 'a2b106ceba3be0c6d097b2a6a6aacf9d638ba8258ae478158f449c321061e0b2', port: 19403, portRpc: 19402, protocol: { magic: 0xf1c8d2fd }, bech32: 'tmona', seedsDns: [ 'testnet-dnsseed.monacoin.org' ], versions: { bip32: { private: 0x04358394, public: 0x043587cf }, bip44: 1, private: 0xef, public: 0x6f, scripthash: 0x75, scripthash2: 0xc4 } }, common); mona = { main: main, test: test }; return mona; } var nbt; var hasRequiredNbt; function requireNbt () { if (hasRequiredNbt) return nbt; hasRequiredNbt = 1; var common = { name: 'NuBits', per1: 1e6, unit: 'NBT' }; var main = Object.assign({}, { hashGenesisBlock: '000003cc2da5a0a289ad0a590c20a8b975219ddc1204efd169e947dd4cbad73f', // nDefaultPort port: 7890, portRpc: 14002, protocol: { // pchMessageStart magic: 0xd9b4bef9 // careful, sent over wire as little endian }, // vSeeds seedsDns: [ ], // base58Prefixes versions: { bip32: { private: 0x0488ade4, public: 0x0488b21e }, bip44: 12, private: 0x96, public: 0x19, scripthash: 0x1a } }, common); nbt = { main: main }; return nbt; } var nmc; var hasRequiredNmc; function requireNmc () { if (hasRequiredNmc) return nmc; hasRequiredNmc = 1; var common = { name: 'Namecoin', unit: 'NMC' }; var main = Object.assign({}, { hashGenesisBlock: '000000000062b72c5e2ceb45fbc8587e807c155b0da735e6483dfba2f0a9c770', versions: { bip44: 7, private: 0xb4, public: 0x34, scripthash: 0x05 } }, common); nmc = { main: main, test: null }; return nmc; } var ppc; var hasRequiredPpc; function requirePpc () { if (hasRequiredPpc) return ppc; hasRequiredPpc = 1; // https://github.com/peercoin/peercoin/tree/v0.7.0ppc/src // https://github.com/peercoin/peercoin/blob/v0.7.0ppc/src/${filename} var common = { name: 'Peercoin', per1: 1e6, // util.h:40 unit: 'PPC', messagePrefix: '\x18Peercoin Signed Message:\n' // main.cpp:77 }; var main = Object.assign({}, { hashGenesisBlock: '0000000032fe677166d54963b62a4677d8957e87c508eaa4fd7eb1c880cd27e3', // main.h:84 // nDefaultPort port: 9901, // protocol.h:18 portRpc: 9902, // protocol.h:19 protocol: { // pchMessageStart magic: 0xe5e9e8e6 // careful, sent over wire as little endian protocol.cpp:31 }, // vSeeds seedsDns: [ // net.cpp:1209 'seed.peercoin.net', 'seed2.peercoin.net', 'seed.peercoin-library.org', 'ppcseed.ns.7server.net' ], versions: { // not implemented in Peercoin <= v0.7.x nodes, only 3rd party wallets // https://github.com/jmacwhyte/recovery-phrase-recovery/blob/52073aba08e9d01032c0b5aff8c682911fe2e5fc/js/bitcoinjs-extensions.js#L58 bip32: { private: 0x0488ade4, public: 0x0488b21e }, bip44: 6, // https://github.com/satoshilabs/slips/blob/master/slip-0044.md private: 0xb7, // base58.h:402 ; 128 + PUBKEY_ADDRESS public: 0x37, // base58.h:276 scripthash: 0x75 // base58.h:277 } }, common); var test = Object.assign({}, { hashGenesisBlock: '00000001f757bb737f6596503e17cd17b0658ce630cc727c0cca81aec47c9f06', port: 9903, portRpc: 9904, protocol: { magic: 0xefc0f2cb }, seedsDns: [ 'tseed.peercoin.net', 'tseed2.peercoin.net', 'tseed.peercoin-library.org' ], versions: { bip32: { private: 0x04358394, public: 0x043587cf }, bip44: 1, private: 0xef, public: 0x6f, scripthash: 0xc4 } }, common); ppc = { main: main, test: test }; return ppc; } /* info from: https://github.com/qtumproject/qtum/blob/master/src/chainparams.cpp */ var qtum; var hasRequiredQtum; function requireQtum () { if (hasRequiredQtum) return qtum; hasRequiredQtum = 1; var common = { name: 'Qtum', unit: 'QTUM' }; var main = Object.assign({}, { hashGenesisBlock: '000075aef83cf2853580f8ae8ce6f8c3096cfa21d98334d6e3f95e5582ed986c', // nDefaultPort port: 3888, protocol: { // pchMessageStart magic: 0xd3a6cff1 // careful, sent over wire as little endian }, bech32: 'qc', // vSeeds seedsDns: [ 'qtum3.dynu.net' ], // base58Prefixes versions: { bip32: { private: 0x0488ade4, public: 0x0488b21e }, bip44: 2301, private: 0x80, public: 0x3A, scripthash: 0x32 } }, common); qtum = { main: main }; return qtum; } var rvn; var hasRequiredRvn; function requireRvn () { if (hasRequiredRvn) return rvn; hasRequiredRvn = 1; // https://github.com/RavenProject/Ravencoin/blob/master/src/chainparams.cpp var common = { name: 'Ravencoin', unit: 'RVN' }; var main = Object.assign({}, { hashGenesisBlock: '0000006b444bc2f2ffe627be9d9e7e7a0730000870ef6eb6da46c8eae389df90', port: 8767, protocol: { magic: 0x4e564152 }, seedsDns: [ 'seed-raven.bitactivate.com', 'seed-raven.ravencoin.com', 'seed-raven.ravencoin.org' ], versions: { bip32: { private: 0x0488ade4, public: 0x0488b21e }, bip44: 175, private: 0x80, public: 0x3c, scripthash: 0x7a } }, common); var test = Object.assign({}, { hashGenesisBlock: '000000ecfc5e6324a079542221d00e10362bdc894d56500c414060eea8a3ad5a', port: 18770, protocol: { magic: 0x544e5652 }, seedsDns: [ 'seed-testnet-raven.bitactivate.com', 'seed-testnet-raven.ravencoin.com', 'seed-testnet-raven.ravencoin.org' ], versions: { bip32: { private: 0x04358394, public: 0x043587cf }, bip44: 1, private: 0xef, public: 0x6f, scripthash: 0xc4 } }, common); rvn = { main: main, test: test }; return rvn; } var rdd; var hasRequiredRdd; function requireRdd () { if (hasRequiredRdd) return rdd; hasRequiredRdd = 1; var common = { name: 'ReddCoin', unit: 'RDD' }; var main = Object.assign({}, { hashGenesisBlock: 'b868e0d95a3c3c0e0dadc67ee587aaf9dc8acbf99e3b4b3110fad4eb74c1decc', versions: { bip44: 4, private: 0xbd, public: 0x3d, scripthash: 0x05 } }, common); var test = Object.assign({}, { hashGenesisBlock: 'a12ac9bd4cd26262c53a6277aafc61fe9dfe1e2b05eaa1ca148a5be8b394e35a', versions: { bip44: 1, private: 0xef, public: 0x6f, scripthash: 0xc4 } }, common); rdd = { main: main, test: test }; return rdd; } /* info from: https://github.com/vertcoin/vertcoin/blob/master/src/chainparams.cpp */ var vtc; var hasRequiredVtc; function requireVtc () { if (hasRequiredVtc) return vtc; hasRequiredVtc = 1; var common = { name: 'Vertcoin', unit: 'VTC' }; var main = Object.assign({}, { hashGenesisBlock: '4d96a915f49d40b1e5c2844d1ee2dccb90013a990ccea12c492d22110489f0c4', // nDefaultPort port: 5889, protocol: { // pchMessageStart magic: 0xdab5bffa // careful, sent over wire as little endian }, bech32: 'vtc', // vSeeds seedsDns: [ 'useast1.vtconline.org', 'vtc.gertjaap.org', 'seed.vtc.bryangoodson.org', 'dnsseed.pknight.ca', 'seed.orderofthetaco.org', 'seed.alexturek.org', 'vertcoin.mbl.cash' ], // base58Prefixes versions: { bip32: { private: 0x0488ade4, public: 0x0488b21e }, bip44: 28, private: 0x80, public: 0x47, scripthash: 0x05 } }, common); var test = Object.assign({}, { hashGenesisBlock: 'cee8f24feb7a64c8f07916976aa4855decac79b6741a8ec2e32e2747497ad2c9', port: 15889, // portRpc: 18332, protocol: { magic: 0x74726576 }, bech32: 'tvtc', seedsDns: [ 'jlovejoy.mit.edu', 'gertjaap.ddns.net', 'fr1.vtconline.org', 'tvtc.vertcoin.org' ], versions: { bip32: { private: 0x04358394, public: 0x043587cf }, private: 0xef, public: 0x4a, scripthash: 0xc4 } }, common); var regtest = Object.assign({}, { hashGenesisBlock: '0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206', port: 18444, // portRpc: 18332, protocol: { magic: 0xdab5bffa }, seedsDns: [], versions: { bip32: { private: 0x04358394, public: 0x043587cf }, private: 0xef, public: 0x6f, scripthash: 0xc4 } }, common); vtc = { main: main, test: test, regtest: regtest }; return vtc; } /* info from: https://github.com/zcash/zcash/blob/v1.0.12/src/chainparamsbase.cpp https://github.com/zcash/zcash/blob/v1.0.12/src/chainparams.cpp */ var zec; var hasRequiredZec; function requireZec () { if (hasRequiredZec) return zec; hasRequiredZec = 1; var common = { name: 'Zcash', unit: 'ZEC' }; var main = Object.assign({}, { hashGenesisBlock: '00040fe8ec8471911baa1db1266ea15dd06b4a8a5c453883c000b031973dce08', // nDefaultPort port: 8233, portRpc: 8232, protocol: { // pchMessageStart magic: 0x6427e924 // careful, sent over wire as little endian }, // vSeeds seedsDns: [ 'dnsseed.z.cash', 'dnsseed.str4d.xyz', 'dnsseed.znodes.org' ], // base58Prefixes versions: { bip32: { private: 0x0488ade4, public: 0x0488b21e }, bip44: 133, private: 0x80, public: 0x1cb8, scripthash: 0x1cbd } }, common); var test = Object.assign({}, { hashGenesisBlock: '0x05a60a92d99d85997cce3b87616c089f6124d7342af37106edc76126334a2c38', port: 18233, portRpc: 18232, protocol: { magic: 0xbff91afa }, seedsDns: [ 'dnsseed.testnet.z.cash' ], versions: { bip32: { private: 0x04358394, public: 0x043587cf }, bip44: 133, private: 0xef, public: 0x1d25, scripthash: 0x1cba } }, common); zec = { main: main, test: test }; return zec; } var coininfo_1; var hasRequiredCoininfo; function requireCoininfo () { if (hasRequiredCoininfo) return coininfo_1; hasRequiredCoininfo = 1; var Buffer = requireSafeBuffer().Buffer; // annoyingly, this is for browserify var coins = [ requireBch(), requireBlk(), requireBtc(), requireBtg(), requireDash(), requireDcr(), requireDgb(), requireDoge(), requireLtc(), requireVia(), requireMona(), requireNbt(), requireNmc(), requirePpc(), requireQtum(), requireRvn(), requireRdd(), requireVtc(), requireZec() ]; var supportedCoins = {}; coins.forEach(function (coin) { var unit = coin.main.unit.toLowerCase(); var name = coin.main.name.toLowerCase(); coin.main.testnet = false; coin.main.toBitcoinJS = toBitcoinJS.bind(coin.main); coin.main.toBitcore = toBitcore.bind(coin.main); supportedCoins[unit] = coin.main; supportedCoins[name] = coin.main; if (coin.test) { coin.test.testnet = true; coin.test.toBitcoinJS = toBitcoinJS.bind(coin.test); coin.test.toBitcore = toBitcore.bind(coin.test); supportedCoins[unit + '-test'] = coin.test; supportedCoins[name + '-test'] = coin.test; } if (coin.regtest) { coin.regtest.testnet = true; coin.regtest.toBitcoinJS = toBitcoinJS.bind(coin.regtest); coin.regtest.toBitcore = toBitcore.bind(coin.regtest); supportedCoins[unit + '-regtest'] = coin.regtest; supportedCoins[name + '-regtest'] = coin.regtest; } }); function coininfo (input) { var coin = input.toLowerCase(); if (!(coin in supportedCoins)) { return null } else { return supportedCoins[coin] } } coins.forEach(function (coin) { coininfo[coin.main.name.toLowerCase()] = coin; }); function toBitcoinJS () { return Object.assign({}, this, { messagePrefix: this.messagePrefix || ('\x19' + this.name + ' Signed Message:\n'), bech32: this.bech32, bip32: { public: (this.versions.bip32 || {}).public, private: (this.versions.bip32 || {}).private }, pubKeyHash: this.versions.public, scriptHash: this.versions.scripthash, wif: this.versions.private, dustThreshold: null // TODO }) } function toBitcore () { // reverse magic var nm = Buffer.allocUnsafe(4); nm.writeUInt32BE(this.protocol ? this.protocol.magic : 0, 0); nm = nm.readUInt32LE(0); return Object.assign({}, this, { name: this.testnet ? 'testnet' : 'livenet', alias: this.testnet ? 'testnet' : 'mainnet', pubkeyhash: this.versions.public, privatekey: this.versions.private, scripthash: this.versions.scripthash, xpubkey: (this.versions.bip32 || {}).public, xprivkey: (this.versions.bip32 || {}).private, networkMagic: nm, port: this.port, dnsSeeds: this.seedsDns || [] }) } coininfo_1 = coininfo; return coininfo_1; } var coininfoExports = requireCoininfo(); var coininfo = /*@__PURE__*/getDefaultExportFromCjs(coininfoExports); /** * Module importing and providing utilities for Bitcoin Cash (BCH) transactions and addresses. */ /** * Size constants for BCH transactions. */ const TX_EMPTY_SIZE = 4 + 1 + 1 + 4; const TX_INPUT_BASE = 32 + 4 + 1 + 4; const TX_INPUT_PUBKEYHASH = 107; const TX_OUTPUT_BASE = 8 + 1; const TX_OUTPUT_PUBKEYHASH = 25; /** * Retrieves the BCH network to be used with bitcore-lib. * @param {Network} network The network type. * @returns {BCHNetwork} The BCH network. */ const bchNetwork = (network) => { switch (network) { case xchainClient.Network.Mainnet: case xchainClient.Network.Stagenet: return coininfo.bitcoincash.main.toBitcoinJS(); case xchainClient.Network.Testnet: return coininfo.bitcoincash.test.toBitcoinJS(); } }; /** * Retrieves the BCH address prefix. * * @returns {string} The BCH address prefix. */ const getPrefix = () => ''; /** * Strips the BCH address prefix. * @param {Address} address The BCH address. * @returns {Address} The address with the prefix removed. */ const stripPrefix = (address) => address.replace(/(bchtest:|bitcoincash:)/, ''); /** * Converts the BCH address to a legacy address format. * @param {Address} address The BCH address. * @returns {Address} The legacy address. */ const toLegacyAddress = (address) => { return bchaddr__namespace.toLegacyAddress(address); }; /** * Converts the BCH address to a cash address format. * @param {Address} address The BCH address. * @returns {Address} The cash address. */ const toCashAddress = (address) => { return bchaddr__namespace.toCashAddress(address); }; /** * Checks whether the address is a cash address. * @param {Address} address The BCH address. * @returns {boolean} Whether the address is a cash address. */ const isCashAddress = (address) => { return bchaddr__namespace.isCashAddress(address); }; /** * Parses a BCH transaction. * @param {Transaction} tx The BCH transaction. * @returns {Tx} The parsed transaction. */ const parseTransaction = (tx) => { return { asset: AssetBCH, from: tx.inputs .filter((input) => !!input.address) .map((input) => ({ from: stripPrefix(input.address), amount: xchainUtil.baseAmount(input.value, BCH_DECIMAL), })), to: tx.outputs .filter((output) => !!output.address) .map((output) => ({ to: stripPrefix(output.address), amount: xchainUtil.baseAmount(output.value, BCH_DECIMAL), })), date: new Date(tx.time * 1000), type: xchainClient.TxType.Transfer, hash: tx.txid, }; }; /** * Converts the XChain network to a BCH address network. * @param {Network} network The XChain network. * @returns {string} The BCH address network. */ const toBCHAddressNetwork = (network) => { switch (network) { case xchainClient.Network.Mainnet: case xchainClient.Network.Stagenet: return bchaddr__namespace.Network.Mainnet; case xchainClient.Network.Testnet: return bchaddr__namespace.Network.Testnet; } }; /** * Validates the BCH address. * @param {string} address The BCH address. * @param {Network} network The XChain network. * @returns {boolean} Whether the address is valid. */ const validateAddress = (address, network) => { const toAddress = toCashAddress(address); return bchaddr__namespace.isValidAddress(toAddress) && bchaddr__namespace.detectAddressNetwork(toAddress) === toBCHAddressNetwork(network); }; // Default parameters for Bitcoin Cash (BCH) client const defaultBchParams = { network: xchainClient.Network.Mainnet, phrase: '', explorerProviders: explorerProviders, dataProviders: [BitgoProviders, HaskoinDataProviders], rootDerivationPaths: { [xchainClient.Network.Mainnet]: `m/44'/145'/0'/0/`, [xchainClient.Network.Testnet]: `m/44'/1'/0'/0/`, [xchainClient.Network.Stagenet]: `m/44'/145'/0'/0/`, // Default root derivation path for Stagenet }, feeBounds: { lower: LOWER_FEE_BOUND, upper: UPPER_FEE_BOUND, // Default upper fee bound }, }; /** * Custom Bitcoin Cash client class. */ class Client extends xchainUtxo.Client { /** * Constructor for the Client class. * * @param {UtxoClientParams} params - Parameters for initializing the client. */ constructor(params = defaultBchParams) { // Call the constructor of the parent class (UTXOClient) with BCHChain as the chain and provided parameters super(BCHChain, { network: params.network, rootDerivationPaths: params.rootDerivationPaths, phrase: params.phrase, feeBounds: params.feeBounds, explorerProviders: params.explorerProviders, dataProviders: params.dataProviders, }); } /** * Get information about the BCH asset. * @returns Information about the BCH asset. */ getAssetInfo() { const assetInfo = { asset: AssetBCH, decimal: BCH_DECIMAL, // Decimal precision }; return assetInfo; } /** * Validate the given address. * * @param {Address} address * @returns {boolean} `true` or `false` */ validateAddress(address) { return validateAddress(address, this.network); } /** * Build a BCH transaction. * @param {BuildParams} params - The transaction build options. * @returns {Transaction} A promise that resolves with the transaction builder, UTXOs, and inputs. * @deprecated */ buildTx({ amount, recipient, memo, feeRate, sender, }) { return __awaiter(this, void 0, void 0, function* () { // Convert recipient address to CashAddress format const recipientCashAddress = toCashAddress(recipient); // Validate recipient address if (!this.validateAddress(recipientCashAddress)) throw new Error('Invalid address'); // Scan UTXOs for the sender address const utxos = yield this.scanUTXOs(sender, false); // Throw error if no UTXOs are found if (utxos.length === 0) throw new Error('No utxos to send'); // Convert fee rate to a whole number const feeRateWhole = Number(feeRate.toFixed(0)); // Compile memo if provided const compiledMemo = memo ? this.compileMemo(memo) : null; const targetOutputs = []; // Add output amount and recipient to target outputs targetOutputs.push({ address: recipient, value: amount.amount().toNumber(), }); // Calculate transaction inputs and outputs const { inputs, outputs } = accumulative(utxos, targetOutputs, feeRateWhole); // Throw error if no solution is found if (!inputs || !outputs) throw new Error('Insufficient Balance for transaction'); // Initialize a new transaction builder const transactionBuilder = new bitcash__namespace.TransactionBuilder(bchNetwork(this.network)); // Add inputs to the transaction builder inputs.forEach((utxo) => transactionBuilder.addInput(bitcash__namespace.Transaction.fromBuffer(Buffer.from(utxo.txHex || '', 'hex')), utxo.index)); // Add outputs to the transaction builder // eslint-disable-next-line @typescript-eslint/no-explicit-any outputs.forEach((output) => { let out = undefined; if (!output.address) { // An empty address means this is the change address out = bitcash__namespace.address.toOutputScript(toLegacyAddress(sender), bchNetwork(this.network)); } else if (output.address) { out = bitcash__namespace.address.toOutputScript(toLegacyAddress(output.address), bchNetwork(this.network)); } transactionBuilder.addOutput(out, output.value); }); // Add output for memo if compiled if (compiledMemo) { transactionBuilder.addOutput(compiledMemo, 0); // Add OP_RETURN {script, value} } // Return transaction builder, UTXOs, and inputs return { builder: transactionBuilder, utxos, inputs, }; }); } /** * Prepare a BCH transaction. * @param {TxParams&Address&FeeRate} params - The transaction preparation options. * @returns {PreparedTx} A promise that resolves with the prepared transaction and UTXOs. */ prepareTx({ sender, memo, amount, recipient, feeRate, }) { return __awaiter(this, void 0, void 0, function* () { // Build the transaction using provided options const { builder, utxos, inputs } = yield this.buildTx({ sender, recipient, amount, memo, feeRate, }); // Return the raw unsigned transaction and UTXOs return { rawUnsignedTx: builder.buildIncomplete().toHex(), utxos, inputs }; }); } /** * Compile a memo. * @param {string} memo - The memo to be compiled. * @returns {Buffer} - The compiled memo. */ compileMemo(memo) { const data = Buffer.from(memo, 'utf8'); // converts MEMO to buffer return bitcash__namespace.script.compile([bitcash__namespace.opcodes.OP_RETURN, data]); // Compile OP_RETURN script } /** * Calculate the transaction fee. * @param {UTXO[]} inputs - The UTXOs. * @param {FeeRate} feeRate - The fee rate. * @param {Buffer | null} data - The compiled memo (optional). * @returns {number} - The fee amount. */ getFeeFromUtxos(inputs, feeRate, data = null) { let totalWeight = TX_EMPTY_SIZE; totalWeight += (TX_INPUT_PUBKEYHASH + TX_INPUT_BASE) * inputs.length; totalWeight += (TX_OUTPUT_BASE + TX_OUTPUT_PUBKEYHASH) * 2; if (data) { totalWeight += 9 + data.length; } return Math.ceil(totalWeight * feeRate); } } /** * Custom Bitcoin client extended to support keystore functionality */ class ClientKeystore extends Client { /** * @deprecated This function eventually will be removed. Use getAddressAsync instead. * Get the address associated with the given index. * @param {number} index The index of the address. * @returns {Address} The Bitcoin address. * @t