From e72afd758e08763657190ccb93c19ed732a2bab1 Mon Sep 17 00:00:00 2001 From: junderw Date: Sat, 14 Sep 2019 07:15:59 +0900 Subject: [PATCH] Update to BitcoinJS 5.1.6 --- BlueElectrum.js | 2 +- class/abstract-hd-wallet.js | 5 +- class/hd-legacy-breadwallet-wallet.js | 8 +- class/hd-legacy-p2pkh-wallet.js | 24 +++--- class/hd-segwit-bech32-transaction.js | 2 +- class/hd-segwit-bech32-wallet.js | 10 +-- class/hd-segwit-p2sh-wallet.js | 10 +-- class/legacy-wallet.js | 6 +- class/segwit-bech-wallet.js | 18 +++-- class/segwit-p2sh-wallet.js | 27 ++++--- models/signer.js | 80 +++++++++++++------ package-lock.json | 51 ++++++------ package.json | 6 +- patches/transaction.js.patch | 12 --- patches/transaction_builder.js.patch | 12 --- screen/selftest.js | 17 ++-- screen/send/details.js | 2 +- screen/transactions/RBF-create.js | 2 +- screen/wallets/transactions.js | 2 +- tests/integration/Electrum.test.js | 2 +- tests/integration/HDWallet.test.js | 17 ++-- .../hd-segwit-bech32-transaction.test.js | 2 +- tests/unit/signer.js | 2 +- 23 files changed, 168 insertions(+), 151 deletions(-) delete mode 100644 patches/transaction.js.patch delete mode 100644 patches/transaction_builder.js.patch diff --git a/BlueElectrum.js b/BlueElectrum.js index 09f82534..d33ec848 100644 --- a/BlueElectrum.js +++ b/BlueElectrum.js @@ -1,7 +1,7 @@ import AsyncStorage from '@react-native-community/async-storage'; import { AppStorage } from './class'; +const bitcoin = require('bitcoinjs-lib'); const ElectrumClient = require('electrum-client'); -let bitcoin = require('bitcoinjs-lib'); let reverse = require('buffer-reverse'); let BigNumber = require('bignumber.js'); diff --git a/class/abstract-hd-wallet.js b/class/abstract-hd-wallet.js index d30aca50..d0c4c687 100644 --- a/class/abstract-hd-wallet.js +++ b/class/abstract-hd-wallet.js @@ -1,7 +1,7 @@ import { LegacyWallet } from './legacy-wallet'; import Frisbee from 'frisbee'; -const bip39 = require('bip39'); const bitcoin = require('bitcoinjs-lib'); +const bip39 = require('bip39'); const BlueElectrum = require('../BlueElectrum'); export class AbstractHDWallet extends LegacyWallet { @@ -498,8 +498,7 @@ export class AbstractHDWallet extends LegacyWallet { unspent.vout = unspent.tx_output_n; unspent.amount = unspent.value; - let chunksIn = bitcoin.script.decompile(Buffer.from(unspent.script, 'hex')); - unspent.address = bitcoin.address.fromOutputScript(chunksIn); + unspent.address = bitcoin.address.fromOutputScript(Buffer.from(unspent.script, 'hex')); utxos.push(unspent); } } catch (err) { diff --git a/class/hd-legacy-breadwallet-wallet.js b/class/hd-legacy-breadwallet-wallet.js index dbf763f7..b39f2bb0 100644 --- a/class/hd-legacy-breadwallet-wallet.js +++ b/class/hd-legacy-breadwallet-wallet.js @@ -22,7 +22,7 @@ export class HDLegacyBreadwalletWallet extends AbstractHDWallet { } const mnemonic = this.secret; const seed = bip39.mnemonicToSeed(mnemonic); - const root = bitcoin.HDNode.fromSeedBuffer(seed); + const root = bitcoin.bip32.fromSeed(seed); const path = "m/0'"; const child = root.derivePath(path).neutered(); @@ -36,7 +36,7 @@ export class HDLegacyBreadwalletWallet extends AbstractHDWallet { if (this.external_addresses_cache[index]) return this.external_addresses_cache[index]; // cache hit const mnemonic = this.secret; const seed = bip39.mnemonicToSeed(mnemonic); - const root = bitcoin.HDNode.fromSeedBuffer(seed); + const root = bitcoin.bip32.fromSeed(seed); const path = "m/0'/0/" + index; const child = root.derivePath(path); @@ -49,7 +49,7 @@ export class HDLegacyBreadwalletWallet extends AbstractHDWallet { if (this.internal_addresses_cache[index]) return this.internal_addresses_cache[index]; // cache hit const mnemonic = this.secret; const seed = bip39.mnemonicToSeed(mnemonic); - const root = bitcoin.HDNode.fromSeedBuffer(seed); + const root = bitcoin.bip32.fromSeed(seed); const path = "m/0'/1/" + index; const child = root.derivePath(path); @@ -75,7 +75,7 @@ export class HDLegacyBreadwalletWallet extends AbstractHDWallet { _getWIFByIndex(internal, index) { const mnemonic = this.secret; const seed = bip39.mnemonicToSeed(mnemonic); - const root = bitcoin.HDNode.fromSeedBuffer(seed); + const root = bitcoin.bip32.fromSeed(seed); const path = `m/0'/${internal ? 1 : 0}/${index}`; const child = root.derivePath(path); diff --git a/class/hd-legacy-p2pkh-wallet.js b/class/hd-legacy-p2pkh-wallet.js index 8a6f1ca8..52c146b8 100644 --- a/class/hd-legacy-p2pkh-wallet.js +++ b/class/hd-legacy-p2pkh-wallet.js @@ -1,5 +1,5 @@ import { AbstractHDWallet } from './abstract-hd-wallet'; -import bitcoin from 'bitcoinjs-lib'; +const bitcoin = require('bitcoinjs-lib'); import bip39 from 'bip39'; import BigNumber from 'bignumber.js'; import signer from '../models/signer'; @@ -23,7 +23,7 @@ export class HDLegacyP2PKHWallet extends AbstractHDWallet { } const mnemonic = this.secret; const seed = bip39.mnemonicToSeed(mnemonic); - const root = bitcoin.HDNode.fromSeedBuffer(seed); + const root = bitcoin.bip32.fromSeed(seed); const path = "m/44'/0'/0'"; const child = root.derivePath(path).neutered(); @@ -50,7 +50,7 @@ export class HDLegacyP2PKHWallet extends AbstractHDWallet { _getWIFByIndex(internal, index) { const mnemonic = this.secret; const seed = bip39.mnemonicToSeed(mnemonic); - const root = bitcoin.HDNode.fromSeedBuffer(seed); + const root = bitcoin.bip32.fromSeed(seed); const path = `m/44'/0'/0'/${internal ? 1 : 0}/${index}`; const child = root.derivePath(path); @@ -61,11 +61,10 @@ export class HDLegacyP2PKHWallet extends AbstractHDWallet { index = index * 1; // cast to int if (this.external_addresses_cache[index]) return this.external_addresses_cache[index]; // cache hit - const node = bitcoin.HDNode.fromBase58(this.getXpub()); - const address = node - .derive(0) - .derive(index) - .getAddress(); + const node = bitcoin.bip32.fromBase58(this.getXpub()); + const address = bitcoin.payments.p2pkh({ + pubkey: node.derive(0).derive(index).publicKey, + }).address; return (this.external_addresses_cache[index] = address); } @@ -74,11 +73,10 @@ export class HDLegacyP2PKHWallet extends AbstractHDWallet { index = index * 1; // cast to int if (this.internal_addresses_cache[index]) return this.internal_addresses_cache[index]; // cache hit - const node = bitcoin.HDNode.fromBase58(this.getXpub()); - const address = node - .derive(1) - .derive(index) - .getAddress(); + const node = bitcoin.bip32.fromBase58(this.getXpub()); + const address = bitcoin.payments.p2pkh({ + pubkey: node.derive(1).derive(index).publicKey, + }).address; return (this.internal_addresses_cache[index] = address); } diff --git a/class/hd-segwit-bech32-transaction.js b/class/hd-segwit-bech32-transaction.js index 04b87820..69998667 100644 --- a/class/hd-segwit-bech32-transaction.js +++ b/class/hd-segwit-bech32-transaction.js @@ -1,5 +1,5 @@ import { HDSegwitBech32Wallet, SegwitBech32Wallet } from './'; -const bitcoin = require('bitcoinjs5'); +const bitcoin = require('bitcoinjs-lib'); const BlueElectrum = require('../BlueElectrum'); const reverse = require('buffer-reverse'); const BigNumber = require('bignumber.js'); diff --git a/class/hd-segwit-bech32-wallet.js b/class/hd-segwit-bech32-wallet.js index a124d04b..44f1bbac 100644 --- a/class/hd-segwit-bech32-wallet.js +++ b/class/hd-segwit-bech32-wallet.js @@ -3,8 +3,8 @@ import { NativeModules } from 'react-native'; import bip39 from 'bip39'; import BigNumber from 'bignumber.js'; import b58 from 'bs58check'; +const bitcoin = require('bitcoinjs-lib'); const BlueElectrum = require('../BlueElectrum'); -const bitcoin5 = require('bitcoinjs5'); const HDNode = require('bip32'); const coinSelectAccumulative = require('coinselect/accumulative'); const coinSelectSplit = require('coinselect/split'); @@ -693,19 +693,19 @@ export class HDSegwitBech32Wallet extends AbstractHDWallet { throw new Error('Not enough balance. Try sending smaller amount'); } - let txb = new bitcoin5.TransactionBuilder(); + let txb = new bitcoin.TransactionBuilder(); let c = 0; let keypairs = {}; let values = {}; inputs.forEach(input => { - const keyPair = bitcoin5.ECPair.fromWIF(this._getWifForAddress(input.address)); + const keyPair = bitcoin.ECPair.fromWIF(this._getWifForAddress(input.address)); keypairs[c] = keyPair; values[c] = input.value; c++; if (!input.address || !this._getWifForAddress(input.address)) throw new Error('Internal error: no address or WIF to sign input'); - const p2wpkh = bitcoin5.payments.p2wpkh({ pubkey: keyPair.publicKey }); + const p2wpkh = bitcoin.payments.p2wpkh({ pubkey: keyPair.publicKey }); txb.addInput(input.txId, input.vout, sequence, p2wpkh.output); // NOTE: provide the prevOutScript! }); @@ -733,7 +733,7 @@ export class HDSegwitBech32Wallet extends AbstractHDWallet { * @returns {String} */ static _nodeToBech32SegwitAddress(hdNode) { - return bitcoin5.payments.p2wpkh({ + return bitcoin.payments.p2wpkh({ pubkey: hdNode.publicKey, }).address; } diff --git a/class/hd-segwit-p2sh-wallet.js b/class/hd-segwit-p2sh-wallet.js index 7a225fbc..0205c1d3 100644 --- a/class/hd-segwit-p2sh-wallet.js +++ b/class/hd-segwit-p2sh-wallet.js @@ -7,7 +7,6 @@ import b58 from 'bs58check'; import signer from '../models/signer'; import { BitcoinUnit } from '../models/bitcoinUnits'; const bitcoin = require('bitcoinjs-lib'); -const bitcoin5 = require('bitcoinjs5'); const HDNode = require('bip32'); const { RNRandomBytes } = NativeModules; @@ -19,6 +18,7 @@ const { RNRandomBytes } = NativeModules; */ function ypubToXpub(ypub) { let data = b58.decode(ypub); + if (data.readUInt32BE() !== 0x049d7cb2) throw new Error('Not a valid ypub extended key!'); data = data.slice(4); data = Buffer.concat([Buffer.from('0488b21e', 'hex'), data]); @@ -31,8 +31,8 @@ function ypubToXpub(ypub) { * @returns {String} */ function nodeToP2shSegwitAddress(hdNode) { - const { address } = bitcoin5.payments.p2sh({ - redeem: bitcoin5.payments.p2wpkh({ pubkey: hdNode.publicKey }), + const { address } = bitcoin.payments.p2sh({ + redeem: bitcoin.payments.p2wpkh({ pubkey: hdNode.publicKey }), }); return address; } @@ -95,11 +95,11 @@ export class HDSegwitP2SHWallet extends AbstractHDWallet { _getWIFByIndex(internal, index) { const mnemonic = this.secret; const seed = bip39.mnemonicToSeed(mnemonic); - const root = bitcoin.HDNode.fromSeedBuffer(seed); + const root = bitcoin.bip32.fromSeed(seed); const path = `m/49'/0'/0'/${internal ? 1 : 0}/${index}`; const child = root.derivePath(path); - return child.keyPair.toWIF(); + return bitcoin.ECPair.fromPrivateKey(child.privateKey).toWIF(); } _getExternalAddressByIndex(index) { diff --git a/class/legacy-wallet.js b/class/legacy-wallet.js index 3042a3cf..ee9afcb2 100644 --- a/class/legacy-wallet.js +++ b/class/legacy-wallet.js @@ -3,9 +3,9 @@ import { SegwitBech32Wallet } from './'; import { useBlockcypherTokens } from './constants'; import Frisbee from 'frisbee'; import { NativeModules } from 'react-native'; +const bitcoin = require('bitcoinjs-lib'); const { RNRandomBytes } = NativeModules; const BigNumber = require('bignumber.js'); -const bitcoin = require('bitcoinjs-lib'); const signer = require('../models/signer'); const BlueElectrum = require('../BlueElectrum'); @@ -85,7 +85,9 @@ export class LegacyWallet extends AbstractWallet { let address; try { let keyPair = bitcoin.ECPair.fromWIF(this.secret); - address = keyPair.getAddress(); + address = bitcoin.payments.p2pkh({ + pubkey: keyPair.publicKey, + }).address; } catch (err) { return false; } diff --git a/class/segwit-bech-wallet.js b/class/segwit-bech-wallet.js index e3d6b19a..9a56ec72 100644 --- a/class/segwit-bech-wallet.js +++ b/class/segwit-bech-wallet.js @@ -10,9 +10,9 @@ export class SegwitBech32Wallet extends LegacyWallet { let address; try { let keyPair = bitcoin.ECPair.fromWIF(this.secret); - let pubKey = keyPair.getPublicKeyBuffer(); - let scriptPubKey = bitcoin.script.witnessPubKeyHash.output.encode(bitcoin.crypto.hash160(pubKey)); - address = bitcoin.address.fromOutputScript(scriptPubKey); + address = bitcoin.payments.p2wpkh({ + pubkey: keyPair.publicKey, + }).address; } catch (err) { return false; } @@ -23,13 +23,17 @@ export class SegwitBech32Wallet extends LegacyWallet { static witnessToAddress(witness) { const pubKey = Buffer.from(witness, 'hex'); - const pubKeyHash = bitcoin.crypto.hash160(pubKey); - const scriptPubKey = bitcoin.script.witnessPubKeyHash.output.encode(pubKeyHash); - return bitcoin.address.fromOutputScript(scriptPubKey, bitcoin.networks.bitcoin); + return bitcoin.payments.p2wpkh({ + pubkey: pubKey, + network: bitcoin.networks.bitcoin, + }).address; } static scriptPubKeyToAddress(scriptPubKey) { const scriptPubKey2 = Buffer.from(scriptPubKey, 'hex'); - return bitcoin.address.fromOutputScript(scriptPubKey2, bitcoin.networks.bitcoin); + return bitcoin.payments.p2wpkh({ + output: scriptPubKey2, + network: bitcoin.networks.bitcoin, + }).address; } } diff --git a/class/segwit-p2sh-wallet.js b/class/segwit-p2sh-wallet.js index f0a02b0d..b61c81dd 100644 --- a/class/segwit-p2sh-wallet.js +++ b/class/segwit-p2sh-wallet.js @@ -3,6 +3,21 @@ const bitcoin = require('bitcoinjs-lib'); const signer = require('../models/signer'); const BigNumber = require('bignumber.js'); +/** + * Creates Segwit P2SH Bitcoin address + * @param pubkey + * @param network + * @returns {String} + */ +function pubkeyToP2shSegwitAddress(pubkey, network) { + network = network || bitcoin.networks.bitcoin; + const { address } = bitcoin.payments.p2sh({ + redeem: bitcoin.payments.p2wpkh({ pubkey, network }), + network, + }); + return address; +} + export class SegwitP2SHWallet extends LegacyWallet { static type = 'segwitP2SH'; static typeReadable = 'SegWit (P2SH)'; @@ -13,11 +28,7 @@ export class SegwitP2SHWallet extends LegacyWallet { static witnessToAddress(witness) { const pubKey = Buffer.from(witness, 'hex'); - const pubKeyHash = bitcoin.crypto.hash160(pubKey); - const redeemScript = bitcoin.script.witnessPubKeyHash.output.encode(pubKeyHash); - const redeemScriptHash = bitcoin.crypto.hash160(redeemScript); - const scriptPubkey = bitcoin.script.scriptHash.output.encode(redeemScriptHash); - return bitcoin.address.fromOutputScript(scriptPubkey, bitcoin.networks.bitcoin); + return pubkeyToP2shSegwitAddress(pubKey); } getAddress() { @@ -25,14 +36,12 @@ export class SegwitP2SHWallet extends LegacyWallet { let address; try { let keyPair = bitcoin.ECPair.fromWIF(this.secret); - let pubKey = keyPair.getPublicKeyBuffer(); + let pubKey = keyPair.publicKey; if (!keyPair.compressed) { console.warn('only compressed public keys are good for segwit'); return false; } - let witnessScript = bitcoin.script.witnessPubKeyHash.output.encode(bitcoin.crypto.hash160(pubKey)); - let scriptPubKey = bitcoin.script.scriptHash.output.encode(bitcoin.crypto.hash160(witnessScript)); - address = bitcoin.address.fromOutputScript(scriptPubKey); + address = pubkeyToP2shSegwitAddress(pubKey); } catch (err) { return false; } diff --git a/models/signer.js b/models/signer.js index 9cd3fdc1..7abb53e0 100644 --- a/models/signer.js +++ b/models/signer.js @@ -6,13 +6,14 @@ * https://github.com/Overtorment/Cashier-BTC * **/ -let bitcoinjs = require('bitcoinjs-lib'); +const bitcoinjs = require('bitcoinjs-lib'); const toSatoshi = num => parseInt((num * 100000000).toFixed(0)); exports.createHDTransaction = function(utxos, toAddress, amount, fixedFee, changeAddress) { let feeInSatoshis = parseInt((fixedFee * 100000000).toFixed(0)); let amountToOutputSatoshi = parseInt(((amount - fixedFee) * 100000000).toFixed(0)); // how much payee should get let txb = new bitcoinjs.TransactionBuilder(); + txb.setVersion(1); let unspentAmountSatoshi = 0; let ourOutputs = {}; let outputNum = 0; @@ -51,7 +52,11 @@ exports.createHDTransaction = function(utxos, toAddress, amount, fixedFee, chang // now, signing every input with a corresponding key for (let c = 0; c <= outputNum; c++) { - txb.sign(c, ourOutputs[c].keyPair); + txb.sign({ + prevOutScriptType: 'p2pkh', + vin: c, + keyPair: ourOutputs[c].keyPair, + }); } let tx = txb.build(); @@ -62,6 +67,7 @@ exports.createHDSegwitTransaction = function(utxos, toAddress, amount, fixedFee, let feeInSatoshis = parseInt((fixedFee * 100000000).toFixed(0)); let amountToOutputSatoshi = parseInt(((amount - fixedFee) * 100000000).toFixed(0)); // how much payee should get let txb = new bitcoinjs.TransactionBuilder(); + txb.setVersion(1); let unspentAmountSatoshi = 0; let ourOutputs = {}; let outputNum = 0; @@ -73,9 +79,9 @@ exports.createHDSegwitTransaction = function(utxos, toAddress, amount, fixedFee, txb.addInput(unspent.txid, unspent.vout); ourOutputs[outputNum] = ourOutputs[outputNum] || {}; let keyPair = bitcoinjs.ECPair.fromWIF(unspent.wif); - let pubKey = keyPair.getPublicKeyBuffer(); - let pubKeyHash = bitcoinjs.crypto.hash160(pubKey); - let redeemScript = bitcoinjs.script.witnessPubKeyHash.output.encode(pubKeyHash); + let redeemScript = bitcoinjs.payments.p2wpkh({ + pubkey: keyPair.publicKey, + }).output; ourOutputs[outputNum].keyPair = keyPair; ourOutputs[outputNum].redeemScript = redeemScript; ourOutputs[outputNum].amount = unspent.amount; @@ -106,7 +112,13 @@ exports.createHDSegwitTransaction = function(utxos, toAddress, amount, fixedFee, // now, signing every input with a corresponding key for (let c = 0; c <= outputNum; c++) { - txb.sign(c, ourOutputs[c].keyPair, ourOutputs[c].redeemScript, null, ourOutputs[c].amount); + txb.sign({ + prevOutScriptType: 'p2sh-p2wpkh', + vin: c, + keyPair: ourOutputs[c].keyPair, + redeemScript: ourOutputs[c].redeemScript, + witnessValue: ourOutputs[c].amount, + }); } let tx = txb.build(); @@ -121,11 +133,12 @@ exports.createSegwitTransaction = function(utxos, toAddress, amount, fixedFee, W let feeInSatoshis = parseInt((fixedFee * 100000000).toFixed(0)); let keyPair = bitcoinjs.ECPair.fromWIF(WIF); - let pubKey = keyPair.getPublicKeyBuffer(); - let pubKeyHash = bitcoinjs.crypto.hash160(pubKey); - let redeemScript = bitcoinjs.script.witnessPubKeyHash.output.encode(pubKeyHash); + let redeemScript = bitcoinjs.payments.p2wpkh({ + pubkey: keyPair.publicKey, + }).output; let txb = new bitcoinjs.TransactionBuilder(); + txb.setVersion(1); let unspentAmount = 0; for (const unspent of utxos) { if (unspent.confirmations < 2) { @@ -148,7 +161,13 @@ exports.createSegwitTransaction = function(utxos, toAddress, amount, fixedFee, W } for (let c = 0; c < utxos.length; c++) { - txb.sign(c, keyPair, redeemScript, null, parseInt((utxos[c].amount * 100000000).toFixed(0))); + txb.sign({ + prevOutScriptType: 'p2sh-p2wpkh', + vin: c, + keyPair, + redeemScript, + witnessValue: parseInt((utxos[c].amount * 100000000).toFixed(0)), + }); } let tx = txb.build(); @@ -172,6 +191,7 @@ exports.createRBFSegwitTransaction = function(txhex, addressReplaceMap, feeDelta // creating TX let txb = new bitcoinjs.TransactionBuilder(); + txb.setVersion(1); for (let unspent of tx.ins) { txb.addInput(unspent.hash.reverse().toString('hex'), unspent.index, highestSequence + 1); } @@ -191,14 +211,20 @@ exports.createRBFSegwitTransaction = function(txhex, addressReplaceMap, feeDelta // signing let keyPair = bitcoinjs.ECPair.fromWIF(WIF); - let pubKey = keyPair.getPublicKeyBuffer(); - let pubKeyHash = bitcoinjs.crypto.hash160(pubKey); - let redeemScript = bitcoinjs.script.witnessPubKeyHash.output.encode(pubKeyHash); + let redeemScript = bitcoinjs.payments.p2wpkh({ + pubkey: keyPair.publicKey, + }).output; for (let c = 0; c < tx.ins.length; c++) { let txid = tx.ins[c].hash.reverse().toString('hex'); let index = tx.ins[c].index; let amount = utxodata[txid][index]; - txb.sign(c, keyPair, redeemScript, null, amount); + txb.sign({ + prevOutScriptType: 'p2sh-p2wpkh', + vin: c, + keyPair, + redeemScript, + witnessValue: amount, + }); } let newTx = txb.build(); @@ -207,11 +233,11 @@ exports.createRBFSegwitTransaction = function(txhex, addressReplaceMap, feeDelta exports.generateNewSegwitAddress = function() { let keyPair = bitcoinjs.ECPair.makeRandom(); - let pubKey = keyPair.getPublicKeyBuffer(); - - let witnessScript = bitcoinjs.script.witnessPubKeyHash.output.encode(bitcoinjs.crypto.hash160(pubKey)); - let scriptPubKey = bitcoinjs.script.scriptHash.output.encode(bitcoinjs.crypto.hash160(witnessScript)); - let address = bitcoinjs.address.fromOutputScript(scriptPubKey); + let address = bitcoinjs.payments.p2sh({ + redeem: bitcoinjs.payments.p2wpkh({ + pubkey: keyPair.publicKey, + }), + }).address; return { address: address, @@ -236,10 +262,11 @@ exports.URI = function(paymentInfo) { exports.WIF2segwitAddress = function(WIF) { let keyPair = bitcoinjs.ECPair.fromWIF(WIF); - let pubKey = keyPair.getPublicKeyBuffer(); - let witnessScript = bitcoinjs.script.witnessPubKeyHash.output.encode(bitcoinjs.crypto.hash160(pubKey)); - let scriptPubKey = bitcoinjs.script.scriptHash.output.encode(bitcoinjs.crypto.hash160(witnessScript)); - return bitcoinjs.address.fromOutputScript(scriptPubKey); + return bitcoinjs.payments.p2sh({ + redeem: bitcoinjs.payments.p2wpkh({ + pubkey: keyPair.publicKey, + }), + }).address; }; exports.createTransaction = function(utxos, toAddress, _amount, _fixedFee, WIF, fromAddress) { @@ -247,6 +274,7 @@ exports.createTransaction = function(utxos, toAddress, _amount, _fixedFee, WIF, let amountToOutput = toSatoshi(_amount - _fixedFee); let pk = bitcoinjs.ECPair.fromWIF(WIF); // eslint-disable-line new-cap let txb = new bitcoinjs.TransactionBuilder(); + txb.setVersion(1); let unspentAmount = 0; for (const unspent of utxos) { if (unspent.confirmations < 2) { @@ -264,7 +292,11 @@ exports.createTransaction = function(utxos, toAddress, _amount, _fixedFee, WIF, } for (let c = 0; c < utxos.length; c++) { - txb.sign(c, pk); + txb.sign({ + prevOutScriptType: 'p2pkh', + vin: c, + keyPair: pk, + }); } return txb.build().toHex(); diff --git a/package-lock.json b/package-lock.json index 6f1ee4b0..a631d919 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2663,6 +2663,11 @@ "file-uri-to-path": "1.0.0" } }, + "bip174": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bip174/-/bip174-1.0.1.tgz", + "integrity": "sha512-Mq2aFs1TdMfxBpYPg7uzjhsiXbAtoVq44TNjEWtvuZBiBgc3m7+n55orYMtTAxdg7jWbL4DtH0MKocJER4xERQ==" + }, "bip21": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/bip21/-/bip21-2.0.2.tgz", @@ -2711,34 +2716,14 @@ "integrity": "sha512-pef6gxZFztEhaE9RY9HmWVmiIHqCb2OyS4HPKkpc6CIiiOa3Qmuoylxc5P2EkU3w+5eTSifI9SEZC88idAIGow==" }, "bitcoinjs-lib": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/bitcoinjs-lib/-/bitcoinjs-lib-3.3.2.tgz", - "integrity": "sha512-l5qqvbaK8wwtANPf6oEffykycg4383XgEYdia1rI7/JpGf1jfRWlOUCvx5TiTZS7kyIvY4j/UhIQ2urLsvGkzw==", - "requires": { - "bech32": "^1.1.2", - "bigi": "^1.4.0", - "bip66": "^1.1.0", - "bitcoin-ops": "^1.3.0", - "bs58check": "^2.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.3", - "ecurve": "^1.0.0", - "merkle-lib": "^2.0.10", - "pushdata-bitcoin": "^1.0.1", - "randombytes": "^2.0.1", - "safe-buffer": "^5.0.1", - "typeforce": "^1.11.3", - "varuint-bitcoin": "^1.0.4", - "wif": "^2.0.1" - } - }, - "bitcoinjs5": { - "version": "git+https://github.com/Overtorment/bitcoinjs5.git#846c0185a6693f86540d58a7a5fffe8173dc8b34", - "from": "git+https://github.com/Overtorment/bitcoinjs5.git#846c018", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/bitcoinjs-lib/-/bitcoinjs-lib-5.1.6.tgz", + "integrity": "sha512-NgvnA8XXUuzpuBnVs1plzZvVOYsuont4KPzaGcVIwjktYQbCk1hUkXnt4wujIOBscNsXuu+plVbPYvtMosZI/w==", "requires": { "@types/node": "10.12.18", "bech32": "^1.1.2", - "bip32": "^2.0.3", + "bip174": "^1.0.1", + "bip32": "^2.0.4", "bip66": "^1.1.0", "bitcoin-ops": "^1.4.0", "bs58check": "^2.0.0", @@ -2751,6 +2736,22 @@ "typeforce": "^1.11.3", "varuint-bitcoin": "^1.0.4", "wif": "^2.0.1" + }, + "dependencies": { + "bip32": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/bip32/-/bip32-2.0.4.tgz", + "integrity": "sha512-ioPytarPDIrWckWMuK4RNUtvwhvWEc2fvuhnO0WEwu732k5OLjUXv4rXi2c/KJHw9ZMNQMkYRJrBw81RujShGQ==", + "requires": { + "@types/node": "10.12.18", + "bs58check": "^2.1.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "tiny-secp256k1": "^1.1.0", + "typeforce": "^1.11.5", + "wif": "^2.0.6" + } + } } }, "bl": { diff --git a/package.json b/package.json index 560ee418..5ca4c473 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "rn-nodeify": "github:tradle/rn-nodeify" }, "scripts": { - "prepare": "./patches/fix_mangle.sh; git apply patches/minifier.js.patch; git apply patches/minify.js.patch; git apply patches/transaction_builder.js.patch; git apply ./patches/transaction.js.patch", + "prepare": "./patches/fix_mangle.sh; git apply patches/minifier.js.patch; git apply patches/minify.js.patch", "clean": "cd android/; ./gradlew clean; cd ..; rm -r -f /tmp/metro-cache/; rm -r -f node_modules/; npm cache clean --force; npm i; npm start -- --reset-cache", "releasenotes2json": "./release-notes.sh > release-notes.txt; node -e 'console.log(JSON.stringify(require(\"fs\").readFileSync(\"release-notes.txt\", \"utf8\")));' > release-notes.json", "podinstall": "./podinstall.sh", @@ -58,13 +58,13 @@ "bip21": "2.0.2", "bip32": "2.0.3", "bip39": "2.5.0", - "bitcoinjs-lib": "3.3.2", - "bitcoinjs5": "git+https://github.com/Overtorment/bitcoinjs5.git#846c018", + "bitcoinjs-lib": "^5.1.6", "buffer": "5.2.1", "buffer-reverse": "1.0.1", "coinselect": "3.1.11", "crypto-js": "3.1.9-1", "dayjs": "1.8.14", + "ecurve": "^1.0.6", "electrum-client": "git+https://github.com/BlueWallet/rn-electrum-client.git", "eslint-config-prettier": "6.0.0", "eslint-config-standard": "12.0.0", diff --git a/patches/transaction.js.patch b/patches/transaction.js.patch deleted file mode 100644 index a235e771..00000000 --- a/patches/transaction.js.patch +++ /dev/null @@ -1,12 +0,0 @@ ---- a/node_modules/bitcoinjs-lib/src/transaction.js 2018-07-18 00:17:03.540824839 +0100 -+++ b/node_modules/bitcoinjs-lib/src/transaction.js 2018-07-18 00:24:55.840803782 +0100 -@@ -408,7 +408,8 @@ - - Transaction.prototype.getId = function () { - // transaction hash's are displayed in reverse order -- return this.getHash().reverse().toString('hex') -+ var bufferReverse = require('buffer-reverse') -+ return bufferReverse(this.getHash()).toString('hex') - } - - Transaction.prototype.toBuffer = function (buffer, initialOffset) { diff --git a/patches/transaction_builder.js.patch b/patches/transaction_builder.js.patch deleted file mode 100644 index 9e2d83a9..00000000 --- a/patches/transaction_builder.js.patch +++ /dev/null @@ -1,12 +0,0 @@ ---- a/node_modules/bitcoinjs-lib/src/transaction_builder.js 2018-07-18 00:09:22.924845375 +0100 -+++ b/node_modules/bitcoinjs-lib/src/transaction_builder.js 2018-07-18 00:14:20.996832086 +0100 -@@ -536,7 +536,8 @@ - // is it a hex string? - if (typeof txHash === 'string') { - // transaction hashs's are displayed in reverse order, un-reverse it -- txHash = Buffer.from(txHash, 'hex').reverse() -+ var bufferReverse = require('buffer-reverse') -+ txHash = bufferReverse(new Buffer(txHash, 'hex')) - - // is it a Transaction object? - } else if (txHash instanceof Transaction) { diff --git a/screen/selftest.js b/screen/selftest.js index e16fed23..38c724f0 100644 --- a/screen/selftest.js +++ b/screen/selftest.js @@ -3,9 +3,9 @@ import { ScrollView, View } from 'react-native'; import { BlueLoading, BlueSpacing20, SafeBlueArea, BlueCard, BlueText, BlueNavigationStyle } from '../BlueComponents'; import PropTypes from 'prop-types'; import { SegwitP2SHWallet, LegacyWallet, HDSegwitP2SHWallet, HDSegwitBech32Wallet } from '../class'; +const bitcoin = require('bitcoinjs-lib'); let BigNumber = require('bignumber.js'); let encryption = require('../encryption'); -let bitcoin = require('bitcoinjs-lib'); let BlueElectrum = require('../BlueElectrum'); export default class Selftest extends Component { @@ -217,16 +217,17 @@ export default class Selftest extends Component { let mnemonic = 'honey risk juice trip orient galaxy win situate shoot anchor bounce remind horse traffic exotic since escape mimic ramp skin judge owner topple erode'; let seed = bip39.mnemonicToSeed(mnemonic); - let root = bitcoin.HDNode.fromSeedBuffer(seed); + let root = bitcoin.bip32.fromSeed(seed); let path = "m/49'/0'/0'/0/0"; let child = root.derivePath(path); - - let keyhash = bitcoin.crypto.hash160(child.getPublicKeyBuffer()); - let scriptSig = bitcoin.script.witnessPubKeyHash.output.encode(keyhash); - let addressBytes = bitcoin.crypto.hash160(scriptSig); - let outputScript = bitcoin.script.scriptHash.output.encode(addressBytes); - let address = bitcoin.address.fromOutputScript(outputScript, bitcoin.networks.bitcoin); + let address = bitcoin.payments.p2sh({ + redeem: bitcoin.payments.p2wpkh({ + pubkey: child.publicKey, + network: bitcoin.networks.bitcoin, + }), + network: bitcoin.networks.bitcoin, + }).address; if (address !== '3GcKN7q7gZuZ8eHygAhHrvPa5zZbG5Q1rK') { errorMessage += 'bip49 is not ok; '; diff --git a/screen/send/details.js b/screen/send/details.js index 0ffd3d1c..664c6acb 100644 --- a/screen/send/details.js +++ b/screen/send/details.js @@ -33,12 +33,12 @@ import BitcoinBIP70TransactionDecode from '../../bip70/bip70'; import { BitcoinUnit, Chain } from '../../models/bitcoinUnits'; import { HDLegacyP2PKHWallet, HDSegwitBech32Wallet, HDSegwitP2SHWallet, LightningCustodianWallet } from '../../class'; import ReactNativeHapticFeedback from 'react-native-haptic-feedback'; +const bitcoin = require('bitcoinjs-lib'); const bip21 = require('bip21'); let BigNumber = require('bignumber.js'); /** @type {AppStorage} */ let BlueApp = require('../../BlueApp'); let loc = require('../../loc'); -let bitcoin = require('bitcoinjs-lib'); const btcAddressRx = /^[a-zA-Z0-9]{26,35}$/; diff --git a/screen/transactions/RBF-create.js b/screen/transactions/RBF-create.js index 66ce1bb4..8f23e9cc 100644 --- a/screen/transactions/RBF-create.js +++ b/screen/transactions/RBF-create.js @@ -14,8 +14,8 @@ import { BlueNavigationStyle, } from '../../BlueComponents'; import PropTypes from 'prop-types'; +const bitcoinjs = require('bitcoinjs-lib'); let BigNumber = require('bignumber.js'); -let bitcoinjs = require('bitcoinjs-lib'); let BlueApp = require('../../BlueApp'); export default class SendCreate extends Component { diff --git a/screen/wallets/transactions.js b/screen/wallets/transactions.js index 108395e7..8736daf2 100644 --- a/screen/wallets/transactions.js +++ b/screen/wallets/transactions.js @@ -280,7 +280,7 @@ export default class WalletTransactions extends Component { ListHeaderComponent={this.renderListHeaderComponent} ListFooterComponent={this.renderListFooterComponent} ListEmptyComponent={ - + { diff --git a/tests/integration/HDWallet.test.js b/tests/integration/HDWallet.test.js index ca335ee1..fee7d06d 100644 --- a/tests/integration/HDWallet.test.js +++ b/tests/integration/HDWallet.test.js @@ -1,9 +1,9 @@ /* global it, jasmine, afterAll, beforeAll */ import { SegwitP2SHWallet, SegwitBech32Wallet, HDSegwitP2SHWallet, HDLegacyBreadwalletWallet, HDLegacyP2PKHWallet } from '../../class'; import { BitcoinUnit } from '../../models/bitcoinUnits'; +const bitcoin = require('bitcoinjs-lib'); global.crypto = require('crypto'); // shall be used by tests under nodejs CLI, but not in RN environment let assert = require('assert'); -let bitcoin = require('bitcoinjs-lib'); global.net = require('net'); // needed by Electrum client. For RN it is proviced in shim.js let BlueElectrum = require('../../BlueElectrum'); // so it connects ASAP jasmine.DEFAULT_TIMEOUT_INTERVAL = 300 * 1000; @@ -155,10 +155,8 @@ it('HD (BIP49) can create TX', async () => { assert.strictEqual(tx.outs.length, 2); assert.strictEqual(tx.outs[0].value, 500); assert.strictEqual(tx.outs[1].value, 25400); - let chunksIn = bitcoin.script.decompile(tx.outs[0].script); - let toAddress = bitcoin.address.fromOutputScript(chunksIn); - chunksIn = bitcoin.script.decompile(tx.outs[1].script); - let changeAddress = bitcoin.address.fromOutputScript(chunksIn); + let toAddress = bitcoin.address.fromOutputScript(tx.outs[0].script); + let changeAddress = bitcoin.address.fromOutputScript(tx.outs[1].script); assert.strictEqual('3GcKN7q7gZuZ8eHygAhHrvPa5zZbG5Q1rK', toAddress); assert.strictEqual(hd._getInternalAddressByIndex(hd.next_free_change_address_index), changeAddress); @@ -175,8 +173,7 @@ it('HD (BIP49) can create TX', async () => { tx = bitcoin.Transaction.fromHex(txhex); assert.strictEqual(tx.ins.length, 1); assert.strictEqual(tx.outs.length, 1); - chunksIn = bitcoin.script.decompile(tx.outs[0].script); - toAddress = bitcoin.address.fromOutputScript(chunksIn); + toAddress = bitcoin.address.fromOutputScript(tx.outs[0].script); assert.strictEqual('3GcKN7q7gZuZ8eHygAhHrvPa5zZbG5Q1rK', toAddress); // testing sendMAX @@ -349,10 +346,8 @@ it('Legacy HD (BIP44) can create TX', async () => { assert.strictEqual(tx.outs.length, 2); assert.strictEqual(tx.outs[0].value, 80000); // payee assert.strictEqual(tx.outs[1].value, 19500); // change - let chunksIn = bitcoin.script.decompile(tx.outs[0].script); - let toAddress = bitcoin.address.fromOutputScript(chunksIn); - chunksIn = bitcoin.script.decompile(tx.outs[1].script); - let changeAddress = bitcoin.address.fromOutputScript(chunksIn); + let toAddress = bitcoin.address.fromOutputScript(tx.outs[0].script); + let changeAddress = bitcoin.address.fromOutputScript(tx.outs[1].script); assert.strictEqual('3GcKN7q7gZuZ8eHygAhHrvPa5zZbG5Q1rK', toAddress); assert.strictEqual(hd._getInternalAddressByIndex(hd.next_free_change_address_index), changeAddress); diff --git a/tests/integration/hd-segwit-bech32-transaction.test.js b/tests/integration/hd-segwit-bech32-transaction.test.js index 7338a821..440c8fa6 100644 --- a/tests/integration/hd-segwit-bech32-transaction.test.js +++ b/tests/integration/hd-segwit-bech32-transaction.test.js @@ -1,6 +1,6 @@ /* global it, describe, jasmine, afterAll, beforeAll */ import { HDSegwitBech32Wallet, HDSegwitBech32Transaction, SegwitBech32Wallet } from '../../class'; -const bitcoin = require('bitcoinjs5'); +const bitcoin = require('bitcoinjs-lib'); global.crypto = require('crypto'); // shall be used by tests under nodejs CLI, but not in RN environment let assert = require('assert'); global.net = require('net'); // needed by Electrum client. For RN it is proviced in shim.js diff --git a/tests/unit/signer.js b/tests/unit/signer.js index 775fe6af..14099ff7 100644 --- a/tests/unit/signer.js +++ b/tests/unit/signer.js @@ -1,5 +1,5 @@ /* global describe, it */ -let bitcoinjs = require('bitcoinjs-lib') +const bitcoinjs = require('bitcoinjs-lib'); let assert = require('assert') describe('unit - signer', function () {