balances working

This commit is contained in:
Matias Alejo Garcia 2016-08-15 10:25:43 -03:00
commit 9f039d8c34
No known key found for this signature in database
GPG key ID: 02470DB551277AB3
9 changed files with 656 additions and 271 deletions

View file

@ -1,20 +1,20 @@
<span ng-show="index.isShared" class="size-12"><span translate>{{index.m}}-of-{{index.n}}</span></span> <span ng-show="wallet.isShared" class="size-12"><span translate>{{wallet.m}}-of-{{wallet.n}}</span></span>
<span ng-show="index.isSingleAddress" class="size-12"><span translate>Auditable</span></span> <span ng-show="wallet.isSingleAddress" class="size-12"><span translate>Auditable</span></span>
<img style="height:0.6em; margin-right: 1px;" ng-show="index.network != 'livenet'" src="img/icon-testnet-white.svg"> <img style="height:0.6em; margin-right: 1px;" ng-show="wallet.network != 'livenet'" src="img/icon-testnet-white.svg">
<img style="height:0.6em; margin-right: 1px;" ng-show="!index.canSign && !index.isPrivKeyExternal" <img style="height:0.6em; margin-right: 1px;" ng-show="!wallet.canSign() && !wallet.isPrivKeyExternal()"
src="img/icon-read-only-white.svg"> src="img/icon-read-only-white.svg">
<img style="height:0.6em; margin-right: 1px;" ng-show="index.externalSource == 'trezor'" <img style="height:0.6em; margin-right: 1px;" ng-show="wallet.getPrivKeyExternalSourceName() == 'trezor'"
src="img/icon-trezor-white.svg"> src="img/icon-trezor-white.svg">
<img style="height:0.6em; margin-right: 1px;" ng-show="index.externalSource == 'ledger'" <img style="height:0.6em; margin-right: 1px;" ng-show="wallet.getPrivKeyExternalSourceName() == 'ledger'"
src="img/icon-ledger-white.svg"> src="img/icon-ledger-white.svg">
<span class="size-12 dib" style="height:0.6em; margin-right: 1px;" ng-show="index.account">#{{index.account || 0}} </span> <span class="size-12 dib" style="height:0.6em; margin-right: 1px;" ng-show="wallet.account">#{{wallet.account || 0}} </span>
<img style="height:0.6em; margin-right: 1px;" ng-show="index.isPrivKeyEncrypted" src="img/icon-lock-white.svg"> <img style="height:0.6em; margin-right: 1px;" ng-show="wallet.isPrivKeyEncrypted()" src="img/icon-lock-white.svg">
<!-- <img style="height:1em" ng&#45;show="index.preferences.email" src="img/icon&#45;email.svg"> --> <!-- <img style="height:1em" ng&#45;show="wallet.preferences.email" src="img/icon&#45;email.svg"> -->
<img style="height:0.6em; margin-right: 1px;" ng-show="index.usingCustomBWS" src="img/icon-bws-white.svg"> <img style="height:0.6em; margin-right: 1px;" ng-show="wallet.usingCustomBWS" src="img/icon-bws-white.svg">
<img style="height:0.6em" class="animated flash infinite" ng-show="index.loadingWallet || <img style="height:0.6em" class="animated flash infinite" ng-show="wallet.loadingWallet ||
index.updatingTxHistory" src="img/icon-sync-white.svg"> index.updatingTxHistory" src="img/icon-sync-white.svg">

View file

@ -1,19 +1,25 @@
<ion-view view-title="Home"> <ion-view view-title="Home">
<ion-content class="padding home" ng-controller="tabHomeController"> <ion-content class="padding home" ng-controller="tabHomeController">
<a href="#/add"><i class="ion-ios-plus-outline right"></i></a>
<h2>Wallets </h2> <h2>Wallets </h2>
<a href="#/add">+</a>
<div class="list card"> <div class="list card">
<ul class="pr"> <ul class="pr">
<li ng-show="wallets[0]" <li ng-show="wallets[0]"
ng-repeat="item in wallets track by $index" class="item item-icon-left" ng-repeat="item in wallets track by $index" class="item item-icon-left"
menu-toggle href ui-sref="walletHome" on-tap="openWallet(item.id, index.walletId)"> menu-toggle href ui-sref="walletDetails({'walletId': item.id})">
<i class="icon icon-wallet size-21" ng-style="{'color':item.color}"></i> <i class="icon icon-wallet size-21" ng-style="{'color':item.color}"></i>
{{item.name || item.id}} {{item.name || item.id}}
<span class="item-note" ng-show="item.n > 1"> <span ng-show="item.n > 1">
{{item.m}}-of-{{item.n}} [ {{item.m}}-of-{{item.n}} ]
</span> </span>
<span class="item-note">
{{item.availableBalanceStr}}
</span>
</li> </li>
</ul> </ul>
</div> </div>

View file

