diff --git a/lib/addresstranslator.js b/lib/bchaddresstranslator.js similarity index 71% rename from lib/addresstranslator.js rename to lib/bchaddresstranslator.js index 6ce752b..b9e714c 100644 --- a/lib/addresstranslator.js +++ b/lib/bchaddresstranslator.js @@ -5,11 +5,11 @@ var Bitcore_ = { var _ = require('lodash'); -function AddressTranslator() { +function BCHAddressTranslator() { }; -AddressTranslator.getAddressCoin = function(address) { +BCHAddressTranslator.getAddressCoin = function(address) { try { new Bitcore_['btc'].Address(address); return 'legacy'; @@ -26,7 +26,7 @@ AddressTranslator.getAddressCoin = function(address) { // Supports 3 formats: legacy (1xxx, mxxxx); Copay: (Cxxx, Hxxx), Cashaddr(qxxx); -AddressTranslator.translate = function(addresses, to, from) { +BCHAddressTranslator.translate = function(addresses, to, from) { var wasArray = true; if (!_.isArray(addresses)) { wasArray = false; @@ -34,7 +34,7 @@ AddressTranslator.translate = function(addresses, to, from) { } - from = from || AddressTranslator.getAddressCoin(addresses[0]); + from = from || BCHAddressTranslator.getAddressCoin(addresses[0]); if (from == to) return addresses; var ret = _.map(addresses, function(x) { @@ -57,15 +57,5 @@ AddressTranslator.translate = function(addresses, to, from) { }; -AddressTranslator.translateInput = function(addresses) { - return this.translate(addresses, 'btc', 'bch'); -} -AddressTranslator.translateOutput = function(addresses) { - return this.translate(addresses, 'bch', 'btc'); -} - - - - -module.exports = AddressTranslator; +module.exports = BCHAddressTranslator; diff --git a/lib/blockchainexplorer.js b/lib/blockchainexplorer.js index a970317..211a00f 100644 --- a/lib/blockchainexplorer.js +++ b/lib/blockchainexplorer.js @@ -37,6 +37,14 @@ function BlockChainExplorer(opts) { var url = opts.url || PROVIDERS[provider][coin][network]; + + if (coin != 'bch' && opts.addressFormat) + throw new Error('addressFormat only supported for bch'); + + if (coin == 'bch' && !opts.addressFormat) + opts.addressFormat = 'cashaddr'; + + switch (provider) { case 'insight': return new Insight({ @@ -45,7 +53,7 @@ function BlockChainExplorer(opts) { url: url, apiPrefix: opts.apiPrefix, userAgent: opts.userAgent, - translateAddresses: opts.translateAddresses, + addressFormat: opts.addressFormat, }); default: throw new Error('Provider ' + provider + ' not supported.'); diff --git a/lib/blockchainexplorers/insight.js b/lib/blockchainexplorers/insight.js index e1a6e5f..489c1b6 100644 --- a/lib/blockchainexplorers/insight.js +++ b/lib/blockchainexplorers/insight.js @@ -24,7 +24,11 @@ function Insight(opts) { this.network = opts.network || 'livenet'; this.hosts = opts.url; this.userAgent = opts.userAgent || 'bws'; - this.shouldTranslateAddresses = _.isUndefined(opts.translateAddresses) ? this.coin == 'bch' : opts.translateAddresses; + + if (opts.addressFormat) { + $.checkArgument(Constants.ADDRESS_FORMATS.includes(opts.addressFormat), 'Unkown addr format:' + opts.addressFormat); + this.addressFormat = opts.addressFormat != 'copay' ? opts.addressFormat : null; + } this.requestQueue = async.queue(this._doRequest.bind(this), Defaults.INSIGHT_REQUEST_POOL_SIZE); @@ -42,39 +46,33 @@ var _parseErr = function(err, res) { // Translate Request Address query Insight.prototype.translateQueryAddresses = function(addresses) { - -console.log('[insight.js.45]', this.shouldTranslateAddresses); //TODO - if (!this.shouldTranslateAddresses) return addresses; - - // It is called 'translatedInput' from Cxxx to qXXXX because the - // module was created for insight-api - return AddressTranslator.translateInput(addresses); + if (!this.addressFormat) return addresses; + return AddressTranslator.translate(addresses, this.addressFormat, 'copay'); }; // Translate Result Address Insight.prototype.translateResultAddresses = function(addresses) { - if (!this.shouldTranslateAddresses) return addresses; + if (!this.addressFormat) return addresses; - // It is called 'translateOutput' from qXXX to Cxxx because the - // module was created for insight-api - return AddressTranslator.translateOutput(addresses); + return AddressTranslator.translate(addresses, 'copay', this.addressFormat); }; Insight.prototype.translateTx = function(tx) { - if (!this.shouldTranslateAddresses) return tx; + var self = this; + if (!this.addressFormat) return tx; _.each(tx.vin, function(x){ if (x.addr) { - x.addr = AddressTranslator.translateOutput(x.addr); + x.addr = self.translateResultAddresses(x.addr); } }); _.each(tx.vout, function(x){ if (x.scriptPubKey && x.scriptPubKey.addresses) { - x.scriptPubKey.addresses = AddressTranslator.translateOutput(x.scriptPubKey.addresses); + x.scriptPubKey.addresses = self.translateResultAddresses(x.scriptPubKey.addresses); } }); @@ -105,7 +103,6 @@ Insight.prototype.getConnectionInfo = function() { * Retrieve a list of unspent outputs associated with an address or set of addresses */ Insight.prototype.getUtxos = function(addresses, cb) { -console.log('[insight.js.105:addresses:]',addresses); //TODO var self = this; var url = this.url + this.apiPrefix + '/addrs/utxo'; @@ -120,7 +117,8 @@ console.log('[insight.js.105:addresses:]',addresses); //TODO this.requestQueue.push(args, function(err, res, unspent) { if (err || res.statusCode !== 200) return cb(_parseErr(err, res)); - if (self.shouldTranslateAddresses) { + if (self.addressFormat) { + _.each(unspent, function(x) { x.address = self.translateResultAddresses(x.address); }); @@ -204,7 +202,7 @@ Insight.prototype.getTransactions = function(addresses, from, to, cb) { // NOTE: Whenever Insight breaks communication with bitcoind, it returns invalid data but no error code. if (!_.isArray(txs) || (txs.length != _.compact(txs).length)) return cb(new Error('Could not retrieve transactions from blockchain. Request was:' + JSON.stringify(args))); - if (self.shouldTranslateAddresses) { + if (self.addressFormat) { _.each(txs, function(tx){ self.translateTx(tx); diff --git a/lib/common/constants.js b/lib/common/constants.js index 5b1562a..6cb36dd 100644 --- a/lib/common/constants.js +++ b/lib/common/constants.js @@ -12,6 +12,8 @@ Constants.NETWORKS = { TESTNET: 'testnet', }; +Constants.ADDRESS_FORMATS = ['copay', 'cashaddr', 'legacy']; + Constants.SCRIPT_TYPES = { P2SH: 'P2SH', P2PKH: 'P2PKH', diff --git a/lib/server.js b/lib/server.js index 6d683a9..4ee46b6 100644 --- a/lib/server.js +++ b/lib/server.js @@ -1189,6 +1189,12 @@ WalletService.prototype._getUtxosForCurrentWallet = function(opts, cb) { if (!opts.coin) return next(); coin = opts.coin; + if (coin != 'bch') return next(); + + if (Utils.getAddressCoin(addressStrs[0]) == 'bch') + return next(); + + // because some old BCH walelts could have legacy addresses? addressStrs = _.map(addressStrs, function(a) { return Utils.translateAddress(a, coin); }); @@ -1245,6 +1251,10 @@ WalletService.prototype._getUtxosForCurrentWallet = function(opts, cb) { // Needed for the clients to sign UTXOs var addressToPath = _.indexBy(allAddresses, 'address'); _.each(allUtxos, function(utxo) { + if (!addressToPath[utxo.address]) { + log.warn('Ignored UTXO!: ' + utxo.address); + return; + } utxo.path = addressToPath[utxo.address].path; utxo.publicKeys = addressToPath[utxo.address].publicKeys; }); @@ -3183,8 +3193,10 @@ WalletService.prototype.getTxHistory = function(opts, cb) { bc.getTransactions(addressStrs, from, to, function(err, rawTxs, total) { if (err) return next(err); +console.log('[server.js.3197: RAWtxs:]', JSON.stringify(rawTxs, null, 4)); //TODO txs = self._normalizeTxHistory(rawTxs); +console.log('[server.js.3197:txs:]', JSON.stringify(txs, null, 4)); //TODO totalItems = total; return next(); }); diff --git a/test/addressestranslator.js b/test/addressestranslator.js deleted file mode 100644 index caf635d..0000000 --- a/test/addressestranslator.js +++ /dev/null @@ -1,87 +0,0 @@ - -var _ = require('lodash'); -var chai = require('chai'); -var sinon = require('sinon'); -var assert = require('assert'); -var should = chai.should; - -var AddressTranslator = require('../lib/addresstranslator'); - -describe('#AddressTranslator', function() { - - it('should translate address from legacy to cashaddr', function() { - var res = AddressTranslator.translate('1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA', 'cashaddr'); - assert( res == 'qrvcdmgpk73zyfd8pmdl9wnuld36zh9n4gms8s0u59'); - }); - - - it('should translate address from copay to cashaddr', function() { - var res = AddressTranslator.translate('HBf8isgS8EXG1r3X6GP89FmooUmiJ42wHS', 'cashaddr'); - assert( res == 'pqu9c0xe7g0ngz9hzpky64nva9790m64esxxjmcv2k'); - }); - - it('should translate address from cashaddr to copay', function() { - var res = AddressTranslator.translate('pqu9c0xe7g0ngz9hzpky64nva9790m64esxxjmcv2k', 'copay'); - assert( res == 'HBf8isgS8EXG1r3X6GP89FmooUmiJ42wHS'); - }); - - - it('should keep addresses if not translation needed from cashaddr to copay', function() { - var res = AddressTranslator.translate('pqu9c0xe7g0ngz9hzpky64nva9790m64esxxjmcv2k', 'cashaddr'); - assert( res == 'pqu9c0xe7g0ngz9hzpky64nva9790m64esxxjmcv2k'); - }); - - - it('should translate address from legacy to cashaddr (testnet)', function() { - var res = AddressTranslator.translate('mnE5ERQ3MKrgAVSLQtBifyjAPE8t6aRfLL', 'cashaddr'); - assert( res == 'qpye0xdyrukzs548zjag5vas8s8f956g8svs329zm4'); - }); - - - - it('should translate address from cashaddr to legacy (testnet)', function() { - var res = AddressTranslator.translate('qpye0xdyrukzs548zjag5vas8s8f956g8svs329zm4', 'legacy'); - assert( res == 'mnE5ERQ3MKrgAVSLQtBifyjAPE8t6aRfLL'); - }); - - - - it.skip('should translate address from bch to btc', function() { - var res = AddressTranslator.translateInput('HBf8isgS8EXG1r3X6GP89FmooUmiJ42wHS'); - assert(res=='36q2G5FMGvJbPgAVEaiyAsFGmpkhPKwk2r'); - }); - - it.skip('should keep the address if there is nothing to do (bch)', function() { - var res = AddressTranslator.translate('CcJ4qUfyQ8x5NwhAeCQkrBSWVeXxXghcNz', 'bch'); - assert(res=='qrvcdmgpk73zyfd8pmdl9wnuld36zh9n4gms8s0u59'); - }); - it.skip('should keep the address if there is nothing to do (btc)', function() { - var res = AddressTranslator.translate('1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA', 'btc'); - assert(res=='1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA'); - }); - it.skip('should support 3 params NOK', function() { - - var a; - try { - var res = AddressTranslator.translate('1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA', 'btc', 'bch'); - } catch (e) { - a=e.toString(); - assert(a.match(/Address has mismatched network type/)); - }; - }); - it.skip('should support 3 params OK', function() { - var res = AddressTranslator.translate('HBf8isgS8EXG1r3X6GP89FmooUmiJ42wHS', 'btc', 'bch'); - assert(res=='36q2G5FMGvJbPgAVEaiyAsFGmpkhPKwk2r'); - }); - - it.skip('should work with arrays also', function() { - var res = AddressTranslator.translateOutput(['1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA', '37YHiaQnMjy73GS1UpiE8p2Ju6MyrrDw3J', '1DuPdCpGzVX73kBYaAbu5XDNDgE2Lza5Ed']); - assert(res[0] == 'qrvcdmgpk73zyfd8pmdl9wnuld36zh9n4gms8s0u59'); - assert(res[1] == 'ppqz5v08kssnuupe0ckqtw4ss3qt460fcqugqzq2me'); - assert(res[2] == 'qzxc5pnsfs8pmgfprhzc4l4vzf3zxz8p85nc6kfh8l'); - }); - - -}); - -