mirror of https://github.com/BTCPrivate/copay.git
Merge pull request #1740 from cmgustavo/bug/tx-proposals
Refresh list of pending transactions proposals after any events
This commit is contained in:
commit
d475ea4f16
|
@ -16,24 +16,10 @@ angular.module('copayApp.controllers').controller('HistoryController',
|
|||
$scope.blockchain_txs = [];
|
||||
$scope.alternativeCurrency = [];
|
||||
|
||||
var satToUnit = 1 / w.settings.unitToSatoshi;
|
||||
|
||||
|
||||
$scope.update = function() {
|
||||
$scope.loading = true;
|
||||
var from = ($scope.txpCurrentPage - 1) * $scope.txpItemsPerPage;
|
||||
var opts = {
|
||||
pending: false,
|
||||
skip: [from, from + $scope.txpItemsPerPage]
|
||||
};
|
||||
controllerUtils.updateTxs(opts);
|
||||
setTimeout(function() {
|
||||
$rootScope.$digest();
|
||||
}, 0);
|
||||
$scope.getTransactions();
|
||||
};
|
||||
|
||||
|
||||
|
||||
$scope.show = function() {
|
||||
$scope.loading = true;
|
||||
setTimeout(function() {
|
||||
|
@ -61,9 +47,6 @@ angular.module('copayApp.controllers').controller('HistoryController',
|
|||
|
||||
_.each(res, function(r) {
|
||||
r.ts = r.minedTs || r.sentTs;
|
||||
if (r.action === 'sent' && r.peerActions) {
|
||||
r.actionList = controllerUtils.getActionList(r.peerActions);
|
||||
}
|
||||
});
|
||||
$scope.blockchain_txs = w.cached_txs = res;
|
||||
$scope.loading = false;
|
||||
|
@ -76,13 +59,11 @@ angular.module('copayApp.controllers').controller('HistoryController',
|
|||
|
||||
$scope.hasAction = function(actions, action) {
|
||||
return actions.hasOwnProperty('create');
|
||||
}
|
||||
};
|
||||
|
||||
$scope.getShortNetworkName = function() {
|
||||
var w = $rootScope.wallet;
|
||||
return w.getNetworkName().substring(0, 4);
|
||||
};
|
||||
|
||||
// Autoload transactions
|
||||
$scope.getTransactions();
|
||||
});
|
||||
|
|
|
@ -72,11 +72,8 @@ angular.module('copayApp.controllers').controller('SendController',
|
|||
});
|
||||
|
||||
$scope.loadTxs = function() {
|
||||
var opts = {
|
||||
pending: true,
|
||||
skip: null
|
||||
};
|
||||
controllerUtils.updateTxs(opts);
|
||||
controllerUtils.updateTxs();
|
||||
|
||||
setTimeout(function() {
|
||||
$scope.loading = false;
|
||||
$rootScope.$digest();
|
||||
|
|
|
@ -72,10 +72,6 @@ angular.module('copayApp.controllers').controller('SidebarController', function(
|
|||
if (controllerUtils.isFocusedWallet(wid)) return;
|
||||
var w = $rootScope.iden.getWalletById(wid);
|
||||
$scope.wallets.push(w);
|
||||
controllerUtils.updateTxs({
|
||||
wallet: w,
|
||||
pending: true
|
||||
});
|
||||
controllerUtils.updateBalance(w, function() {
|
||||
$rootScope.$digest();
|
||||
})
|
||||
|
|
|
@ -361,7 +361,7 @@ Wallet.prototype._processProposalEvents = function(senderId, m) {
|
|||
} else {
|
||||
ev = {
|
||||
type: 'corrupt',
|
||||
cId: senderId,
|
||||
cId: senderId
|
||||
};
|
||||
}
|
||||
if (ev)
|
||||
|
@ -513,7 +513,7 @@ Wallet.prototype._onReject = function(senderId, data) {
|
|||
this.emitAndKeepAlive('txProposalEvent', {
|
||||
type: 'rejected',
|
||||
cId: senderId,
|
||||
txId: data.ntxid,
|
||||
txId: data.ntxid
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -536,7 +536,7 @@ Wallet.prototype._onSeen = function(senderId, data) {
|
|||
this.emitAndKeepAlive('txProposalEvent', {
|
||||
type: 'seen',
|
||||
cId: senderId,
|
||||
txId: data.ntxid,
|
||||
txId: data.ntxid
|
||||
});
|
||||
|
||||
};
|
||||
|
@ -1281,6 +1281,64 @@ Wallet.prototype.getTxProposals = function() {
|
|||
return ret;
|
||||
};
|
||||
|
||||
/**
|
||||
* @desc get list of actions (see {@link getPendingTxProposals})
|
||||
*/
|
||||
Wallet.prototype._getActionList = function(actions) {
|
||||
if (!actions) return;
|
||||
var peers = Object.keys(actions).map(function(i) {
|
||||
return {
|
||||
cId: i,
|
||||
actions: actions[i]
|
||||
}
|
||||
});
|
||||
|
||||
return peers.sort(function(a, b) {
|
||||
return !!b.actions.create - !!a.actions.create;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @desc Retrieve Pendings Transaction proposals (see {@link TxProposals})
|
||||
* @return {Object[]} each object returned represents a transaction proposal
|
||||
*/
|
||||
Wallet.prototype.getPendingTxProposals = function() {
|
||||
var that = this;
|
||||
var ret = [];
|
||||
ret.txs = [];
|
||||
var pendingForUs = 0;
|
||||
var txps = this.getTxProposals();
|
||||
var satToUnit = 1 / this.settings.unitToSatoshi;
|
||||
|
||||
_.find(txps, function(txp) {
|
||||
if (txp.isPending) {
|
||||
pendingForUs++;
|
||||
var tx = txp.builder.build();
|
||||
var outs = [];
|
||||
tx.outs.forEach(function(o) {
|
||||
var addr = bitcore.Address.fromScriptPubKey(o.getScript(), that.getNetworkName())[0].toString();
|
||||
if (!that.addressIsOwn(addr, {
|
||||
excludeMain: true
|
||||
})) {
|
||||
outs.push({
|
||||
address: addr,
|
||||
value: bitcore.util.valueToBigInt(o.getValue()) * satToUnit,
|
||||
});
|
||||
}
|
||||
});
|
||||
// extra fields
|
||||
txp.outs = outs;
|
||||
txp.fee = txp.builder.feeSat * satToUnit;
|
||||
txp.missingSignatures = tx.countInputMissingSignatures(0);
|
||||
txp.actionList = that._getActionList(txp.peerActions);
|
||||
ret.txs.push(txp);
|
||||
}
|
||||
});
|
||||
|
||||
ret.pendingForUs = pendingForUs;
|
||||
return ret;
|
||||
};
|
||||
|
||||
/**
|
||||
* @desc Removes old transactions
|
||||
* @param {boolean} deleteAll - if true, remove all the transactions
|
||||
|
@ -2882,6 +2940,13 @@ Wallet.prototype.getTransactionHistory = function(cb) {
|
|||
tx.merchant = proposal.merchant;
|
||||
tx.peerActions = proposal.peerActions;
|
||||
tx.finallyRejected = proposal.finallyRejected;
|
||||
tx.merchant = proposal.merchant;
|
||||
tx.peerActions = proposal.peerActions;
|
||||
tx.finallyRejected = proposal.finallyRejected;
|
||||
|
||||
if (tx.peerActions) {
|
||||
tx.actionList = self._getActionList(tx.peerActions);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -63,13 +63,10 @@ angular.module('copayApp.services')
|
|||
|
||||
|
||||
root.updateTxsAndBalance = _.debounce(function(w) {
|
||||
root.updateTxs({
|
||||
wallet: w,
|
||||
pending: true,
|
||||
});
|
||||
root.updateTxs();
|
||||
root.updateBalance(w, function() {
|
||||
$rootScope.$digest();
|
||||
})
|
||||
});
|
||||
}, 3000);
|
||||
|
||||
root.installWalletHandlers = function($scope, w) {
|
||||
|
@ -139,19 +136,29 @@ angular.module('copayApp.services')
|
|||
|
||||
w.on('txProposalEvent', function(e) {
|
||||
|
||||
root.updateTxsAndBalance(w);
|
||||
// TODO: add wallet name notification
|
||||
var user = w.publicKeyRing.nicknameForCopayer(e.cId);
|
||||
var name = w.getName();
|
||||
switch (e.type) {
|
||||
case 'new':
|
||||
notification.info('['+ name +'] New Transaction',
|
||||
$filter('translate')('You received a transaction proposal from') + ' ' + user);
|
||||
break;
|
||||
case 'signed':
|
||||
notification.info('Transaction Update', $filter('translate')('A transaction was signed by') + ' ' + user);
|
||||
notification.info('['+ name +'] Transaction Signed',
|
||||
$filter('translate')('A transaction was signed by') + ' ' + user);
|
||||
break;
|
||||
case 'rejected':
|
||||
notification.info('Transaction Update', $filter('translate')('A transaction was rejected by') + ' ' + user);
|
||||
notification.info('['+ name +'] Transaction Rejected',
|
||||
$filter('translate')('A transaction was rejected by') + ' ' + user);
|
||||
break;
|
||||
case 'corrupt':
|
||||
notification.error('Transaction Error', $filter('translate')('Received corrupt transaction from') + ' ' + user);
|
||||
notification.error('['+ name +'] Transaction Error',
|
||||
$filter('translate')('Received corrupt transaction from') + ' ' + user);
|
||||
break;
|
||||
}
|
||||
$rootScope.$digest();
|
||||
});
|
||||
w.on('addressBookUpdated', function(dontDigest) {
|
||||
if (root.isFocusedWallet(wid)) {
|
||||
|
@ -210,6 +217,7 @@ angular.module('copayApp.services')
|
|||
$rootScope.wallet = w;
|
||||
w.updateFocusedTimestamp(Date.now());
|
||||
root.redirIfLogged();
|
||||
root.updateTxs();
|
||||
root.updateBalance(w, function() {
|
||||
$rootScope.$digest();
|
||||
})
|
||||
|
@ -323,75 +331,26 @@ angular.module('copayApp.services')
|
|||
});
|
||||
};
|
||||
|
||||
root.updateTxs = function(opts) {
|
||||
function computeAlternativeAmount(w, tx, cb) {
|
||||
rateService.whenAvailable(function() {
|
||||
_.each(tx.outs, function(out) {
|
||||
var valueSat = out.value * w.settings.unitToSatoshi;
|
||||
out.alternativeAmount = rateService.toFiat(valueSat, w.settings.alternativeIsoCode);
|
||||
out.alternativeIsoCode = w.settings.alternativeIsoCode;
|
||||
});
|
||||
if (cb) return cb();
|
||||
root.computeAlternativeAmount = function(w, tx, cb) {
|
||||
rateService.whenAvailable(function() {
|
||||
_.each(tx.outs, function(out) {
|
||||
var valueSat = out.value * w.settings.unitToSatoshi;
|
||||
out.alternativeAmount = rateService.toFiat(valueSat, w.settings.alternativeIsoCode);
|
||||
out.alternativeIsoCode = w.settings.alternativeIsoCode;
|
||||
});
|
||||
};
|
||||
|
||||
var w = opts.wallet || $rootScope.wallet;
|
||||
if (!w) return;
|
||||
opts = opts || $rootScope.txsOpts || {};
|
||||
|
||||
var satToUnit = 1 / w.settings.unitToSatoshi;
|
||||
var myCopayerId = w.getMyCopayerId();
|
||||
var pendingForUs = 0;
|
||||
var inT = w.getTxProposals().sort(function(t1, t2) {
|
||||
return t2.createdTs - t1.createdTs
|
||||
if (cb) return cb(tx);
|
||||
});
|
||||
var txs = [];
|
||||
};
|
||||
|
||||
inT.forEach(function(i, index) {
|
||||
if (opts.skip && (index < opts.skip[0] || index >= opts.skip[1])) {
|
||||
return txs.push(null);
|
||||
}
|
||||
|
||||
if (i.isPending && myCopayerId != i.creator && !i.rejectedByUs && !i.signedByUs) {
|
||||
pendingForUs++;
|
||||
}
|
||||
|
||||
if (!!opts.pending == !!i.isPending) {
|
||||
var tx = i.builder.build();
|
||||
var outs = [];
|
||||
tx.outs.forEach(function(o) {
|
||||
var addr = bitcore.Address.fromScriptPubKey(o.getScript(), w.getNetworkName())[0].toString();
|
||||
if (!w.addressIsOwn(addr, {
|
||||
excludeMain: true
|
||||
})) {
|
||||
outs.push({
|
||||
address: addr,
|
||||
value: bitcore.util.valueToBigInt(o.getValue()) * satToUnit,
|
||||
});
|
||||
}
|
||||
});
|
||||
// extra fields
|
||||
i.outs = outs;
|
||||
i.fee = i.builder.feeSat * satToUnit;
|
||||
i.missingSignatures = tx.countInputMissingSignatures(0);
|
||||
i.actionList = getActionList(i.peerActions);
|
||||
if (i.isPending) {
|
||||
computeAlternativeAmount(w, i);
|
||||
}
|
||||
txs.push(i);
|
||||
}
|
||||
});
|
||||
|
||||
// Disabling this as discrepancies in local time on copayer machines is causing
|
||||
// valid TXPs to get removed
|
||||
//w.removeTxWithSpentInputs();
|
||||
|
||||
$rootScope.txs = txs;
|
||||
$rootScope.txsOpts = opts;
|
||||
if ($rootScope.pendingTxCount < pendingForUs) {
|
||||
$rootScope.txAlertCount = pendingForUs;
|
||||
root.updateTxs = function() {
|
||||
var w = $rootScope.wallet;
|
||||
if (!w) return root.onErrorDigest();
|
||||
var res = w.getPendingTxProposals();
|
||||
$rootScope.txps = res.txs;
|
||||
if ($rootScope.pendingTxCount < res.pendingForUs) {
|
||||
$rootScope.txAlertCount = res.pendingForUs;
|
||||
}
|
||||
$rootScope.pendingTxCount = pendingForUs;
|
||||
$rootScope.pendingTxCount = res.pendingForUs;
|
||||
};
|
||||
|
||||
root.deleteWallet = function($scope, w) {
|
||||
|
@ -404,24 +363,5 @@ angular.module('copayApp.services')
|
|||
});
|
||||
};
|
||||
|
||||
root.getActionList = function(actions) {
|
||||
return getActionList(actions);
|
||||
};
|
||||
|
||||
function getActionList(actions) {
|
||||
var peers = Object.keys(actions).map(function(i) {
|
||||
return {
|
||||
cId: i,
|
||||
actions: actions[i]
|
||||
}
|
||||
});
|
||||
|
||||
return peers.sort(function(a, b) {
|
||||
return !!b.actions.create - !!a.actions.create;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
return root;
|
||||
});
|
||||
|
|
|
@ -43,6 +43,7 @@ describe("Unit: Controllers", function() {
|
|||
scope = $rootScope.$new();
|
||||
$rootScope.iden = sinon.stub();
|
||||
$rootScope.safeUnspentCount = 1;
|
||||
$rootScope.pendingTxCount = 0;
|
||||
|
||||
var w = {};
|
||||
w.isReady = sinon.stub().returns(true);
|
||||
|
@ -72,7 +73,10 @@ describe("Unit: Controllers", function() {
|
|||
w.sendTx = sinon.stub().yields(null);
|
||||
w.requiresMultipleSignatures = sinon.stub().returns(true);
|
||||
w.getTxProposals = sinon.stub().returns([1, 2, 3]);
|
||||
|
||||
w.getPendingTxProposals = sinon.stub().returns({
|
||||
txs : [{ isPending : true }],
|
||||
pendingForUs: 1
|
||||
});
|
||||
|
||||
$rootScope.wallet = w;
|
||||
}));
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
<div class="send" data-ng-controller="SendController" data-ng-init="loadTxs()">
|
||||
<div class="send" ng-controller="SendController" ng-init="loadTxs()">
|
||||
<div ng-show='$root.wallet.isReady()'>
|
||||
|
||||
<div class="row" ng-show="txs.length != 0">
|
||||
<div class="row" ng-show="$root.txps.length != 0">
|
||||
<div class="large-12 columns">
|
||||
<h2 translate>Pending Transactions Proposals</h2>
|
||||
<div class="last-transactions"
|
||||
ng-repeat="tx in txs | paged"
|
||||
ng-repeat="tx in $root.txps | paged"
|
||||
ng-include="'views/includes/transaction.html'"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-show="txs.length != 0" class="line-dashed-h m20b"></div>
|
||||
<div ng-show="$root.txps.length != 0" class="line-dashed-h m20b"></div>
|
||||
|
||||
<h1 class="hide-for-large-up">{{$root.title}}</h1>
|
||||
<div class="row">
|
||||
|
|
Loading…
Reference in New Issue