@ -0,0 +1,230 @@
<div ng-controller="walletDetailsController">
<div class="onGoingProcess" ng-show="wallet.updating">
<div class="onGoingProcess-content" ng-style="{'background-color':wallet.color}">
<div class="spinner">
<div class="rect1"></div>
<div class="rect2"></div>
<div class="rect3"></div>
<div class="rect4"></div>
<div class="rect5"></div>
</div>
<span translate>Updating Wallet...</span>
</div>
</div>
<div class="oh">
<div id="walletHome" class="walletHome">
<ion-content delegate-handle="my-handle" overflow-scroll="true">
<div class="oh pr">
<div ng-style="{'background-color':wallet.color}" class="amount">
<div ng-if="!wallet.notAuthorized && !wallet.updating">
<div class="size-14 m10b" ng-if="wallet.totalBalanceAlternative">{{wallet.name}}</div>
<div class="m15t" ng-show="wallet.updateError" ng-click='update()'>
<span class="size-12 db m10b">{{wallet.updateError|translate}}</span>
<button class="outline white tiny round" translate>Tap to retry</button>
</div>
<div ng-show="wallet.walletScanStatus == 'error'" ng-click='wallet.retryScan()'>
<span translate>Scan status finished with error</span>
<br><span translate>Tap to retry</span>
</div>
<div ng-click='wallet.updateAll({triggerTxUpdate: true})' ng-show="!wallet.updateError && wallet.walletScanStatus != 'error' && !wallet.hideBalance" on-hold="hideToggle()">
<strong class="size-36">{{wallet.totalBalanceStr}}</strong>
<div class="size-14" ng-if="wallet.totalBalanceAlternative">{{wallet.totalBalanceAlternative}} {{wallet.alternativeIsoCode}}</div>
<div class="size-14" ng-if="wallet.pendingAmount">
<span translate>Pending Confirmation</span>: {{wallet.pendingAmountStr}}
</div>
</div>
<div ng-show="!wallet.updateError && wallet.walletScanStatus != 'error' && wallet.shouldHideBalance" on-hold="wallet.hideToggle()">
<strong class="size-24" translate>[Balance Hidden]</strong>
<div class="size-14" translate>
Tap and hold to show
</div>
</div>
</div>
<div ng-if="wallet.updating">
<div class="size-36">
<strong>...</strong>
</div>
</div>
</div> <!-- amount -->
<div class="wallet-info">
<span ng-include="'views/includes/walletInfo.html'"></span>
</div>
</div> <!-- oh -->
<div class="p60b">
<div class="oh pr m20t" ng-show="wallet.incorrectDerivation">
<div class="text-center text-warning">
<i class="fi-alert"></i>
<span translate>
WARNING: Key derivation is not working on this device/wallet. Actions cannot be performed on this wallet.
</span>
</div>
</div>
<div class="oh pr m20t" ng-show="wallet.notAuthorized && !wallet.updating">
<div class="text-center text-warning">
<i class="fi-alert"></i>
<span translate>
WARNING: Wallet not registered
</span>
</div>
<div class="text-center text-gray m15r m15l" translate>
This wallet is not registered at the given Bitcore Wallet Service (BWS). You can recreate it from the local information.
</div>
<div class="text-center m10t ">
<span class="button outline round dark-gray tiny"
ng-click="wallet.recreate()">
<span translate>Recreate</span>
</span>
</div>
</div>
<div class="release size-12" ng-show="newRelease" ng-click="$root.openExternalLink('https://github.com/bitpay/copay/releases/latest')">
<span>{{newRelease}}</span><i class="icon-arrow-right3 right size-18"></i>
</div>
<div ng-if="wallet.txps[0]">
<h4 ng-show="wallet.requiresMultipleSignatures" class="title m0" translate>Payment Proposals</h4>
<h4 ng-show="!wallet.requiresMultipleSignatures" class="title m0" translate>Unsent transactions</h4>
<div ng-repeat="tx in wallet.txps">
<div ng-include="wallet.txTemplateUrl"></div>
</div>
<div class="text-gray text-center size-12 p10t"
ng-show="wallet.lockedBalanceSat">
<span translate>Total Locked Balance</span>:
<b>{{wallet.lockedBalanceStr}} </b>
<span> {{wallet.lockedBalanceAlternative}}
{{wallet.alternativeIsoCode}} </span>
</div>
</div>
<!-- Activity -->
<h4 class="title" ng-click="wallet.startSearch(); openSearchModal()" ng-show="!wallet.notAuthorized">
<span translate>Activity</span>
<i class="dib m5l size-16 pointer fi-magnifying-glass"></i>
</h4>
<div class="oh pr m20t text-gray size-12 text-center"
ng-show="!wallet.loadingWallet && !wallet.txHistory[0] && !wallet.updatingTxHistory && !wallet.txHistoryError && !wallet.updateError && !wallet.notAuthorized"
translate>No transactions yet ZZZZ {{wallet.totalBalanceStr}}
</div>
<div class="oh pr" ng-show="(wallet.txHistory[0] || wallet.txProgress > 5) && !wallet.notAuthorized">
<div ng-show="wallet.updatingTxHistory && wallet.txProgress > 5">
<div class="row p20 text-center">
<div class="columns large-12 medium-12 small-12 m10b">
<ion-spinner class="spinner-dark" icon="lines"></ion-spinner>
</div>
<div class="size-12 text-gray m20t">
<div translate>{{wallet.txProgress}} transactions downloaded</div>
<div translate>Updating transaction history. Please stand by.</div>
</div>
</div>
</div>
<div ng-if="wallet.txHistory[0] && wallet.updatingTxHistory && wallet.newTx" class="row collapse last-transactions-content animated fadeInDown">
<div class="large-6 medium-6 small-6 columns size-14">
<div class="m10r left">
<img src="img/icon-new.svg" width="40">
</div>
<div class="m10t" style="background:#eee; width: 8em; margin-left: 52px; line-height:0.6em">
<span>&nbsp;</span>
</div>
<div style="margin-top:5px; background:#eee; width: 6em; margin-left: 52px; line-height:0.6em">
<span>&nbsp;</span>
</div>
</div>
</div>
<div ng-repeat="btx in wallet.txHistory track by btx.txid"
ng-click="openTxModal(btx)"
class="row collapse last-transactions-content">
<div class="large-6 medium-6 small-6 columns size-14">
<div class="m10r left">
<img src="img/icon-receive-history.svg" alt="sync" width="40" ng-show="btx.action == 'received'">
<img src="img/icon-sent-history.svg" alt="sync" width="40" ng-show="btx.action == 'sent'">
<img src="img/icon-moved.svg" alt="sync" width="40" ng-show="btx.action == 'moved'">
</div>
<div class="m10t">
<span ng-show="btx.action == 'received'">
<span class="ellipsis">
<span ng-if="btx.note.body">{{btx.note.body}}</span>
<span ng-if="!btx.note.body" translate> Received</span>
</span>
</span>
<span ng-show="btx.action == 'sent'">
<span class="ellipsis">
<span ng-if="btx.message">{{btx.message}}</span>
<span ng-if="!btx.message && btx.note.body">{{btx.note.body}}</span>
<span ng-if="!btx.message && !btx.note.body && wallet.addressbook[btx.addressTo]">{{wallet.addressbook[btx.addressTo]}}</span>
<span ng-if="!btx.message && !btx.note.body && !wallet.addressbook[btx.addressTo]" translate> Sent</span>
</span>
</span>
<span ng-show="btx.action == 'moved'">
<span class="ellipsis">
<span ng-if="btx.note.body">{{btx.note.body}}</span>
<span ng-if="!btx.note.body" translate>Moved</span>
</span>
</span>
<span class="label tu warning radius" ng-show="btx.action == 'invalid'" translate>Invalid</span>
</div>
</div>
<div class="large-5 medium-5 small-5 columns text-right" >
<span class="size-16" ng-class="{'text-bold': btx.recent}">
<span ng-if="btx.action == 'received'">+</span>
<span ng-if="btx.action == 'sent'">-</span>
<span class="size-12" ng-if="btx.action == 'invalid'" translate>
(possible double spend)
</span>
<span ng-if="btx.action != 'invalid'">
{{btx.amountStr}}
</span>
</span>
<div class="size-12 text-gray">
<time ng-if="btx.time">{{btx.time * 1000 | amTimeAgo}}</time>
<span translate class="text-warning"
ng-show="!btx.time && (!btx.confirmations || btx.confirmations == 0)">
Unconfirmed
</span>
</div>
</div>
<div class="large-1 medium-1 small-1 columns text-right m10t">
<i class="icon-arrow-right3 size-18"></i>
</div>
</div>
<div class="row m20t text-center" ng-show="wallet.historyRendering && !wallet.ching">
<div class="columns large-12 medium-12 small-12">
<ion-spinner class="spinner-stable" icon="lines"></ion-spinner>
</div>
</div>
<ion-infinite-scroll
ng-if="historyShowMore"
on-infinite="showMore()"
distance="1%">
</ion-infinite-scroll>
</div>
</div>
</ion-content>
<div class="extra-margin-bottom"></div>
</div> <!-- END WalletHome -->
</div>
</div>

