From fdf73fa838d08fc8283810fdbd0d92d1e5873174 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Thu, 22 Jun 2017 11:38:13 -0300 Subject: [PATCH 1/4] add to low amount to incoming TXs --- src/js/controllers/confirm.js | 6 ++- src/js/controllers/modals/txpDetails.js | 10 ----- src/js/controllers/tx-details.js | 18 +++----- src/js/controllers/walletDetails.js | 5 ++- src/js/services/feeService.js | 56 ++++++++++++++++++++++-- src/js/services/profileService.js | 2 + src/js/services/txFormatService.js | 5 +++ src/js/services/walletService.js | 16 +++++-- src/sass/views/confirm.scss | 4 ++ src/sass/views/includes/txp-details.scss | 2 +- www/views/confirm.html | 9 +++- www/views/includes/walletHistory.html | 5 +++ www/views/modals/txp-details.html | 2 +- www/views/tx-details.html | 7 ++- 14 files changed, 110 insertions(+), 37 deletions(-) diff --git a/src/js/controllers/confirm.js b/src/js/controllers/confirm.js index c9ce5943a..9623206f2 100644 --- a/src/js/controllers/confirm.js +++ b/src/js/controllers/confirm.js @@ -4,6 +4,7 @@ angular.module('copayApp.controllers').controller('confirmController', function( var countDown = null; var CONFIRM_LIMIT_USD = 20; + var FEE_TOO_HIGH_LIMIT_PER = 15; var tx = {}; @@ -286,7 +287,10 @@ angular.module('copayApp.controllers').controller('confirmController', function( txFormatService.formatAlternativeStr(txp.fee, function(v) { txp.alternativeFeeStr = v; }); - txp.feeRatePerStr = (txp.fee / (txp.amount + txp.fee) * 100).toFixed(2) + '%'; + + var per = (txp.fee / (txp.amount + txp.fee) * 100); + txp.feeRatePerStr = per.toFixed(2) + '%'; + txp.feeToHigh = per > FEE_TOO_HIGH_LIMIT_PER; tx.txp[wallet.id] = txp; diff --git a/src/js/controllers/modals/txpDetails.js b/src/js/controllers/modals/txpDetails.js index bfab29089..3767b6e93 100644 --- a/src/js/controllers/modals/txpDetails.js +++ b/src/js/controllers/modals/txpDetails.js @@ -14,8 +14,6 @@ angular.module('copayApp.controllers').controller('txpDetailsController', functi $scope.canSign = $scope.wallet.canSign() || $scope.wallet.isPrivKeyExternal(); $scope.color = $scope.wallet.color; $scope.data = {}; - $scope.displayAmount = getDisplayAmount($scope.tx.amountStr); - $scope.displayUnit = getDisplayUnit($scope.tx.amountStr); displayFeeValues(); initActionList(); checkPaypro(); @@ -43,14 +41,6 @@ angular.module('copayApp.controllers').controller('txpDetailsController', functi $scope.buttonText += gettextCatalog.getString('to accept'); }; - function getDisplayAmount(amountStr) { - return amountStr.split(' ')[0]; - }; - - function getDisplayUnit(amountStr) { - return amountStr.split(' ')[1]; - }; - function initActionList() { $scope.actionList = []; diff --git a/src/js/controllers/tx-details.js b/src/js/controllers/tx-details.js index 5af36a0e0..6d76fe84c 100644 --- a/src/js/controllers/tx-details.js +++ b/src/js/controllers/tx-details.js @@ -1,6 +1,6 @@ 'use strict'; -angular.module('copayApp.controllers').controller('txDetailsController', function($rootScope, $log, $ionicHistory, $scope, $timeout, walletService, lodash, gettextCatalog, profileService, externalLinkService, popupService, ongoingProcess, txFormatService, txConfirmNotification) { +angular.module('copayApp.controllers').controller('txDetailsController', function($rootScope, $log, $ionicHistory, $scope, $timeout, walletService, lodash, gettextCatalog, profileService, externalLinkService, popupService, ongoingProcess, txFormatService, txConfirmNotification, feeService) { var txId; var listeners = []; @@ -40,14 +40,6 @@ angular.module('copayApp.controllers').controller('txDetailsController', functio }); }); - function getDisplayAmount(amountStr) { - return amountStr.split(' ')[0]; - } - - function getDisplayUnit(amountStr) { - return amountStr.split(' ')[1]; - } - function updateMemo() { walletService.getTxNote($scope.wallet, $scope.btx.txid, function(err, note) { if (err) { @@ -122,12 +114,14 @@ angular.module('copayApp.controllers').controller('txDetailsController', functio if ($scope.btx.action == 'moved') $scope.title = gettextCatalog.getString('Moved Funds'); } - $scope.displayAmount = getDisplayAmount($scope.btx.amountStr); - $scope.displayUnit = getDisplayUnit($scope.btx.amountStr); - updateMemo(); initActionList(); getFiatRate(); + + feeService.getLowAmount($scope.wallet, function(err, amount) { + $scope.btx.lowAmount = tx.amount< amount; + }); + $timeout(function() { $scope.$apply(); }); diff --git a/src/js/controllers/walletDetails.js b/src/js/controllers/walletDetails.js index 24cf0afbc..259ca2ff3 100644 --- a/src/js/controllers/walletDetails.js +++ b/src/js/controllers/walletDetails.js @@ -1,6 +1,6 @@ 'use strict'; -angular.module('copayApp.controllers').controller('walletDetailsController', function($scope, $rootScope, $interval, $timeout, $filter, $log, $ionicModal, $ionicPopover, $state, $stateParams, $ionicHistory, profileService, lodash, configService, platformInfo, walletService, txpModalService, externalLinkService, popupService, addressbookService, storageService, $ionicScrollDelegate, $window, bwcError, gettextCatalog, timeService) { +angular.module('copayApp.controllers').controller('walletDetailsController', function($scope, $rootScope, $interval, $timeout, $filter, $log, $ionicModal, $ionicPopover, $state, $stateParams, $ionicHistory, profileService, lodash, configService, platformInfo, walletService, txpModalService, externalLinkService, popupService, addressbookService, storageService, $ionicScrollDelegate, $window, bwcError, gettextCatalog, timeService, feeService) { var HISTORY_SHOW_LIMIT = 10; var currentTxHistoryPage = 0; @@ -154,9 +154,10 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun }); }; - $timeout(function() { + feeService.getLowAmount($scope.wallet, function(err, lowAmount){ walletService.getTxHistory($scope.wallet, { progressFn: progressFn, + lowAmount: lowAmount, }, function(err, txHistory) { $scope.updatingTxHistory = false; if (err) { diff --git a/src/js/services/feeService.js b/src/js/services/feeService.js index c88b867ca..a3e554f38 100644 --- a/src/js/services/feeService.js +++ b/src/js/services/feeService.js @@ -4,6 +4,7 @@ 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 = { @@ -43,7 +44,7 @@ angular.module('copayApp.services').factory('feeService', function($log, $timeou var feeRate = feeLevelRate.feePerKB; - if (!fromCache) $log.debug('Dynamic fee: ' + feeLevel + '/' + network +' ' + (feeLevelRate.feePerKB / 1000).toFixed() + ' SAT/B'); + if (!fromCache) $log.debug('Dynamic fee: ' + feeLevel + '/' + network + ' ' + (feeLevelRate.feePerKB / 1000).toFixed() + ' SAT/B'); return cb(null, feeRate); }); @@ -55,8 +56,8 @@ angular.module('copayApp.services').factory('feeService', function($log, $timeou root.getFeeLevels = function(cb) { - if (cache.updateTs > Date.now() - CACHE_TIME_TS * 1000 ) { - $timeout( function() { + if (cache.updateTs > Date.now() - CACHE_TIME_TS * 1000) { + $timeout(function() { return cb(null, cache.data, true); }, 1); } @@ -70,7 +71,7 @@ angular.module('copayApp.services').factory('feeService', function($log, $timeou return cb(gettextCatalog.getString('Could not get dynamic fee')); } - cache.updateTs =Date.now(); + cache.updateTs = Date.now(); cache.data = { 'livenet': levelsLivenet, 'testnet': levelsTestnet @@ -81,5 +82,52 @@ 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 8c5a93662..5f1118a1d 100644 --- a/src/js/services/profileService.js +++ b/src/js/services/profileService.js @@ -90,6 +90,8 @@ 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/txFormatService.js b/src/js/services/txFormatService.js index 7524bb548..fee503a18 100644 --- a/src/js/services/txFormatService.js +++ b/src/js/services/txFormatService.js @@ -93,6 +93,11 @@ angular.module('copayApp.services').factory('txFormatService', function($filter, tx.alternativeAmountStr = root.formatAlternativeStr(tx.amount); tx.feeStr = root.formatAmountStr(tx.fee || tx.fees); + if (tx.amountStr) { + tx.amountValueStr = tx.amountStr.split(' ')[0]; + tx.amountUnitStr = tx.amountStr.split(' ')[1]; + } + return tx; }; diff --git a/src/js/services/walletService.js b/src/js/services/walletService.js index a9d45f3ff..7f53f1ce8 100644 --- a/src/js/services/walletService.js +++ b/src/js/services/walletService.js @@ -413,7 +413,6 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim $log.debug('Fixing Tx Cache Unit to:' + name) lodash.each(txs, function(tx) { - tx.amountStr = txFormatService.formatAmount(tx.amount) + name; tx.feeStr = txFormatService.formatAmount(tx.fees) + name; }); @@ -511,6 +510,15 @@ 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; + }); + }; + + updateLowAmount(txs); + updateNotes(function() { // @@ -567,9 +575,9 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim root.getTx = function(wallet, txid, cb) { - function finish(list){ + function finish(list) { var tx = lodash.find(list, { - txid: txid + txid: txid }); if (!tx) return cb('Could not get transaction'); @@ -602,7 +610,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim }); }; - + root.getTxHistory = function(wallet, opts, cb) { opts = opts || {}; diff --git a/src/sass/views/confirm.scss b/src/sass/views/confirm.scss index 8adc61672..9ceee92c4 100644 --- a/src/sass/views/confirm.scss +++ b/src/sass/views/confirm.scss @@ -5,6 +5,10 @@ float: none; .fee-rate { display: inline-block; + .warn { + color: red; + } + } } .icon-amazon { diff --git a/src/sass/views/includes/txp-details.scss b/src/sass/views/includes/txp-details.scss index c68841a4c..7303c1f82 100644 --- a/src/sass/views/includes/txp-details.scss +++ b/src/sass/views/includes/txp-details.scss @@ -98,7 +98,7 @@ &.low-fees { display: flex; font-size: 14px; - color: #aaa; + color: #777; align-items: center; i { padding-right: 20px; diff --git a/www/views/confirm.html b/www/views/confirm.html index cff04ebf3..0048cb951 100644 --- a/www/views/confirm.html +++ b/www/views/confirm.html @@ -81,8 +81,15 @@ {{'Fee:' | translate}} {{tx.feeLevelName | translate}} {{tx.txp[wallet.id].feeStr || '...'}} - {{tx.txp[wallet.id].alternativeFeeStr || '...'}} - {{tx.txp[wallet.id].feeRatePerStr}} of the transaction + {{tx.txp[wallet.id].alternativeFeeStr || '...'}}  + · +   + {{tx.txp[wallet.id].feeRatePerStr}} of the sending amount + + + + diff --git a/www/views/includes/walletHistory.html b/www/views/includes/walletHistory.html index bdd372e2f..81124ab7d 100644 --- a/www/views/includes/walletHistory.html +++ b/www/views/includes/walletHistory.html @@ -26,6 +26,11 @@ Low fees +
+ + Amount too low to spend +
+
diff --git a/www/views/modals/txp-details.html b/www/views/modals/txp-details.html index a093ba441..c5649201a 100644 --- a/www/views/modals/txp-details.html +++ b/www/views/modals/txp-details.html @@ -19,7 +19,7 @@ Sending
-
{{displayAmount}} {{displayUnit}}
+
{{tx.amountValueStr}} {{tx.amountUnitStr}}
{{tx.alternativeAmountStr}}
diff --git a/www/views/tx-details.html b/www/views/tx-details.html index 5af45c3aa..cd13d7535 100644 --- a/www/views/tx-details.html +++ b/www/views/tx-details.html @@ -24,7 +24,7 @@ Receiving
-
{{displayAmount}} {{displayUnit}}
+
{{btx.amountValueStr}} {{btx.amountUnitStr}}
{{btx.alternativeAmountStr}} @@ -88,6 +88,11 @@ This transaction could take a long time to confirm or could be dropped due to the low fees set by the sender
+
+ + This transaction amount is too small given current Bitcoin network fees. Spending these funds will incur in fees comparable to the amount itself. +
+
Confirmations From b83c0590dcc53c1678521d858fc3aef3c1314ec2 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Thu, 22 Jun 2017 13:44:49 -0300 Subject: [PATCH 2/4] add low amount in txhistory/details and balance --- src/js/controllers/walletDetails.js | 19 ++++++- src/js/services/feeService.js | 47 ----------------- src/js/services/profileService.js | 2 - src/js/services/walletService.js | 79 +++++++++++++++++++++++++++++ www/views/tx-details.html | 3 +- www/views/walletDetails.html | 6 +++ 6 files changed, 104 insertions(+), 52 deletions(-) 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 + + +
From 44cd3cd4953f9996ec83206e167906692dd26148 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Thu, 22 Jun 2017 17:00:20 -0300 Subject: [PATCH 3/4] add balance warning --- src/js/controllers/addresses.js | 29 +++++++++++++++++++++++++++-- src/js/services/walletService.js | 27 ++++++++++++++++----------- www/views/addresses.html | 30 +++++++++++++++++++++++++++++- 3 files changed, 72 insertions(+), 14 deletions(-) diff --git a/src/js/controllers/addresses.js b/src/js/controllers/addresses.js index cfc324521..19db9ad11 100644 --- a/src/js/controllers/addresses.js +++ b/src/js/controllers/addresses.js @@ -1,6 +1,6 @@ 'use strict'; -angular.module('copayApp.controllers').controller('addressesController', function($scope, $log, $stateParams, $state, $timeout, $ionicHistory, $ionicScrollDelegate, configService, popupService, gettextCatalog, ongoingProcess, lodash, profileService, walletService, bwcError, platformInfo, appConfigService) { +angular.module('copayApp.controllers').controller('addressesController', function($scope, $log, $stateParams, $state, $timeout, $ionicHistory, $ionicScrollDelegate, configService, popupService, gettextCatalog, ongoingProcess, lodash, profileService, walletService, bwcError, platformInfo, appConfigService, txFormatService, feeService) { var UNUSED_ADDRESS_LIMIT = 5; var BALANCE_ADDRESS_LIMIT = 5; var config = configService.getSync().wallet.settings; @@ -55,7 +55,7 @@ angular.module('copayApp.controllers').controller('addressesController', functio $scope.latestWithBalance = lodash.slice(withBalance, 0, BALANCE_ADDRESS_LIMIT); lodash.each(withBalance, function(a) { - a.balanceStr = (a.amount * satToUnit).toFixed(unitDecimals) + ' ' + unitName; + a.balanceStr = txFormatService.formatAmount(a.amount); }); $scope.viewAll = { @@ -72,6 +72,31 @@ angular.module('copayApp.controllers').controller('addressesController', functio }); }); }); + + + + feeService.getFeeLevels(function(err, levels){ + walletService.getLowUtxos($scope.wallet, levels, function(err, resp) { + if (err) return; + + if (resp.allUtxos && resp.allUtxos.length) { + + + var allSum = lodash.sum(resp.allUtxos || 0, 'satoshis'); + var per = (resp.minFee / allSum) * 100; + + $scope.lowWarning = resp.warning; + $scope.lowUtxosNb = resp.lowUtxos.length; + $scope.allUtxosNb = resp.allUtxos.length; + $scope.lowUtxosSum = txFormatService.formatAmountStr(lodash.sum(resp.lowUtxos || 0, 'satoshis')); + $scope.allUtxosSum = txFormatService.formatAmountStr(allSum); + $scope.minFee = txFormatService.formatAmountStr(resp.minFee || 0); + $scope.minFeePer = per.toFixed(2) + '%'; + + + } + }); + }); }; function processPaths(list) { diff --git a/src/js/services/walletService.js b/src/js/services/walletService.js index 5e8930c82..2a33cf091 100644 --- a/src/js/services/walletService.js +++ b/src/js/services/walletService.js @@ -1,10 +1,12 @@ 'use strict'; 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; + // Ratio low amount warning (fee/amount) in incoming TX + var LOW_AMOUNT_RATIO = 0.15; + + // Ratio of "many utxos" warning in total balance (fee/amount) + var TOTAL_LOW_WARNING_RATIO = .3; var root = {}; @@ -921,15 +923,20 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim // Approx utxo amount, from which the uxto is economically redeemable - root.getLowAmount = function(wallet, feeLevels, nbOutputs) { + root.getMinFee = 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 size * lowLevelRate; + }; - return parseInt(minFee / (LOW_AMOUNT_RATIO)); + + // Approx utxo amount, from which the uxto is economically redeemable + root.getLowAmount = function(wallet, feeLevels, nbOutputs) { + var minFee = root.getMinFee(wallet,feeLevels, nbOutputs); + return parseInt( minFee / LOW_AMOUNT_RATIO); }; @@ -939,14 +946,10 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim 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; }); @@ -954,8 +957,10 @@ console.log('[walletService.js.950:lowAmount1:]',lowAmount1); //TODO var totalLow = lodash.sum(lowUtxos, 'satoshis'); return cb(err, { - lowUtxos: lowUtxos, + allUtxos: resp || [], + lowUtxos: lowUtxos || [], warning: lowAmountN / total > TOTAL_LOW_WARNING_RATIO, + minFee: root.getMinFee(wallet, levels, resp.length), }); }); }; diff --git a/www/views/addresses.html b/www/views/addresses.html index 5e8ef5b32..2698aa55f 100644 --- a/www/views/addresses.html +++ b/www/views/addresses.html @@ -35,7 +35,7 @@
-
+
Unused Addresses
@@ -70,6 +70,34 @@
{{w.balanceStr}}
+ + +
+
+ Wallet Inputs +
+ +
+ Total wallet inputs +
+ {{allUtxosNb}} [{{allUtxosSum}}] +
+
+
+ Low amount inputs +
+ {{lowUtxosNb}} [{{ lowUtxosSum }}] +
+
+ +
+ Approximate fee to move all wallet's balance (with normal priority) +
+ {{minFeePer}} [{{minFee}}] +
+
+ +
From bdf0f594273487aad6963ab5a64cddb01e97b8b5 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Fri, 23 Jun 2017 08:52:45 -0300 Subject: [PATCH 4/4] fix sendmax --- src/js/controllers/confirm.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/js/controllers/confirm.js b/src/js/controllers/confirm.js index 9623206f2..1d455c4b9 100644 --- a/src/js/controllers/confirm.js +++ b/src/js/controllers/confirm.js @@ -243,13 +243,15 @@ angular.module('copayApp.controllers').controller('confirmController', function( updateAmount(); refresh(); + // End of quick refresh, before wallet is selected. + if (!wallet)return cb(); + feeService.getFeeRate(tx.network, tx.feeLevel, function(err, feeRate) { if (err) return cb(err); tx.feeRate = feeRate; tx.feeLevelName = feeService.feeOpts[tx.feeLevel]; - // End of quick refresh, before wallet is selected. if (!wallet) return cb();