diff --git a/src/js/controllers/walletDetails.js b/src/js/controllers/walletDetails.js index 259ca2ff3..59799293a 100644 --- a/src/js/controllers/walletDetails.js +++ b/src/js/controllers/walletDetails.js @@ -47,6 +47,19 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun $scope.txps = lodash.sortBy(txps, 'createdOn').reverse(); }; + var analyzeUtxosDone; + + var analyzeUtxos = function() { + if (analyzeUtxosDone) return; + + feeService.getFeeLevels(function(err, levels){ + walletService.getLowUtxos($scope.wallet, levels, function(err, resp){ + analyzeUtxosDone = true; + $scope.lowUtxosWarning = resp.warning; + }); + }); + }; + var updateStatus = function(force) { $scope.updatingStatus = true; $scope.updateStatusError = null; @@ -72,6 +85,8 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun $scope.$apply(); }); + analyzeUtxos(); + }); }; @@ -154,10 +169,10 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun }); }; - feeService.getLowAmount($scope.wallet, function(err, lowAmount){ + feeService.getFeeLevels(function(err, levels){ walletService.getTxHistory($scope.wallet, { progressFn: progressFn, - lowAmount: lowAmount, + feeLevels: levels, }, function(err, txHistory) { $scope.updatingTxHistory = false; if (err) { diff --git a/src/js/services/feeService.js b/src/js/services/feeService.js index a3e554f38..1f51b046b 100644 --- a/src/js/services/feeService.js +++ b/src/js/services/feeService.js @@ -4,7 +4,6 @@ angular.module('copayApp.services').factory('feeService', function($log, $timeou var root = {}; var CACHE_TIME_TS = 60; // 1 min - var LOW_AMOUNT_RATIO = 0.15; //Ratio low amount warning (econ fee/amount) // Constant fee options to translate root.feeOpts = { @@ -83,51 +82,5 @@ angular.module('copayApp.services').factory('feeService', function($log, $timeou }; - // These 2 functions were taken from - // https://github.com/bitpay/bitcore-wallet-service/blob/master/lib/model/txproposal.js#L243 - - function getEstimatedSizeForSingleInput(wallet) { - switch (wallet.credentials.addressType) { - case 'P2PKH': - return 147; - default: - case 'P2SH': - return wallet.m * 72 + wallet.n * 36 + 44; - } - }; - - - function getEstimatedSize(wallet) { - // Note: found empirically based on all multisig P2SH inputs and within m & n allowed limits. - var safetyMargin = 0.02; - - var overhead = 4 + 4 + 9 + 9; - var inputSize = getEstimatedSizeForSingleInput(wallet); - var outputSize = 34; - var nbInputs = 1; //Assume 1 input - var nbOutputs = 2; // Assume 2 outputs - - var size = overhead + inputSize * nbInputs + outputSize * nbOutputs; - return parseInt((size * (1 + safetyMargin)).toFixed(0)); - }; - - - // Approx utxo amount, from which the uxto is economically redeemable - root.getLowAmount = function(wallet, cb) { - root.getFeeLevels(function(err, levels) { - if (err) return cb(err); - - var lowLevelRate = (lodash.find(levels[wallet.network], { - level: 'economy', - }).feePerKB / 1000).toFixed(0); - - var size = getEstimatedSize(wallet); - - var minFee = size * lowLevelRate; - - return cb(null, parseInt(minFee / (LOW_AMOUNT_RATIO))); - }); - }; - return root; }); diff --git a/src/js/services/profileService.js b/src/js/services/profileService.js index 5f1118a1d..8c5a93662 100644 --- a/src/js/services/profileService.js +++ b/src/js/services/profileService.js @@ -90,8 +90,6 @@ angular.module('copayApp.services') wallet.m = wallet.credentials.m; wallet.n = wallet.credentials.n; - wallet.lowAmount = - root.updateWalletSettings(wallet); root.wallet[walletId] = wallet; diff --git a/src/js/services/walletService.js b/src/js/services/walletService.js index 7f53f1ce8..5e8930c82 100644 --- a/src/js/services/walletService.js +++ b/src/js/services/walletService.js @@ -3,6 +3,9 @@ angular.module('copayApp.services').factory('walletService', function($log, $timeout, lodash, trezor, ledger, intelTEE, storageService, configService, rateService, uxLanguage, $filter, gettextCatalog, bwcError, $ionicPopup, fingerprintService, ongoingProcess, gettext, $rootScope, txFormatService, $ionicModal, $state, bwcService, bitcore, popupService) { // `wallet` is a decorated version of client. + var LOW_AMOUNT_RATIO = 0.15; //Ratio low amount warning (econ fee/amount) + var TOTAL_LOW_WARNING_RATIO = .15; + var root = {}; root.externalSource = { @@ -401,6 +404,11 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim var progressFn = opts.progressFn || function() {}; var foundLimitTx = false; + + if (opts.feeLevels) { + opts.lowAmount = root.getLowAmount(wallet, opts.feeLevels); + } + var fixTxsUnit = function(txs) { if (!txs || !txs[0] || !txs[0].amountStr) return; @@ -512,6 +520,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim function updateLowAmount(txs) { if (!opts.lowAmount) return; + lodash.each(txs, function(tx) { tx.lowAmount = tx.amount < opts.lowAmount; }); @@ -881,6 +890,76 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim }); }; + + // These 2 functions were taken from + // https://github.com/bitpay/bitcore-wallet-service/blob/master/lib/model/txproposal.js#L243 + + function getEstimatedSizeForSingleInput(wallet) { + switch (wallet.credentials.addressType) { + case 'P2PKH': + return 147; + default: + case 'P2SH': + return wallet.m * 72 + wallet.n * 36 + 44; + } + }; + + + root.getEstimatedTxSize = function(wallet, nbOutputs) { + // Note: found empirically based on all multisig P2SH inputs and within m & n allowed limits. + var safetyMargin = 0.02; + + var overhead = 4 + 4 + 9 + 9; + var inputSize = getEstimatedSizeForSingleInput(wallet); + var outputSize = 34; + var nbInputs = 1; //Assume 1 input + var nbOutputs = nbOutputs || 2; // Assume 2 outputs + + var size = overhead + inputSize * nbInputs + outputSize * nbOutputs; + return parseInt((size * (1 + safetyMargin)).toFixed(0)); + }; + + + // Approx utxo amount, from which the uxto is economically redeemable + root.getLowAmount = function(wallet, feeLevels, nbOutputs) { + var lowLevelRate = (lodash.find(feeLevels[wallet.network], { + level: 'normal', + }).feePerKB / 1000).toFixed(0); + + var size = root.getEstimatedTxSize(wallet, nbOutputs); + var minFee = size * lowLevelRate; + + return parseInt(minFee / (LOW_AMOUNT_RATIO)); + }; + + + + root.getLowUtxos = function(wallet, levels, cb) { + + wallet.getUtxos({}, function(err, resp) { + if (err || !resp || !resp.length) return cb(); + + + var lowAmountN = root.getLowAmount(wallet, levels, resp.length + 1); +console.log('[walletService.js.946:lowAmountN:]',lowAmountN); //TODO + var total = lodash.sum(resp, 'satoshis'); +console.log('[walletService.js.948:total:]',total); //TODO + + var lowAmount1 = root.getLowAmount(wallet, levels); +console.log('[walletService.js.950:lowAmount1:]',lowAmount1); //TODO + var lowUtxos = lodash.filter(resp, function(x) { + return x.satoshis < lowAmount1; + }); + + var totalLow = lodash.sum(lowUtxos, 'satoshis'); + + return cb(err, { + lowUtxos: lowUtxos, + warning: lowAmountN / total > TOTAL_LOW_WARNING_RATIO, + }); + }); + }; + root.getAddress = function(wallet, forceNew, cb) { storageService.getLastAddress(wallet.id, function(err, addr) { if (err) return cb(err); diff --git a/www/views/tx-details.html b/www/views/tx-details.html index cd13d7535..6ef243116 100644 --- a/www/views/tx-details.html +++ b/www/views/tx-details.html @@ -90,7 +90,8 @@
- This transaction amount is too small given current Bitcoin network fees. Spending these funds will incur in fees comparable to the amount itself. + +This transaction amount is too small compared to current Bitcoin network fees. Spending these funds will need a Bitcoin network fee cost comparable to the funds itself.
diff --git a/www/views/walletDetails.html b/www/views/walletDetails.html index 93fe90f68..7b075a50c 100644 --- a/www/views/walletDetails.html +++ b/www/views/walletDetails.html @@ -158,6 +158,12 @@ Wallet not backed up + + + Spending this balance will need significant Bitcoin network fees + + +