View file

@ -19,35 +19,14 @@ angular.module('copayApp.controllers').controller('tabHomeController',
self.setWallets(); self.setWallets();
}); });
self.setWallets = function() { self.setWallets = function() {
if (!profileService.profile) return; $scope.wallets = profileService.getWallets();
var config = configService.getSync();
config.colorFor = config.colorFor || {};
config.aliasFor = config.aliasFor || {};
// Sanitize empty wallets (fixed in BWC 1.8.1, and auto fixed when wallets completes)
var credentials = lodash.filter(profileService.profile.credentials, 'walletName');
var ret = lodash.map(credentials, function(c) {
return {
m: c.m,
n: c.n,
name: config.aliasFor[c.walletId] || c.walletName,
id: c.walletId,
color: config.colorFor[c.walletId] || '#4A90E2',
};
});
$scope.wallets = lodash.sortBy(ret, 'name');
}; };
self.updateAllClients = function() {
lodash.each(profileService.getClients(), function(client) {
walletService.updateStatus(client, {}, function(err, status) {
if (err)
console.log('[tab-home.js.47]', err); //TODO
console.log('[tab-home.js.47:console:]',status); //TODO
self.updateAllClients = function() {
lodash.each(profileService.getWallets(), function(wallet) {
walletService.updateStatus(wallet, {}, function(err, status) {
if (err) {} // TODO
}); });
}); });
} }
@ -55,7 +34,4 @@ console.log('[tab-home.js.47:console:]',status); //TODO
self.setWallets(); self.setWallets();
self.updateAllClients(); self.updateAllClients();
$scope.bitpayCardEnabled = true; // TODO $scope.bitpayCardEnabled = true; // TODO
}); });

View file

@ -0,0 +1,76 @@
'use strict';
angular.module('copayApp.controllers').controller('walletDetailsController', function($scope, $rootScope, $interval, $timeout, $filter, $log, $ionicModal, $ionicPopover, $stateParams, profileService, lodash, configService, gettext, gettextCatalog, platformInfo, go, walletService ) {
console.log('[walletDetails.js.5]', $stateParams); //TODO
var isCordova = platformInfo.isCordova;
var isWP = platformInfo.isWP;
var isAndroid = platformInfo.isAndroid;
var isChromeApp = platformInfo.isChromeApp;
var self = this;
$rootScope.shouldHideMenuBar = false;
$rootScope.wpInputFocused = false;
var config = configService.getSync();
var configWallet = config.wallet;
var walletSettings = configWallet.settings;
var ret = {};
// INIT. Global value
ret.unitToSatoshi = walletSettings.unitToSatoshi;
ret.satToUnit = 1 / ret.unitToSatoshi;
ret.unitName = walletSettings.unitName;
ret.alternativeIsoCode = walletSettings.alternativeIsoCode;
ret.alternativeName = walletSettings.alternativeName;
ret.alternativeAmount = 0;
ret.unitDecimals = walletSettings.unitDecimals;
ret.isCordova = isCordova;
ret.addresses = [];
ret.isMobile = platformInfo.isMobile;
ret.isWindowsPhoneApp = platformInfo.isWP;
ret.countDown = null;
ret.sendMaxInfo = {};
ret.showAlternative = false;
$scope.openSearchModal = function() {
var fc = profileService.focusedClient;
$scope.color = fc.backgroundColor;
$scope.self = self;
$ionicModal.fromTemplateUrl('views/modals/search.html', {
scope: $scope,
focusFirstInput: true
}).then(function(modal) {
$scope.searchModal = modal;
$scope.searchModal.show();
});
};
this.openTxModal = function(btx) {
var self = this;
$scope.btx = lodash.cloneDeep(btx);
$scope.self = self;
$ionicModal.fromTemplateUrl('views/modals/tx-details.html', {
scope: $scope,
hideDelay: 500
}).then(function(modal) {
$scope.txDetailsModal = modal;
$scope.txDetailsModal.show();
});
};
$scope.update = function() {
console.log('[walletDetails.js.65:update:] TODO'); //TODO
// {triggerTxUpdate: true}
};
$scope.hideToggle = function() {
console.log('[walletDetails.js.70:hideToogle:] TODO'); //TODO
};
$scope.wallet = profileService.getWallet($stateParams.walletId);
console.log('[walletDetails.js.66]',$scope.wallet); //TODO
});

View file

@ -14,7 +14,7 @@ if (window && window.navigator) {
//Setting up route //Setting up route
angular.module('copayApp').config(function(historicLogProvider, $provide, $logProvider, $stateProvider, $urlRouterProvider, $compileProvider) { angular.module('copayApp').config(function(historicLogProvider, $provide, $logProvider, $stateProvider, $urlRouterProvider, $compileProvider) {
$urlRouterProvider.otherwise('/'); $urlRouterProvider.otherwise('/tabs');
$logProvider.debugEnabled(true); $logProvider.debugEnabled(true);
$provide.decorator('$log', ['$delegate', 'platformInfo', $provide.decorator('$log', ['$delegate', 'platformInfo',
@ -93,8 +93,20 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
} }
} }
}) })
.state('walletDetails', {
url: '/details',
needProfile: true,
views: {
'main': {
templateUrl: 'views/walletDetails.html',
},
},
params: {
walletId: null,
},
})
.state('walletHome', { .state('walletHome', {
url: '/', url: '/old',
needProfile: true, needProfile: true,
views: { views: {
'main': { 'main': {

View file

@ -3,82 +3,5 @@
angular.module('copayApp.services') angular.module('copayApp.services')
.factory('addressService', function(storageService, profileService, $log, $timeout, lodash, bwcError, gettextCatalog) { .factory('addressService', function(storageService, profileService, $log, $timeout, lodash, bwcError, gettextCatalog) {
var root = {}; var root = {};
root.expireAddress = function(walletId, cb) {
$log.debug('Cleaning Address ' + walletId);
storageService.clearLastAddress(walletId, function(err) {
return cb(err);
});
};
root.isUsed = function(walletId, byAddress, cb) {
storageService.getLastAddress(walletId, function(err, addr) {
var used = lodash.find(byAddress, {
address: addr
});
return cb(null, used);
});
};
root._createAddress = function(walletId, cb) {
var client = profileService.getClient(walletId);
$log.debug('Creating address for wallet:', walletId);
client.createAddress({}, function(err, addr) {
if (err) {
var prefix = gettextCatalog.getString('Could not create address');
if (err.error && err.error.match(/locked/gi)) {
$log.debug(err.error);
return $timeout(function() {
root._createAddress(walletId, cb);
}, 5000);
} else if (err.message && err.message == 'MAIN_ADDRESS_GAP_REACHED') {
$log.warn(err.message);
prefix = null;
client.getMainAddresses({
reverse: true,
limit: 1
}, function(err, addr) {
if (err) return cb(err);
return cb(null, addr[0].address);
});
}
return bwcError.cb(err, prefix, cb);
}
return cb(null, addr.address);
});
};
root.getAddress = function(walletId, forceNew, cb) {
var firstStep;
if (forceNew) {
firstStep = storageService.clearLastAddress;
} else {
firstStep = function(walletId, cb) {
return cb();
};
}
firstStep(walletId, function(err) {
if (err) return cb(err);
storageService.getLastAddress(walletId, function(err, addr) {
if (err) return cb(err);
if (addr) return cb(null, addr);
root._createAddress(walletId, function(err, addr) {
if (err) return cb(err);
storageService.storeLastAddress(walletId, addr, function() {
if (err) return cb(err);
return cb(null, addr);
});
});
});
});
};
return root; return root;
}); });

View file

@ -17,31 +17,19 @@ angular.module('copayApp.services')
root.profile = null; root.profile = null;
root.focusedClient = null; root.focusedClient = null;
root.walletClients = {}; root.wallet = {}; // decorated version of client
root.Utils = bwcService.getUtils();
root.formatAmount = function(amount, fullPrecision) {
var config = configService.getSync().wallet.settings;
if (config.unitCode == 'sat') return amount;
//TODO : now only works for english, specify opts to change thousand separator and decimal separator
var opts = {
fullPrecision: !!fullPrecision
};
return this.Utils.formatAmount(amount, config.unitCode, opts);
};
root._setFocus = function(walletId, cb) { root._setFocus = function(walletId, cb) {
$log.debug('Set focus:', walletId); $log.debug('Set focus:', walletId);
// Set local object // Set local object
if (walletId) if (walletId)
root.focusedClient = root.walletClients[walletId]; root.focusedClient = root.wallet[walletId];
else else
root.focusedClient = []; root.focusedClient = [];
if (lodash.isEmpty(root.focusedClient)) { if (lodash.isEmpty(root.focusedClient)) {
root.focusedClient = root.walletClients[lodash.keys(root.walletClients)[0]]; root.focusedClient = root.wallet[lodash.keys(root.wallet)[0]];
} }
// Still nothing? // Still nothing?
@ -51,7 +39,7 @@ angular.module('copayApp.services')
$rootScope.$emit('Local/NewFocusedWallet'); $rootScope.$emit('Local/NewFocusedWallet');
// Set update period // Set update period
lodash.each(root.walletClients, function(client, id) { lodash.each(root.wallet, function(client, id) {
client.setNotificationsInterval(BACKGROUND_UPDATE_PERIOD); client.setNotificationsInterval(BACKGROUND_UPDATE_PERIOD);
}); });
root.focusedClient.setNotificationsInterval(FOREGROUND_UPDATE_PERIOD); root.focusedClient.setNotificationsInterval(FOREGROUND_UPDATE_PERIOD);
@ -66,18 +54,37 @@ angular.module('copayApp.services')
}); });
}; };
root.setCustomBWSFlag = function(wallet) {
var defaults = configService.getDefaults();
var config = configService.getSync();
wallet.usingCustomBWS = config.bwsFor && config.bwsFor[wallet.id] && (config.bwsFor[wallet.id] != defaults.bws.url);
};
// Adds a wallet client to profileService // Adds a wallet client to profileService
root.bindWalletClient = function(client, opts) { root.bindWalletClient = function(client, opts) {
var opts = opts || {}; var opts = opts || {};
var walletId = client.credentials.walletId; var walletId = client.credentials.walletId;
var config = configService.getSync();
config.colorFor = config.colorFor || {};
config.aliasFor = config.aliasFor || {};
if ((root.walletClients[walletId] && root.walletClients[walletId].started) || opts.force) {
if ((root.wallet[walletId] && root.wallet[walletId].started) || opts.force) {
return false; return false;
} }
root.walletClients[walletId] = client; // INIT WALLET CLIENT VIEWMODEL
root.walletClients[walletId].started = true; var c = client;
root.walletClients[walletId].doNotVerifyPayPro = isChromeApp; c.id = walletId;
c.started = true;
c.doNotVerifyPayPro = isChromeApp;
c.name = config.aliasFor[walletId] || client.credentials.walletName;
c.color = config.colorFor[walletId] || '#4A90E2';
c.network = client.credentials.network;
root.setCustomBWSFlag(c);
root.wallet[walletId] = c;
client.removeAllListeners(); client.removeAllListeners();
client.on('report', function(n) { client.on('report', function(n) {
@ -162,7 +169,7 @@ angular.module('copayApp.services')
// Used when reading wallets from the profile // Used when reading wallets from the profile
root.bindWallet = function(credentials, cb) { root.bindWallet = function(credentials, cb) {
if (!credentials.walletId) if (!credentials.walletId || !credentials.m)
return cb('bindWallet should receive credentials JSON'); return cb('bindWallet should receive credentials JSON');
@ -239,7 +246,7 @@ angular.module('copayApp.services')
root.pushNotificationsInit = function() { root.pushNotificationsInit = function() {
var defaults = configService.getDefaults(); var defaults = configService.getDefaults();
var push = pushNotificationsService.init(root.walletClients); var push = pushNotificationsService.init(root.wallet);
push.on('notification', function(data) { push.on('notification', function(data) {
if (!data.additionalData.foreground) { if (!data.additionalData.foreground) {
@ -431,14 +438,15 @@ angular.module('copayApp.services')
}); });
}; };
root.getClient = function(walletId) { root.getWallet = function(walletId) {
return root.walletClients[walletId]; return root.wallet[walletId];
}; };
root.deleteWalletClient = function(client, cb) { root.deleteWalletClient = function(client, cb) {
var walletId = client.credentials.walletId; var walletId = client.credentials.walletId;
pushNotificationsService.unsubscribe(root.getClient(walletId), function(err) { pushNotificationsService.unsubscribe(root.getWallet(walletId), function(err) {
if (err) $log.warn('Unsubscription error: ' + err.message); if (err) $log.warn('Unsubscription error: ' + err.message);
else $log.debug('Unsubscribed from push notifications service'); else $log.debug('Unsubscribed from push notifications service');
}); });
@ -448,7 +456,7 @@ angular.module('copayApp.services')
root.profile.deleteWallet(walletId); root.profile.deleteWallet(walletId);
delete root.walletClients[walletId]; delete root.wallet[walletId];
root.focusedClient = null; root.focusedClient = null;
@ -529,7 +537,7 @@ angular.module('copayApp.services')
storageService.storeProfile(root.profile, function(err) { storageService.storeProfile(root.profile, function(err) {
var config = configService.getSync(); var config = configService.getSync();
if (config.pushNotifications.enabled) if (config.pushNotifications.enabled)
pushNotificationsService.enableNotifications(root.walletClients); pushNotificationsService.enableNotifications(root.wallet);
return cb(err, walletId); return cb(err, walletId);
}); });
@ -705,8 +713,22 @@ angular.module('copayApp.services')
storageService.storeProfile(root.profile, cb); storageService.storeProfile(root.profile, cb);
}; };
root.getClients = function() { root.getWallets = function(network, n) {
return lodash.values(root.walletClients); var ret = lodash.values(root.wallet);
if (network) {
ret = lodash.filter(ret, function(x) {
return (x.credentials.network == network);
});
}
if (n) {
ret = lodash.filter(ret, function(w) {
return (w.credentials.n == n);
});
}
return lodash.sortBy(ret, 'name');
}; };
root.needsBackup = function(client, cb) { root.needsBackup = function(client, cb) {
@ -732,36 +754,5 @@ angular.module('copayApp.services')
}); });
}; };
root.getWallets = function(network, n) {
if (!root.profile) return [];
var config = configService.getSync();
config.colorFor = config.colorFor || {};
config.aliasFor = config.aliasFor || {};
var ret = lodash.map(root.profile.credentials, function(c) {
return {
m: c.m,
n: c.n,
name: config.aliasFor[c.walletId] || c.walletName,
id: c.walletId,
network: c.network,
color: config.colorFor[c.walletId] || '#4A90E2',
copayerId: c.copayerId
};
});
if (network) {
ret = lodash.filter(ret, function(w) {
return (w.network == network);
});
}
if (n) {
ret = lodash.filter(ret, function(w) {
return (w.n == n);
});
}
return lodash.sortBy(ret, 'name');
};
return root; return root;
}); });

View file

@ -1,15 +1,42 @@
'use strict'; 'use strict';
// DO NOT INCLUDE STORAGE HERE \/ \/ // DO NOT INCLUDE STORAGE HERE \/ \/
angular.module('copayApp.services').factory('walletService', function($log, $timeout, lodash, trezor, ledger, storageService, configService, uxLanguage) { angular.module('copayApp.services').factory('walletService', function($log, $timeout, lodash, trezor, ledger, storageService, configService, rateService, uxLanguage, bwcService, $filter) {
// DO NOT INCLUDE STORAGE HERE ^^ // DO NOT INCLUDE STORAGE HERE ^^
//
//
// `wallet` is a decorated version of client.
var root = {}; var root = {};
var _signWithLedger = function(client, txp, cb) {
// // RECEIVE
// // Check address
// root.isUsed(wallet.walletId, balance.byAddress, function(err, used) {
// if (used) {
// $log.debug('Address used. Creating new');
// $rootScope.$emit('Local/AddressIsUsed');
// }
// });
//
root.Utils = bwcService.getUtils();
root.formatAmount = function(amount, fullPrecision) {
var config = configService.getSync().wallet.settings;
if (config.unitCode == 'sat') return amount;
//TODO : now only works for english, specify opts to change thousand separator and decimal separator
var opts = {
fullPrecision: !!fullPrecision
};
return this.Utils.formatAmount(amount, config.unitCode, opts);
};
var _signWithLedger = function(wallet, txp, cb) {
$log.info('Requesting Ledger Chrome app to sign the transaction'); $log.info('Requesting Ledger Chrome app to sign the transaction');
ledger.signTx(txp, client.credentials.account, function(result) { ledger.signTx(txp, wallet.credentials.account, function(result) {
$log.debug('Ledger response', result); $log.debug('Ledger response', result);
if (!result.success) if (!result.success)
return cb(result.message || result.error); return cb(result.message || result.error);
@ -17,27 +44,27 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
txp.signatures = lodash.map(result.signatures, function(s) { txp.signatures = lodash.map(result.signatures, function(s) {
return s.substring(0, s.length - 2); return s.substring(0, s.length - 2);
}); });
return client.signTxProposal(txp, cb); return wallet.signTxProposal(txp, cb);
}); });
}; };
var _signWithTrezor = function(client, txp, cb) { var _signWithTrezor = function(wallet, txp, cb) {
$log.info('Requesting Trezor to sign the transaction'); $log.info('Requesting Trezor to sign the transaction');
var xPubKeys = lodash.pluck(client.credentials.publicKeyRing, 'xPubKey'); var xPubKeys = lodash.pluck(wallet.credentials.publicKeyRing, 'xPubKey');
trezor.signTx(xPubKeys, txp, client.credentials.account, function(err, result) { trezor.signTx(xPubKeys, txp, wallet.credentials.account, function(err, result) {
if (err) return cb(err); if (err) return cb(err);
$log.debug('Trezor response', result); $log.debug('Trezor response', result);
txp.signatures = result.signatures; txp.signatures = result.signatures;
return client.signTxProposal(txp, cb); return wallet.signTxProposal(txp, cb);
}); });
}; };
root.needsBackup = function(client) { root.needsBackup = function(wallet) {
if (client.isPrivKeyExternal()) return false; if (wallet.isPrivKeyExternal()) return false;
if (!client.credentials.mnemonic) return false; if (!wallet.credentials.mnemonic) return false;
if (client.credentials.network == 'testnet') return false; if (wallet.credentials.network == 'testnet') return false;
return true; return true;
}; };
@ -58,10 +85,10 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
// trigger from async events (like updates). // trigger from async events (like updates).
// Debounce function avoids multiple popups // Debounce function avoids multiple popups
var _handleError = function(err) { var _handleError = function(err) {
$log.warn('Client ERROR: ', err); $log.warn('wallet ERROR: ', err);
$log.warn('TODO'); $log.warn('TODO');
return ; // TODO!!! return; // TODO!!!
if (err instanceof errors.NOT_AUTHORIZED) { if (err instanceof errors.NOT_AUTHORIZED) {
self.notAuthorized = true; self.notAuthorized = true;
go.walletHome(); go.walletHome();
@ -76,14 +103,83 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
}; };
root.handleError = lodash.debounce(_handleError, 1000); root.handleError = lodash.debounce(_handleError, 1000);
// emits
// statusUpdated walletId, err ,statusObj root.setBalance = function(wallet, balance) {
// if (!balance) return;
root.updateStatus = function(client, opts, cb, initStatusHash, tries) {
var config = configService.getSync().wallet.settings;
var COIN = 1e8;
// Address with Balance
wallet.balanceByAddress = balance.byAddress;
// Spend unconfirmed funds
if (wallet.spendUnconfirmed) {
wallet.totalBalanceSat = balance.totalAmount;
wallet.lockedBalanceSat = balance.lockedAmount;
wallet.availableBalanceSat = balance.availableAmount;
wallet.totalBytesToSendMax = balance.totalBytesToSendMax;
wallet.pendingAmount = null;
} else {
wallet.totalBalanceSat = balance.totalConfirmedAmount;
wallet.lockedBalanceSat = balance.lockedConfirmedAmount;
wallet.availableBalanceSat = balance.availableConfirmedAmount;
wallet.totalBytesToSendMax = balance.totalBytesToSendConfirmedMax;
wallet.pendingAmount = balance.totalAmount - balance.totalConfirmedAmount;
}
// Selected unit
wallet.unitToSatoshi = config.unitToSatoshi;
wallet.satToUnit = 1 / wallet.unitToSatoshi;
wallet.unitName = config.unitName;
//STR
wallet.totalBalanceStr = root.formatAmount(wallet.totalBalanceSat) + ' ' + wallet.unitName;
wallet.lockedBalanceStr = root.formatAmount(wallet.lockedBalanceSat) + ' ' + wallet.unitName;
wallet.availableBalanceStr = root.formatAmount(wallet.availableBalanceSat) + ' ' + wallet.unitName;
if (wallet.pendingAmount) {
wallet.pendingAmountStr = root.formatAmount(wallet.pendingAmount) + ' ' + wallet.unitName;
} else {
wallet.pendingAmountStr = null;
}
wallet.alternativeName = config.alternativeName;
wallet.alternativeIsoCode = config.alternativeIsoCode;
rateService.whenAvailable(function() {
var totalBalanceAlternative = rateService.toFiat(wallet.totalBalanceSat, wallet.alternativeIsoCode);
var lockedBalanceAlternative = rateService.toFiat(wallet.lockedBalanceSat, wallet.alternativeIsoCode);
var alternativeConversionRate = rateService.toFiat(100000000, wallet.alternativeIsoCode);
wallet.totalBalanceAlternative = $filter('formatFiatAmount')(totalBalanceAlternative);
wallet.lockedBalanceAlternative = $filter('formatFiatAmount')(lockedBalanceAlternative);
wallet.alternativeConversionRate = $filter('formatFiatAmount')(alternativeConversionRate);
wallet.alternativeBalanceAvailable = true;
wallet.isRateAvailable = true;
});
};
root.setStatus = function(wallet, status) {
wallet.status = status;
wallet.statusUpdatedOn = Date.now();
wallet.isValid = true;
root.setBalance(wallet, status.balance);
};
root.updateStatus = function(wallet, opts, cb, initStatusHash, tries) {
tries = tries || 0; tries = tries || 0;
opts = opts || {}; opts = opts || {};
var walletId = client.credentials.walletId if (wallet.isValid && ! opts.force)
return;
var walletId = wallet.id;
if (opts.untilItChanges && lodash.isUndefined(initStatusHash)) { if (opts.untilItChanges && lodash.isUndefined(initStatusHash)) {
initStatusHash = _walletStatusHash(); initStatusHash = _walletStatusHash();
@ -94,7 +190,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
if (opts.walletStatus) if (opts.walletStatus)
return cb(null, opts.walletStatus); return cb(null, opts.walletStatus);
else { else {
return client.getStatus({ return wallet.getStatus({
twoStep: true twoStep: true
}, function(err, ret) { }, function(err, ret) {
if (err) if (err)
@ -102,7 +198,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
// TODO?? // TODO??
// self.isSingleAddress = !!ret.wallet.singleAddress; // self.isSingleAddress = !!ret.wallet.singleAddress;
// self.updating = ret.wallet.scanStatus == 'running'; // self.updating = ret.wallet.scanStatus == 'running';
return cb(err); return cb(null, ret);
}); });
} }
}; };
@ -117,16 +213,16 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
$timeout(function() { $timeout(function() {
// if (!opts.quiet) // if (!opts.quiet)
// self.updating = true; // self.updating = true;
$log.debug('Updating Status:', client.credentials.walletName, tries); $log.debug('Updating Status:', wallet.credentials.walletName, tries);
get(function(err, walletStatus) { get(function(err, walletStatus) {
var currentStatusHash = _walletStatusHash(walletStatus); var currentStatusHash = _walletStatusHash(walletStatus);
$log.debug('Status update. hash:' + currentStatusHash + ' Try:' + tries); $log.debug('Status update. hash:' + currentStatusHash + ' Try:' + tries);
if (!err && opts.untilItChanges && initStatusHash == currentStatusHash && tries < 7 && walletId == profileService.focusedClient.credentials.walletId) { if (!err && opts.untilItChanges && initStatusHash == currentStatusHash && tries < 7 && walletId == profileService.focusedClient.credentials.walletId) {
return $timeout(function() { return $timeout(function() {
$log.debug('Retrying update... ' + walletId + ' Try:' + tries) $log.debug('Retrying update... ' + walletId + ' Try:' + tries)
return root.updateStatus(client, { return root.updateStatus(wallet, {
walletStatus: null, walletStatus: null,
untilItChanges: true, untilItChanges: true,
triggerTxUpdate: opts.triggerTxUpdate, triggerTxUpdate: opts.triggerTxUpdate,
@ -138,8 +234,9 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
root.handleError(err); root.handleError(err);
return cb(err); return cb(err);
} }
$log.debug('Got Wallet Status for:' + wallet.credentials.walletName);
$log.debug('Wallet Status:' + client.credentials.walletName, walletStatus); root.setStatus(wallet, walletStatus);
// self.setPendingTxps(walletStatus.pendingTxps); // self.setPendingTxps(walletStatus.pendingTxps);
// //
@ -160,11 +257,11 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
// TODO // TODO
if (opts.triggerTxUpdate && opts.untilItChanges) { if (opts.triggerTxUpdate && opts.untilItChanges) {
$timeout(function() { $timeout(function() {
root.debounceUpdateHistory(); root.debounceUpdateHistory();
}, 1); }, 1);
} }
return cb(null, walletStatus); return cb();
// } else { // } else {
// self.loadingWallet = false; // self.loadingWallet = false;
// } // }
@ -192,10 +289,10 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
}); });
}; };
var getTxsFromServer = function(client, skip, endingTxid, limit, cb) { var getTxsFromServer = function(wallet, skip, endingTxid, limit, cb) {
var res = []; var res = [];
client.getTxHistory({ wallet.getTxHistory({
skip: skip, skip: skip,
limit: limit limit: limit
}, function(err, txsFromServer) { }, function(err, txsFromServer) {
@ -213,11 +310,11 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
}; };
var updateLocalTxHistory = function(client, cb) { var updateLocalTxHistory = function(wallet, cb) {
var FIRST_LIMIT = 5; var FIRST_LIMIT = 5;
var LIMIT = 50; var LIMIT = 50;
var requestLimit = FIRST_LIMIT; var requestLimit = FIRST_LIMIT;
var walletId = client.credentials.walletId; var walletId = wallet.credentials.walletId;
var config = configService.getSync().wallet.settings; var config = configService.getSync().wallet.settings;
var fixTxsUnit = function(txs) { var fixTxsUnit = function(txs) {
@ -233,8 +330,8 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
$log.debug('Fixing Tx Cache Unit to:' + name) $log.debug('Fixing Tx Cache Unit to:' + name)
lodash.each(txs, function(tx) { lodash.each(txs, function(tx) {
tx.amountStr = profileService.formatAmount(tx.amount) + name; tx.amountStr = root.formatAmount(tx.amount) + name;
tx.feeStr = profileService.formatAmount(tx.fees) + name; tx.feeStr = root.formatAmount(tx.fees) + name;
}); });
}; };
@ -260,7 +357,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
historyUpdateInProgress[walletId] = true; historyUpdateInProgress[walletId] = true;
function getNewTxs(newTxs, skip, i_cb) { function getNewTxs(newTxs, skip, i_cb) {
getTxsFromServer(client, skip, endingTxid, requestLimit, function(err, res, shouldContinue) { getTxsFromServer(wallet, skip, endingTxid, requestLimit, function(err, res, shouldContinue) {
if (err) return i_cb(err); if (err) return i_cb(err);
newTxs = newTxs.concat(lodash.compact(res)); newTxs = newTxs.concat(lodash.compact(res));
@ -306,7 +403,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
if (!endingTs) return cb2(); if (!endingTs) return cb2();
$log.debug('Syncing notes from: ' + endingTs); $log.debug('Syncing notes from: ' + endingTs);
client.getTxNotes({ wallet.getTxNotes({
minTs: endingTs minTs: endingTs
}, function(err, notes) { }, function(err, notes) {
if (err) { if (err) {
@ -352,10 +449,10 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
}; };
root.updateHistory = function(client) { root.updateHistory = function(wallet) {
var walletId = client.credentials.walletId; var walletId = wallet.credentials.walletId;
if (!client.isComplete()) return; if (!wallet.isComplete()) return;
$log.debug('Updating Transaction History'); $log.debug('Updating Transaction History');
@ -363,7 +460,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
self.updatingTxHistory = true; self.updatingTxHistory = true;
$timeout(function() { $timeout(function() {
updateLocalTxHistory(client, function(err) { updateLocalTxHistory(wallet, function(err) {
historyUpdateInProgress[walletId] = self.updatingTxHistory = false; historyUpdateInProgress[walletId] = self.updatingTxHistory = false;
self.loadingWallet = false; self.loadingWallet = false;
self.txProgress = 0; self.txProgress = 0;
@ -382,45 +479,45 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
root.isEncrypted = function(client) { root.isEncrypted = function(wallet) {
if (lodash.isEmpty(client)) return; if (lodash.isEmpty(wallet)) return;
var isEncrypted = client.isPrivKeyEncrypted(); var isEncrypted = wallet.isPrivKeyEncrypted();
if (isEncrypted) $log.debug('Wallet is encrypted'); if (isEncrypted) $log.debug('Wallet is encrypted');
return isEncrypted; return isEncrypted;
}; };
root.lock = function(client) { root.lock = function(wallet) {
try { try {
client.lock(); wallet.lock();
} catch (e) { } catch (e) {
$log.warn('Encrypting wallet:', e); $log.warn('Encrypting wallet:', e);
}; };
}; };
root.unlock = function(client, password) { root.unlock = function(wallet, password) {
if (lodash.isEmpty(client)) if (lodash.isEmpty(wallet))
return 'MISSING_PARAMETER'; return 'MISSING_PARAMETER';
if (lodash.isEmpty(password)) if (lodash.isEmpty(password))
return 'NO_PASSWORD_GIVEN'; return 'NO_PASSWORD_GIVEN';
try { try {
client.unlock(password); wallet.unlock(password);
} catch (e) { } catch (e) {
$log.warn('Decrypting wallet:', e); $log.warn('Decrypting wallet:', e);
return 'PASSWORD_INCORRECT'; return 'PASSWORD_INCORRECT';
} }
}; };
root.createTx = function(client, txp, cb) { root.createTx = function(wallet, txp, cb) {
if (lodash.isEmpty(txp) || lodash.isEmpty(client)) if (lodash.isEmpty(txp) || lodash.isEmpty(wallet))
return cb('MISSING_PARAMETER'); return cb('MISSING_PARAMETER');
if (txp.sendMax) { if (txp.sendMax) {
client.createTxProposal(txp, function(err, createdTxp) { wallet.createTxProposal(txp, function(err, createdTxp) {
if (err) return cb(err); if (err) return cb(err);
else return cb(null, createdTxp); else return cb(null, createdTxp);
}); });
} else { } else {
client.getFeeLevels(client.credentials.network, function(err, levels) { wallet.getFeeLevels(wallet.credentials.network, function(err, levels) {
if (err) return cb(err); if (err) return cb(err);
var feeLevelValue = lodash.find(levels, { var feeLevelValue = lodash.find(levels, {
@ -435,7 +532,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
$log.debug('Dynamic fee: ' + txp.feeLevel + ' ' + feeLevelValue.feePerKB + ' SAT'); $log.debug('Dynamic fee: ' + txp.feeLevel + ' ' + feeLevelValue.feePerKB + ' SAT');
txp.feePerKb = feeLevelValue.feePerKB; txp.feePerKb = feeLevelValue.feePerKB;
client.createTxProposal(txp, function(err, createdTxp) { wallet.createTxProposal(txp, function(err, createdTxp) {
if (err) return cb(err); if (err) return cb(err);
else { else {
$log.debug('Transaction created'); $log.debug('Transaction created');
@ -446,11 +543,11 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
} }
}; };
root.publishTx = function(client, txp, cb) { root.publishTx = function(wallet, txp, cb) {
if (lodash.isEmpty(txp) || lodash.isEmpty(client)) if (lodash.isEmpty(txp) || lodash.isEmpty(wallet))
return cb('MISSING_PARAMETER'); return cb('MISSING_PARAMETER');
client.publishTxProposal({ wallet.publishTxProposal({
txp: txp txp: txp
}, function(err, publishedTx) { }, function(err, publishedTx) {
if (err) return cb(err); if (err) return cb(err);
@ -461,25 +558,25 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
}); });
}; };
root.signTx = function(client, txp, cb) { root.signTx = function(wallet, txp, cb) {
if (lodash.isEmpty(txp) || lodash.isEmpty(client)) if (lodash.isEmpty(txp) || lodash.isEmpty(wallet))
return cb('MISSING_PARAMETER'); return cb('MISSING_PARAMETER');
if (client.isPrivKeyExternal()) { if (wallet.isPrivKeyExternal()) {
switch (client.getPrivKeyExternalSourceName()) { switch (wallet.getPrivKeyExternalSourceName()) {
case 'ledger': case 'ledger':
return _signWithLedger(client, txp, cb); return _signWithLedger(wallet, txp, cb);
case 'trezor': case 'trezor':
return _signWithTrezor(client, txp, cb); return _signWithTrezor(wallet, txp, cb);
default: default:
var msg = 'Unsupported External Key:' + client.getPrivKeyExternalSourceName(); var msg = 'Unsupported External Key:' + wallet.getPrivKeyExternalSourceName();
$log.error(msg); $log.error(msg);
return cb(msg); return cb(msg);
} }
} else { } else {
try { try {
client.signTxProposal(txp, function(err, signedTxp) { wallet.signTxProposal(txp, function(err, signedTxp) {
$log.debug('Transaction signed'); $log.debug('Transaction signed');
return cb(err, signedTxp); return cb(err, signedTxp);
}); });
@ -490,14 +587,14 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
} }
}; };
root.broadcastTx = function(client, txp, cb) { root.broadcastTx = function(wallet, txp, cb) {
if (lodash.isEmpty(txp) || lodash.isEmpty(client)) if (lodash.isEmpty(txp) || lodash.isEmpty(wallet))
return cb('MISSING_PARAMETER'); return cb('MISSING_PARAMETER');
if (txp.status != 'accepted') if (txp.status != 'accepted')
return cb('TX_NOT_ACCEPTED'); return cb('TX_NOT_ACCEPTED');
client.broadcastTxProposal(txp, function(err, broadcastedTxp, memo) { wallet.broadcastTxProposal(txp, function(err, broadcastedTxp, memo) {
if (err) if (err)
return cb(err); return cb(err);
@ -508,21 +605,21 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
}); });
}; };
root.rejectTx = function(client, txp, cb) { root.rejectTx = function(wallet, txp, cb) {
if (lodash.isEmpty(txp) || lodash.isEmpty(client)) if (lodash.isEmpty(txp) || lodash.isEmpty(wallet))
return cb('MISSING_PARAMETER'); return cb('MISSING_PARAMETER');
client.rejectTxProposal(txp, null, function(err, rejectedTxp) { wallet.rejectTxProposal(txp, null, function(err, rejectedTxp) {
$log.debug('Transaction rejected'); $log.debug('Transaction rejected');
return cb(err, rejectedTxp); return cb(err, rejectedTxp);
}); });
}; };
root.removeTx = function(client, txp, cb) { root.removeTx = function(wallet, txp, cb) {
if (lodash.isEmpty(txp) || lodash.isEmpty(client)) if (lodash.isEmpty(txp) || lodash.isEmpty(wallet))
return cb('MISSING_PARAMETER'); return cb('MISSING_PARAMETER');
client.removeTxProposal(txp, function(err) { wallet.removeTxProposal(txp, function(err) {
$log.debug('Transaction removed'); $log.debug('Transaction removed');
return cb(err); return cb(err);
}); });
@ -535,11 +632,11 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
clients = [clients]; clients = [clients];
function updateRemotePreferencesFor(clients, prefs, cb) { function updateRemotePreferencesFor(clients, prefs, cb) {
var client = clients.shift(); var wallet = clients.shift();
if (!client) return cb(); if (!wallet) return cb();
$log.debug('Saving remote preferences', client.credentials.walletName, prefs); $log.debug('Saving remote preferences', wallet.credentials.walletName, prefs);
client.savePreferences(prefs, function(err) { wallet.savePreferences(prefs, function(err) {
// we ignore errors here // we ignore errors here
if (err) $log.warn(err); if (err) $log.warn(err);
@ -603,9 +700,9 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
}); });
}; };
root.recreate = function(client, cb) { root.recreate = function(wallet, cb) {
ongoingProcess.set('recreating', true); ongoingProcess.set('recreating', true);
client.recreateWallet(function(err) { wallet.recreateWallet(function(err) {
self.notAuthorized = false; self.notAuthorized = false;
ongoingProcess.set('recreating', false); ongoingProcess.set('recreating', false);
@ -615,20 +712,20 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
return; return;
} }
profileService.bindWalletClient(client, { profileService.bindWalletClient(wallet, {
force: true force: true
}); });
self.startScan(client); self.startScan(wallet);
}); });
}; };
root.startScan = function(client) { root.startScan = function(wallet) {
$log.debug('Scanning wallet ' + client.credentials.walletId); $log.debug('Scanning wallet ' + wallet.credentials.walletId);
if (!client.isComplete()) return; if (!wallet.isComplete()) return;
// self.updating = true; // self.updating = true;
client.startScan({ wallet.startScan({
includeCopayerBranches: true, includeCopayerBranches: true,
}, function(err) { }, function(err) {
@ -642,6 +739,80 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
}; };
root.expireAddress = function(wallet, cb) {
$log.debug('Cleaning Address ' + wallet.id);
storageService.clearLastAddress(wallet.id, function(err) {
return cb(err);
});
};
root.isUsed = function(wallet, byAddress, cb) {
storageService.getLastAddress(wallet.id, function(err, addr) {
var used = lodash.find(byAddress, {
address: addr
});
return cb(null, used);
});
};
root._createAddress = function(wallet, cb) {
$log.debug('Creating address for wallet:', wallet.id);
wallet.createAddress({}, function(err, addr) {
if (err) {
var prefix = gettextCatalog.getString('Could not create address');
if (err.error && err.error.match(/locked/gi)) {
$log.debug(err.error);
return $timeout(function() {
root._createAddress(walletId, cb);
}, 5000);
} else if (err.message && err.message == 'MAIN_ADDRESS_GAP_REACHED') {
$log.warn(err.message);
prefix = null;
wallet.getMainAddresses({
reverse: true,
limit: 1
}, function(err, addr) {
if (err) return cb(err);
return cb(null, addr[0].address);
});
}
return bwcError.cb(err, prefix, cb);
}
return cb(null, addr.address);
});
};
root.getAddress = function(wallet, forceNew, cb) {
var firstStep;
if (forceNew) {
firstStep = storageService.clearLastAddress;
} else {
firstStep = function(walletId, cb) {
return cb();
};
}
firstStep(wallet.id, function(err) {
if (err) return cb(err);
storageService.getLastAddress(wallet.id, function(err, addr) {
if (err) return cb(err);
if (addr) return cb(null, addr);
root._createAddress(wallet, function(err, addr) {
if (err) return cb(err);
storageService.storeLastAddress(wallet.id, addr, function() {
if (err) return cb(err);
return cb(null, addr);
});
});
});
});
};
return root; return root;
}); });