Merge pull request #1281 from maraoz/refactor/settings
Refactor settings
This commit is contained in:
commit
d358330d1d
40 changed files with 697 additions and 655 deletions
43
config.js
43
config.js
|
|
@ -6,11 +6,6 @@ var defaultConfig = {
|
|||
forceNetwork: false,
|
||||
logLevel: 'info',
|
||||
|
||||
// DEFAULT unit: Bit
|
||||
unitName: 'bits',
|
||||
unitToSatoshi: 100,
|
||||
alternativeName: 'US Dollar',
|
||||
alternativeIsoCode: 'USD',
|
||||
|
||||
// wallet limits
|
||||
limits: {
|
||||
|
|
@ -20,9 +15,12 @@ var defaultConfig = {
|
|||
|
||||
// network layer config
|
||||
network: {
|
||||
host: 'test-insight.bitpay.com',
|
||||
port: 443,
|
||||
schema: 'https'
|
||||
testnet: {
|
||||
url: 'https://test-insight.bitpay.com:443'
|
||||
},
|
||||
livenet: {
|
||||
url: 'https://insight.bitpay.com:443'
|
||||
},
|
||||
},
|
||||
|
||||
// wallet default config
|
||||
|
|
@ -30,25 +28,15 @@ var defaultConfig = {
|
|||
requiredCopayers: 2,
|
||||
totalCopayers: 3,
|
||||
spendUnconfirmed: true,
|
||||
verbose: 1,
|
||||
// will duplicate itself after each try
|
||||
reconnectDelay: 5000,
|
||||
idleDurationMin: 4
|
||||
},
|
||||
|
||||
// blockchain service API config
|
||||
blockchain: {
|
||||
schema: 'https',
|
||||
host: 'test-insight.bitpay.com',
|
||||
port: 443,
|
||||
retryDelay: 1000,
|
||||
},
|
||||
// socket service API config
|
||||
socket: {
|
||||
schema: 'https',
|
||||
host: 'test-insight.bitpay.com',
|
||||
port: 443,
|
||||
reconnectDelay: 1000,
|
||||
idleDurationMin: 4,
|
||||
settings: {
|
||||
unitName: 'bits',
|
||||
unitToSatoshi: 100,
|
||||
unitDecimals: 2,
|
||||
alternativeName: 'US Dollar',
|
||||
alternativeIsoCode: 'USD',
|
||||
}
|
||||
},
|
||||
|
||||
// local encryption/security config
|
||||
|
|
@ -62,7 +50,6 @@ var defaultConfig = {
|
|||
updateFrequencySeconds: 60 * 60
|
||||
},
|
||||
|
||||
verbose: 1,
|
||||
};
|
||||
if (typeof module !== 'undefined')
|
||||
module.exports = defaultConfig;
|
||||
module.exports = defaultConfig;
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@
|
|||
<i class="fi-loop icon-rotate m15r"></i>
|
||||
<span translate> Network Error. Attempting to reconnect...</span>
|
||||
</span>
|
||||
<nav class="tab-bar" ng-class="{'hide-tab-bar' : !$root.wallet ||
|
||||
!$root.wallet.isReady() || $root.wallet.isLocked}">
|
||||
<nav class="tab-bar" ng-if="$root.wallet &&
|
||||
$root.wallet.isReady() && !$root.wallet.isLocked">
|
||||
<section class="left-small">
|
||||
<a class="left-off-canvas-toggle menu-icon" ><span></span></a>
|
||||
</section>
|
||||
|
|
@ -28,7 +28,7 @@
|
|||
|
||||
<section class="middle tab-bar-section">
|
||||
<h1 class="right">
|
||||
{{totalBalance || 0 |noFractionNumber}} {{$root.unitName}}
|
||||
{{totalBalance || 0 |noFractionNumber}} {{$root.wallet.settings.unitName}}
|
||||
</h1>
|
||||
<h1 class="title ellipsis">
|
||||
{{$root.wallet.getName()}}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ angular.module('copayApp.controllers').controller('CreateController',
|
|||
$scope.walletPassword = $rootScope.walletPassword;
|
||||
$scope.isMobile = !!window.cordova;
|
||||
$scope.hideAdv = true;
|
||||
$scope.networkName = config.networkName;
|
||||
|
||||
// ng-repeat defined number of times instead of repeating over array?
|
||||
$scope.getNumber = function(num) {
|
||||
|
|
@ -83,6 +84,7 @@ angular.module('copayApp.controllers').controller('CreateController',
|
|||
nickname: $scope.myNickname,
|
||||
passphrase: passphrase,
|
||||
privateKeyHex: $scope.private,
|
||||
networkName: $scope.networkName,
|
||||
};
|
||||
var w = walletFactory.create(opts);
|
||||
controllerUtils.startNetwork(w, $scope);
|
||||
|
|
|
|||
|
|
@ -118,7 +118,6 @@ angular.module('copayApp.controllers').controller('JoinController',
|
|||
}
|
||||
|
||||
$scope.loading = true;
|
||||
walletFactory.network.on('badSecret', function() {});
|
||||
|
||||
Passphrase.getBase64Async($scope.joinPassword, function(passphrase) {
|
||||
walletFactory.joinCreateSession($scope.connectionId, $scope.nickname, passphrase, $scope.private, function(err, w) {
|
||||
|
|
@ -129,7 +128,7 @@ angular.module('copayApp.controllers').controller('JoinController',
|
|||
else if (err === 'walletFull')
|
||||
notification.error('The wallet is full');
|
||||
else if (err === 'badNetwork')
|
||||
notification.error('Network Error', 'The wallet your are trying to join uses a different Bitcoin Network. Check your settings.');
|
||||
notification.error('Network Error', 'Wallet network configuration missmatch');
|
||||
else if (err === 'badSecret')
|
||||
notification.error('Bad secret', 'The secret string you entered is invalid');
|
||||
else
|
||||
|
|
|
|||
|
|
@ -1,45 +1,97 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('MoreController',
|
||||
function($scope, $rootScope, $location, backupService, walletFactory, controllerUtils, notification) {
|
||||
function($scope, $rootScope, $location, backupService, walletFactory, controllerUtils, notification, rateService) {
|
||||
var w = $rootScope.wallet;
|
||||
|
||||
$scope.hideAdv=true;
|
||||
$scope.hidePriv=true;
|
||||
$scope.unitOpts = [{
|
||||
name: 'Satoshis (100,000,000 satoshis = 1BTC)',
|
||||
shortName: 'SAT',
|
||||
value: 1,
|
||||
decimals: 0
|
||||
}, {
|
||||
name: 'bits (1,000,000 bits = 1BTC)',
|
||||
shortName: 'bits',
|
||||
value: 100,
|
||||
decimals: 2
|
||||
}, {
|
||||
name: 'mBTC (1,000 mBTC = 1BTC)',
|
||||
shortName: 'mBTC',
|
||||
value: 100000,
|
||||
decimals: 5
|
||||
}, {
|
||||
name: 'BTC',
|
||||
shortName: 'BTC',
|
||||
value: 100000000,
|
||||
decimals: 8
|
||||
}];
|
||||
$scope.selectedAlternative = {
|
||||
name: w.settings.alternativeName,
|
||||
isoCode: w.settings.alternativeIsoCode
|
||||
};
|
||||
$scope.alternativeOpts = rateService.isAvailable ?
|
||||
rateService.listAlternatives() : [$scope.selectedAlternative];
|
||||
|
||||
rateService.whenAvailable(function() {
|
||||
$scope.alternativeOpts = rateService.listAlternatives();
|
||||
for (var ii in $scope.alternativeOpts) {
|
||||
if (w.settings.alternativeIsoCode === $scope.alternativeOpts[ii].isoCode) {
|
||||
$scope.selectedAlternative = $scope.alternativeOpts[ii];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
for (var ii in $scope.unitOpts) {
|
||||
if (w.settings.unitName === $scope.unitOpts[ii].shortName) {
|
||||
$scope.selectedUnit = $scope.unitOpts[ii];
|
||||
break;
|
||||
}
|
||||
}
|
||||
$scope.save = function() {
|
||||
w.changeSettings({
|
||||
unitName: $scope.selectedUnit.shortName,
|
||||
unitToSatoshi: $scope.selectedUnit.value,
|
||||
unitDecimals: $scope.selectedUnit.decimals,
|
||||
alternativeName: $scope.selectedAlternative.name,
|
||||
alternativeIsoCode: $scope.selectedAlternative.isoCode,
|
||||
});
|
||||
controllerUtils.updateBalance();
|
||||
};
|
||||
|
||||
|
||||
$scope.hideAdv = true;
|
||||
$scope.hidePriv = true;
|
||||
if (w)
|
||||
$scope.priv = w.privateKey.toObj().extendedPrivateKeyString;
|
||||
|
||||
$scope.downloadBackup = function() {
|
||||
var w = $rootScope.wallet;
|
||||
backupService.download(w);
|
||||
}
|
||||
|
||||
$scope.deleteWallet = function() {
|
||||
var w = $rootScope.wallet;
|
||||
walletFactory.delete(w.id, function() {
|
||||
controllerUtils.logout();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.purge = function(deleteAll) {
|
||||
var w = $rootScope.wallet;
|
||||
var removed = w.purgeTxProposals(deleteAll);
|
||||
if (removed){
|
||||
if (removed) {
|
||||
controllerUtils.updateBalance();
|
||||
}
|
||||
notification.info('Tx Proposals Purged', removed + ' transaction proposal purged');
|
||||
};
|
||||
|
||||
$scope.updateIndexes = function() {
|
||||
var w = $rootScope.wallet;
|
||||
notification.info('Scaning for transactions','Using derived addresses from your wallet');
|
||||
notification.info('Scaning for transactions', 'Using derived addresses from your wallet');
|
||||
w.updateIndexes(function(err) {
|
||||
notification.info('Scan Ended', 'Updating balance');
|
||||
if (err) {
|
||||
notification.error('Error', 'Error updating indexes: ' + err);
|
||||
}
|
||||
controllerUtils.updateAddressList();
|
||||
controllerUtils.updateBalance(function(){
|
||||
controllerUtils.updateBalance(function() {
|
||||
notification.info('Finished', 'The balance is updated using the derived addresses');
|
||||
w.sendIndexes();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,17 +1,22 @@
|
|||
'use strict';
|
||||
var bitcore = require('bitcore');
|
||||
var preconditions = require('preconditions').singleton();
|
||||
|
||||
angular.module('copayApp.controllers').controller('SendController',
|
||||
function($scope, $rootScope, $window, $timeout, $anchorScroll, $modal, isMobile, notification, controllerUtils, rateService) {
|
||||
var w = $rootScope.wallet;
|
||||
preconditions.checkState(w);
|
||||
preconditions.checkState(w.settings.unitToSatoshi);
|
||||
|
||||
$scope.title = 'Send';
|
||||
$scope.loading = false;
|
||||
var satToUnit = 1 / config.unitToSatoshi;
|
||||
var satToUnit = 1 / w.settings.unitToSatoshi;
|
||||
$scope.defaultFee = bitcore.TransactionBuilder.FEE_PER_1000B_SAT * satToUnit;
|
||||
$scope.unitToBtc = config.unitToSatoshi / bitcore.util.COIN;
|
||||
$scope.unitToSatoshi = config.unitToSatoshi;
|
||||
$scope.unitToBtc = w.settings.unitToSatoshi / bitcore.util.COIN;
|
||||
$scope.unitToSatoshi = w.settings.unitToSatoshi;
|
||||
|
||||
$scope.alternativeName = config.alternativeName;
|
||||
$scope.alternativeIsoCode = config.alternativeIsoCode;
|
||||
$scope.alternativeName = w.settings.alternativeName;
|
||||
$scope.alternativeIsoCode = w.settings.alternativeIsoCode;
|
||||
|
||||
$scope.isRateAvailable = false;
|
||||
$scope.rateService = rateService;
|
||||
|
|
@ -36,7 +41,7 @@ angular.module('copayApp.controllers').controller('SendController',
|
|||
this._alternative = newValue;
|
||||
if (typeof(newValue) === 'number' && $scope.isRateAvailable) {
|
||||
this._amount = parseFloat(
|
||||
(rateService.fromFiat(newValue, config.alternativeIsoCode) * satToUnit).toFixed(config.unitDecimals), 10);
|
||||
(rateService.fromFiat(newValue, w.settings.alternativeIsoCode) * satToUnit).toFixed(w.settings.unitDecimals), 10);
|
||||
} else {
|
||||
this._amount = 0;
|
||||
}
|
||||
|
|
@ -53,7 +58,7 @@ angular.module('copayApp.controllers').controller('SendController',
|
|||
this._amount = newValue;
|
||||
if (typeof(newValue) === 'number' && $scope.isRateAvailable) {
|
||||
this._alternative = parseFloat(
|
||||
(rateService.toFiat(newValue * config.unitToSatoshi, config.alternativeIsoCode)).toFixed(2), 10);
|
||||
(rateService.toFiat(newValue * w.settings.unitToSatoshi, w.settings.alternativeIsoCode)).toFixed(2), 10);
|
||||
} else {
|
||||
this._alternative = 0;
|
||||
}
|
||||
|
|
@ -75,7 +80,6 @@ angular.module('copayApp.controllers').controller('SendController',
|
|||
}
|
||||
|
||||
$scope.showAddressBook = function() {
|
||||
var w = $rootScope.wallet;
|
||||
var flag;
|
||||
if (w) {
|
||||
for (var k in w.addressBook) {
|
||||
|
|
@ -91,7 +95,7 @@ angular.module('copayApp.controllers').controller('SendController',
|
|||
if ($rootScope.pendingPayment) {
|
||||
var pp = $rootScope.pendingPayment;
|
||||
$scope.address = pp.address + '';
|
||||
var amount = pp.data.amount / config.unitToSatoshi * 100000000;
|
||||
var amount = pp.data.amount / w.settings.unitToSatoshi * 100000000;
|
||||
$scope.amount = amount;
|
||||
$scope.commentText = pp.data.message;
|
||||
}
|
||||
|
|
@ -113,11 +117,9 @@ angular.module('copayApp.controllers').controller('SendController',
|
|||
$scope.loading = true;
|
||||
|
||||
var address = form.address.$modelValue;
|
||||
var amount = parseInt((form.amount.$modelValue * config.unitToSatoshi).toFixed(0));
|
||||
var amount = parseInt((form.amount.$modelValue * w.settings.unitToSatoshi).toFixed(0));
|
||||
var commentText = form.comment.$modelValue;
|
||||
|
||||
var w = $rootScope.wallet;
|
||||
|
||||
function done(err, ntxid, merchantData) {
|
||||
if (err) {
|
||||
var message = 'The transaction' + (w.isShared() ? ' proposal' : '') + ' could not be created';
|
||||
|
|
@ -344,7 +346,6 @@ angular.module('copayApp.controllers').controller('SendController',
|
|||
}
|
||||
|
||||
$scope.toggleAddressBookEntry = function(key) {
|
||||
var w = $rootScope.wallet;
|
||||
w.toggleAddressBookEntry(key);
|
||||
};
|
||||
|
||||
|
|
@ -379,7 +380,6 @@ angular.module('copayApp.controllers').controller('SendController',
|
|||
});
|
||||
|
||||
modalInstance.result.then(function(entry) {
|
||||
var w = $rootScope.wallet;
|
||||
|
||||
$timeout(function() {
|
||||
$scope.loading = false;
|
||||
|
|
@ -403,7 +403,7 @@ angular.module('copayApp.controllers').controller('SendController',
|
|||
};
|
||||
|
||||
$scope.getAvailableAmount = function() {
|
||||
var amount = ((($rootScope.availableBalance * config.unitToSatoshi).toFixed(0) - bitcore.TransactionBuilder.FEE_PER_1000B_SAT) / config.unitToSatoshi);
|
||||
var amount = ((($rootScope.availableBalance * w.settings.unitToSatoshi).toFixed(0) - bitcore.TransactionBuilder.FEE_PER_1000B_SAT) / w.settings.unitToSatoshi);
|
||||
return amount > 0 ? amount : 0;
|
||||
};
|
||||
|
||||
|
|
@ -416,7 +416,6 @@ angular.module('copayApp.controllers').controller('SendController',
|
|||
$scope.send = function(ntxid, cb) {
|
||||
$scope.loading = true;
|
||||
$rootScope.txAlertCount = 0;
|
||||
var w = $rootScope.wallet;
|
||||
w.sendTx(ntxid, function(txid, merchantData) {
|
||||
if (!txid) {
|
||||
notification.error('Error', 'There was an error sending the transaction');
|
||||
|
|
@ -441,7 +440,6 @@ angular.module('copayApp.controllers').controller('SendController',
|
|||
|
||||
$scope.sign = function(ntxid) {
|
||||
$scope.loading = true;
|
||||
var w = $rootScope.wallet;
|
||||
w.sign(ntxid, function(ret) {
|
||||
if (!ret) {
|
||||
notification.error('Error', 'There was an error signing the transaction');
|
||||
|
|
@ -461,7 +459,6 @@ angular.module('copayApp.controllers').controller('SendController',
|
|||
$scope.reject = function(ntxid) {
|
||||
$scope.loading = true;
|
||||
$rootScope.txAlertCount = 0;
|
||||
var w = $rootScope.wallet;
|
||||
w.reject(ntxid);
|
||||
notification.warning('Transaction rejected', 'You rejected the transaction successfully');
|
||||
$scope.loading = false;
|
||||
|
|
@ -497,7 +494,7 @@ angular.module('copayApp.controllers').controller('SendController',
|
|||
// Payment Protocol URI (BIP-72)
|
||||
scope.wallet.fetchPaymentTx(uri.merchant, function(err, merchantData) {
|
||||
var balance = $rootScope.availableBalance;
|
||||
var available = +(balance * config.unitToSatoshi).toFixed(0);
|
||||
var available = +(balance * w.settings.unitToSatoshi).toFixed(0);
|
||||
|
||||
if (merchantData && available < +merchantData.total) {
|
||||
err = new Error('No unspent outputs available.');
|
||||
|
|
@ -508,7 +505,7 @@ angular.module('copayApp.controllers').controller('SendController',
|
|||
scope.sendForm.address.$isValid = false;
|
||||
|
||||
if (err.amount) {
|
||||
scope.sendForm.amount.$setViewValue(+err.amount / config.unitToSatoshi);
|
||||
scope.sendForm.amount.$setViewValue(+err.amount / w.settings.unitToSatoshi);
|
||||
scope.sendForm.amount.$render();
|
||||
scope.sendForm.amount.$isValid = false;
|
||||
scope.notEnoughAmount = true;
|
||||
|
|
@ -538,7 +535,7 @@ angular.module('copayApp.controllers').controller('SendController',
|
|||
var url = merchantData.request_url;
|
||||
var domain = /^(?:https?)?:\/\/([^\/:]+).*$/.exec(url)[1];
|
||||
|
||||
merchantData.unitTotal = (+merchantData.total / config.unitToSatoshi) + '';
|
||||
merchantData.unitTotal = (+merchantData.total / w.settings.unitToSatoshi) + '';
|
||||
merchantData.expiration = new Date(
|
||||
merchantData.pr.pd.expires * 1000).toISOString();
|
||||
merchantData.domain = domain;
|
||||
|
|
@ -587,8 +584,10 @@ angular.module('copayApp.controllers').controller('SendController',
|
|||
}
|
||||
|
||||
notification.info('Payment Request',
|
||||
'Server is requesting ' + merchantData.unitTotal + ' ' + config.unitName + '.' + ' Message: ' + merchantData.pr.pd.memo);
|
||||
'Server is requesting ' + merchantData.unitTotal +
|
||||
' ' + w.settings.unitName +
|
||||
'.' + ' Message: ' + merchantData.pr.pd.memo);
|
||||
});
|
||||
};
|
||||
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,15 +1,12 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('SettingsController', function($scope, $rootScope, $window, $location, controllerUtils, rateService) {
|
||||
angular.module('copayApp.controllers').controller('SettingsController', function($scope, $rootScope, $window, $location, controllerUtils) {
|
||||
|
||||
controllerUtils.redirIfLogged();
|
||||
$scope.title = 'Settings';
|
||||
$scope.networkName = config.networkName;
|
||||
$scope.insightHost = config.blockchain.host;
|
||||
$scope.insightPort = config.blockchain.port;
|
||||
$scope.insightSecure = config.blockchain.schema === 'https';
|
||||
$scope.forceNetwork = config.forceNetwork;
|
||||
$scope.defaultLanguage = config.defaultLanguage || 'en';
|
||||
$scope.insightLivenet = config.network.livenet.url;
|
||||
$scope.insightTestnet = config.network.testnet.url;
|
||||
|
||||
$scope.availableLanguages = [{
|
||||
name: 'English',
|
||||
|
|
@ -26,86 +23,18 @@ angular.module('copayApp.controllers').controller('SettingsController', function
|
|||
}
|
||||
}
|
||||
|
||||
$scope.unitOpts = [{
|
||||
name: 'Satoshis (100,000,000 satoshis = 1BTC)',
|
||||
shortName: 'SAT',
|
||||
value: 1,
|
||||
decimals: 0
|
||||
}, {
|
||||
name: 'bits (1,000,000 bits = 1BTC)',
|
||||
shortName: 'bits',
|
||||
value: 100,
|
||||
decimals: 2
|
||||
}, {
|
||||
name: 'mBTC (1,000 mBTC = 1BTC)',
|
||||
shortName: 'mBTC',
|
||||
value: 100000,
|
||||
decimals: 5
|
||||
}, {
|
||||
name: 'BTC',
|
||||
shortName: 'BTC',
|
||||
value: 100000000,
|
||||
decimals: 8
|
||||
}];
|
||||
|
||||
$scope.selectedAlternative = {
|
||||
name: config.alternativeName,
|
||||
isoCode: config.alternativeIsoCode
|
||||
};
|
||||
$scope.alternativeOpts = rateService.isAvailable ?
|
||||
rateService.listAlternatives() : [$scope.selectedAlternative];
|
||||
|
||||
rateService.whenAvailable(function() {
|
||||
$scope.alternativeOpts = rateService.listAlternatives();
|
||||
for (var ii in $scope.alternativeOpts) {
|
||||
if (config.alternativeIsoCode === $scope.alternativeOpts[ii].isoCode) {
|
||||
$scope.selectedAlternative = $scope.alternativeOpts[ii];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (var ii in $scope.unitOpts) {
|
||||
if (config.unitName === $scope.unitOpts[ii].shortName) {
|
||||
$scope.selectedUnit = $scope.unitOpts[ii];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$scope.changeNetwork = function() {
|
||||
$scope.insightHost = $scope.networkName !== 'testnet' ? 'test-insight.bitpay.com' : 'insight.bitpay.com';
|
||||
};
|
||||
|
||||
|
||||
$scope.changeInsightSSL = function() {
|
||||
$scope.insightPort = $scope.insightSecure ? 80 : 443;
|
||||
};
|
||||
|
||||
|
||||
$scope.save = function() {
|
||||
var network = config.network;
|
||||
network.host = $scope.insightHost;
|
||||
network.port = $scope.insightPort;
|
||||
network.schema = $scope.insightSecure ? 'https' : 'http';
|
||||
var insightSettings = {
|
||||
livenet: {
|
||||
url: $scope.insightLivenet,
|
||||
},
|
||||
testnet: {
|
||||
url: $scope.insightTestnet,
|
||||
},
|
||||
}
|
||||
|
||||
localStorage.setItem('config', JSON.stringify({
|
||||
networkName: $scope.networkName,
|
||||
blockchain: {
|
||||
host: $scope.insightHost,
|
||||
port: $scope.insightPort,
|
||||
schema: $scope.insightSecure ? 'https' : 'http',
|
||||
},
|
||||
socket: {
|
||||
host: $scope.insightHost,
|
||||
port: $scope.insightPort,
|
||||
schema: $scope.insightSecure ? 'https' : 'http',
|
||||
},
|
||||
network: network,
|
||||
unitName: $scope.selectedUnit.shortName,
|
||||
unitToSatoshi: $scope.selectedUnit.value,
|
||||
unitDecimals: $scope.selectedUnit.decimals,
|
||||
alternativeName: $scope.selectedAlternative.name,
|
||||
alternativeIsoCode: $scope.selectedAlternative.isoCode,
|
||||
|
||||
network: insightSettings,
|
||||
version: copay.version,
|
||||
defaultLanguage: $scope.selectedLanguage.isoCode
|
||||
}));
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ var bitcore = require('bitcore');
|
|||
angular.module('copayApp.controllers').controller('TransactionsController',
|
||||
function($scope, $rootScope, $timeout, controllerUtils, notification) {
|
||||
|
||||
var w = $rootScope.wallet;
|
||||
|
||||
$scope.title = 'Transactions';
|
||||
$scope.loading = false;
|
||||
$scope.lastShowed = false;
|
||||
|
|
@ -12,7 +14,7 @@ angular.module('copayApp.controllers').controller('TransactionsController',
|
|||
$scope.txpItemsPerPage = 4;
|
||||
$scope.blockchain_txs = [];
|
||||
|
||||
var satToUnit = 1 / config.unitToSatoshi;
|
||||
var satToUnit = 1 / w.settings.unitToSatoshi;
|
||||
|
||||
$scope.update = function() {
|
||||
$scope.loading = true;
|
||||
|
|
@ -139,7 +141,7 @@ angular.module('copayApp.controllers').controller('TransactionsController',
|
|||
}
|
||||
|
||||
$scope.getShortNetworkName = function() {
|
||||
return config.networkName.substring(0, 4);
|
||||
return w.getNetworkName().substring(0, 4);
|
||||
};
|
||||
|
||||
// Autoload transactions on 1-of-1
|
||||
|
|
|
|||
|
|
@ -3,9 +3,11 @@
|
|||
angular.module('copayApp.controllers').controller('VersionController',
|
||||
function($scope, $rootScope, $http, notification) {
|
||||
|
||||
var w = $rootScope.wallet;
|
||||
|
||||
$scope.version = copay.version;
|
||||
$scope.commitHash = copay.commitHash;
|
||||
$scope.networkName = config.networkName;
|
||||
$scope.networkName = w ? w.getNetworkName() : '';
|
||||
$scope.defaultLanguage = config.defaultLanguage;
|
||||
if (_.isUndefined($rootScope.checkVersion))
|
||||
$rootScope.checkVersion = true;
|
||||
|
|
@ -30,4 +32,4 @@ angular.module('copayApp.controllers').controller('VersionController',
|
|||
});
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
'use strict';
|
||||
|
||||
var bitcore = require('bitcore');
|
||||
var Address = bitcore.Address;
|
||||
var bignum = bitcore.Bignum;
|
||||
var preconditions = require('preconditions').singleton();
|
||||
|
||||
angular.module('copayApp.directives')
|
||||
.directive('validAddress', ['$rootScope', function($rootScope) {
|
||||
var bitcore = require('bitcore');
|
||||
var Address = bitcore.Address;
|
||||
var bignum = bitcore.Bignum;
|
||||
|
||||
return {
|
||||
require: 'ngModel',
|
||||
|
|
@ -28,14 +30,14 @@ angular.module('copayApp.directives')
|
|||
// Bip21 uri
|
||||
if (/^bitcoin:/.test(value)) {
|
||||
var uri = new bitcore.BIP21(value);
|
||||
var hasAddress = uri.address && uri.isValid() && uri.address.network().name === config.networkName;
|
||||
var hasAddress = uri.address && uri.isValid() && uri.address.network().name === $rootScope.wallet.getNetworkName();
|
||||
ctrl.$setValidity('validAddress', uri.data.merchant || hasAddress);
|
||||
return value;
|
||||
}
|
||||
|
||||
// Regular Address
|
||||
var a = new Address(value);
|
||||
ctrl.$setValidity('validAddress', a.isValid() && a.network().name === config.networkName);
|
||||
ctrl.$setValidity('validAddress', a.isValid() && a.network().name === $rootScope.wallet.getNetworkName());
|
||||
return value;
|
||||
};
|
||||
|
||||
|
|
@ -46,14 +48,17 @@ angular.module('copayApp.directives')
|
|||
}])
|
||||
.directive('enoughAmount', ['$rootScope',
|
||||
function($rootScope) {
|
||||
var bitcore = require('bitcore');
|
||||
var w = $rootScope.wallet;
|
||||
preconditions.checkState(w);
|
||||
preconditions.checkState(w.settings.unitToSatoshi);
|
||||
|
||||
var feeSat = Number(bitcore.TransactionBuilder.FEE_PER_1000B_SAT);
|
||||
return {
|
||||
require: 'ngModel',
|
||||
link: function(scope, element, attrs, ctrl) {
|
||||
var val = function(value) {
|
||||
var availableBalanceNum = Number(($rootScope.availableBalance * config.unitToSatoshi).toFixed(0));
|
||||
var vNum = Number((value * config.unitToSatoshi).toFixed(0));
|
||||
var availableBalanceNum = Number(($rootScope.availableBalance * w.settings.unitToSatoshi).toFixed(0));
|
||||
var vNum = Number((value * w.settings.unitToSatoshi).toFixed(0));
|
||||
|
||||
if (typeof vNum == "number" && vNum > 0) {
|
||||
vNum = vNum + feeSat;
|
||||
|
|
@ -270,7 +275,7 @@ angular.module('copayApp.directives')
|
|||
|
||||
client.on('datarequested', function(client) {
|
||||
client.setText(scope.clipCopy);
|
||||
} );
|
||||
});
|
||||
|
||||
client.on('complete', function(client, args) {
|
||||
elm.removeClass('btn-copy').addClass('btn-copied').html('Copied!');
|
||||
|
|
|
|||
|
|
@ -44,43 +44,44 @@ angular.module('copayApp.filters', [])
|
|||
return addrs;
|
||||
};
|
||||
})
|
||||
.filter('noFractionNumber',
|
||||
[ '$filter', '$locale',
|
||||
function(filter, locale) {
|
||||
var numberFilter = filter('number');
|
||||
var formats = locale.NUMBER_FORMATS;
|
||||
return function(amount, n) {
|
||||
var fractionSize = (typeof(n) != 'undefined') ? n : config.unitToSatoshi.toString().length - 1;
|
||||
var value = numberFilter(amount, fractionSize);
|
||||
var sep = value.indexOf(formats.DECIMAL_SEP);
|
||||
var group = value.indexOf(formats.GROUP_SEP);
|
||||
if(amount >= 0) {
|
||||
if (group > 0) {
|
||||
if (sep < 0) {
|
||||
.filter('noFractionNumber', ['$filter', '$locale', '$rootScope',
|
||||
function(filter, locale, $rootScope) {
|
||||
var numberFilter = filter('number');
|
||||
var formats = locale.NUMBER_FORMATS;
|
||||
return function(amount, n) {
|
||||
if (typeof(n) === 'undefined' && !$rootScope.wallet) return amount;
|
||||
|
||||
var fractionSize = (typeof(n) !== 'undefined') ?
|
||||
n : $rootScope.wallet.settings.unitToSatoshi.toString().length - 1;
|
||||
var value = numberFilter(amount, fractionSize);
|
||||
var sep = value.indexOf(formats.DECIMAL_SEP);
|
||||
var group = value.indexOf(formats.GROUP_SEP);
|
||||
if (amount >= 0) {
|
||||
if (group > 0) {
|
||||
if (sep < 0) {
|
||||
return value;
|
||||
}
|
||||
var intValue = value.substring(0, sep);
|
||||
var floatValue = parseFloat(value.substring(sep));
|
||||
if (floatValue === 0) {
|
||||
floatValue = '';
|
||||
} else {
|
||||
if (floatValue % 1 === 0) {
|
||||
floatValue = floatValue.toFixed(0);
|
||||
}
|
||||
floatValue = floatValue.toString().substring(1);
|
||||
}
|
||||
var finalValue = intValue + floatValue;
|
||||
return finalValue;
|
||||
} else {
|
||||
value = parseFloat(value);
|
||||
if (value % 1 === 0) {
|
||||
value = value.toFixed(0);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
var intValue = value.substring(0, sep);
|
||||
var floatValue = parseFloat(value.substring(sep));
|
||||
if (floatValue === 0) {
|
||||
floatValue = '';
|
||||
}
|
||||
else {
|
||||
if(floatValue % 1 === 0) {
|
||||
floatValue = floatValue.toFixed(0);
|
||||
}
|
||||
floatValue = floatValue.toString().substring(1);
|
||||
}
|
||||
var finalValue = intValue + floatValue;
|
||||
return finalValue;
|
||||
}
|
||||
else {
|
||||
value = parseFloat(value);
|
||||
if(value % 1 === 0) {
|
||||
value = value.toFixed(0);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
} ]);
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
]);
|
||||
|
|
|
|||
|
|
@ -15,9 +15,7 @@ var preconditions = require('preconditions').singleton();
|
|||
subscribing to transactions on adressess and blocks.
|
||||
|
||||
Opts:
|
||||
- host
|
||||
- port
|
||||
- schema
|
||||
- url
|
||||
- reconnection (optional)
|
||||
- reconnectionDelay (optional)
|
||||
|
||||
|
|
@ -29,22 +27,22 @@ var preconditions = require('preconditions').singleton();
|
|||
*/
|
||||
|
||||
var Insight = function(opts) {
|
||||
preconditions.checkArgument(opts)
|
||||
.shouldBeObject(opts)
|
||||
.checkArgument(opts.url)
|
||||
|
||||
this.status = this.STATUS.DISCONNECTED;
|
||||
this.subscribed = {};
|
||||
this.listeningBlocks = false;
|
||||
|
||||
preconditions.checkArgument(opts).shouldBeObject(opts)
|
||||
.checkArgument(opts.host)
|
||||
.checkArgument(opts.port)
|
||||
.checkArgument(opts.schema);
|
||||
|
||||
this.url = opts.schema + '://' + opts.host + ':' + opts.port;
|
||||
this.url = opts.url;
|
||||
this.opts = {
|
||||
'reconnection': opts.reconnection || true,
|
||||
'reconnectionDelay': opts.reconnectionDelay || 1000,
|
||||
'secure': opts.schema === 'https'
|
||||
'secure': opts.url.indexOf('https') === 0
|
||||
};
|
||||
|
||||
this.socket = this.getSocket();
|
||||
}
|
||||
|
||||
util.inherits(Insight, EventEmitter);
|
||||
|
|
@ -105,7 +103,7 @@ Insight.prototype._setMainHandlers = function(url, opts) {
|
|||
|
||||
|
||||
/** @private */
|
||||
Insight.prototype.getSocket = function(url, opts) {
|
||||
Insight.prototype.getSocket = function() {
|
||||
|
||||
if (!this.socket) {
|
||||
this.socket = this._getSocketIO(this.url, this.opts);
|
||||
|
|
@ -148,7 +146,6 @@ Insight.prototype.subscribe = function(addresses) {
|
|||
return function(txid) {
|
||||
// verify the address is still subscribed
|
||||
if (!self.subscribed[address]) return;
|
||||
|
||||
log.debug('insight tx event');
|
||||
|
||||
self.emit('tx', {
|
||||
|
|
|
|||
|
|
@ -73,9 +73,9 @@ function Wallet(opts) {
|
|||
this.id = opts.id || Wallet.getRandomId();
|
||||
this.secretNumber = opts.secretNumber || Wallet.getRandomNumber();
|
||||
this.lock = new WalletLock(this.storage, this.id, opts.lockTimeOutMin);
|
||||
this.settings = opts.settings || copayConfig.wallet.settings;
|
||||
this.name = opts.name;
|
||||
|
||||
this.verbose = opts.verbose;
|
||||
this.publicKeyRing.walletId = this.id;
|
||||
this.txProposals.walletId = this.id;
|
||||
this.network.maxPeers = this.totalCopayers;
|
||||
|
|
@ -112,6 +112,21 @@ Wallet.builderOpts = {
|
|||
feeSat: undefined,
|
||||
};
|
||||
|
||||
/**
|
||||
* @desc static list with persisted properties of a wallet.
|
||||
* These are the properties that get stored/read from localstorage
|
||||
*/
|
||||
Wallet.PERSISTED_PROPERTIES = [
|
||||
'opts',
|
||||
'settings',
|
||||
'publicKeyRing',
|
||||
'txProposals',
|
||||
'privateKey',
|
||||
'addressBook',
|
||||
'backupOffered',
|
||||
'lastTimestamp',
|
||||
];
|
||||
|
||||
/**
|
||||
* @desc Retrieve a random id for the wallet
|
||||
* @TODO: Discuss changing to a UUID
|
||||
|
|
@ -161,6 +176,22 @@ Wallet.prototype._onIndexes = function(senderId, data) {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @desc
|
||||
* Changes wallet settings. The settings format is:
|
||||
*
|
||||
* var settings = {
|
||||
* unitName: 'bits',
|
||||
* unitToSatoshi: 100,
|
||||
* alternativeName: 'US Dollar',
|
||||
* alternativeIsoCode: 'USD',
|
||||
* };
|
||||
*/
|
||||
Wallet.prototype.changeSettings = function(settings) {
|
||||
this.settings = settings;
|
||||
this.store();
|
||||
};
|
||||
|
||||
/**
|
||||
* @desc
|
||||
* Handles a 'PUBLICKEYRING' message from <tt>senderId</tt>.
|
||||
|
|
@ -570,6 +601,7 @@ Wallet.prototype._optsToObj = function() {
|
|||
totalCopayers: this.totalCopayers,
|
||||
name: this.name,
|
||||
version: this.version,
|
||||
networkName: this.getNetworkName(),
|
||||
};
|
||||
|
||||
return obj;
|
||||
|
|
@ -615,7 +647,11 @@ Wallet.prototype.getSecretNumber = function() {
|
|||
* @return {string}
|
||||
*/
|
||||
Wallet.prototype.getSecret = function() {
|
||||
var buf = new Buffer(this.getMyCopayerId() + this.getSecretNumber(), 'hex');
|
||||
var buf = new Buffer(
|
||||
this.getMyCopayerId() +
|
||||
this.getSecretNumber() +
|
||||
(this.getNetworkName() === 'livenet' ? '00' : '01'),
|
||||
'hex');
|
||||
var str = Base58Check.encode(buf);
|
||||
return str;
|
||||
};
|
||||
|
|
@ -630,9 +666,11 @@ Wallet.decodeSecret = function(secretB) {
|
|||
var secret = Base58Check.decode(secretB);
|
||||
var pubKeyBuf = secret.slice(0, 33);
|
||||
var secretNumber = secret.slice(33, 38);
|
||||
var networkName = secret.slice(38, 39).toString('hex') === '00' ? 'livenet' : 'testnet';
|
||||
return {
|
||||
pubKey: pubKeyBuf.toString('hex'),
|
||||
secretNumber: secretNumber.toString('hex')
|
||||
secretNumber: secretNumber.toString('hex'),
|
||||
networkName: networkName,
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -780,9 +818,7 @@ Wallet.prototype.keepAlive = function() {
|
|||
*/
|
||||
Wallet.prototype.store = function() {
|
||||
this.keepAlive();
|
||||
|
||||
var wallet = this.toObj();
|
||||
this.storage.setFromObj(this.id, wallet);
|
||||
this.storage.setFromObj(this.id, this.toObj());
|
||||
log.debug('Wallet stored');
|
||||
};
|
||||
|
||||
|
|
@ -793,13 +829,11 @@ Wallet.prototype.store = function() {
|
|||
Wallet.prototype.toObj = function() {
|
||||
var optsObj = this._optsToObj();
|
||||
|
||||
var networkNonce = this.network.getHexNonce();
|
||||
var networkNonces = this.network.getHexNonces();
|
||||
|
||||
var walletObj = {
|
||||
opts: optsObj,
|
||||
networkNonce: networkNonce, //yours
|
||||
networkNonces: networkNonces, //copayers
|
||||
settings: this.settings,
|
||||
networkNonce: this.network.getHexNonce(), //yours
|
||||
networkNonces: this.network.getHexNonces(), //copayers
|
||||
publicKeyRing: this.publicKeyRing.toObj(),
|
||||
txProposals: this.txProposals.toObj(),
|
||||
privateKey: this.privateKey ? this.privateKey.toObj() : undefined,
|
||||
|
|
@ -831,6 +865,7 @@ Wallet.fromObj = function(o, storage, network, blockchain) {
|
|||
var opts = JSON.parse(JSON.stringify(o.opts));
|
||||
|
||||
opts.addressBook = o.addressBook;
|
||||
opts.settings = o.settings;
|
||||
|
||||
if (o.privateKey) {
|
||||
opts.privateKey = PrivateKey.fromObj(o.privateKey);
|
||||
|
|
@ -896,7 +931,6 @@ Wallet.prototype.send = function(recipients, obj) {
|
|||
Wallet.prototype.sendAllTxProposals = function(recipients, sinceTs) {
|
||||
var ntxids = sinceTs ? this.txProposals.getNtxidsSince(sinceTs) : this.txProposals.getNtxids();
|
||||
var self = this;
|
||||
|
||||
_.each(ntxids, function(ntxid, key) {
|
||||
self.sendTxProposal(ntxid, recipients);
|
||||
});
|
||||
|
|
@ -2522,4 +2556,4 @@ Wallet.request = function(options, callback) {
|
|||
return ret;
|
||||
};
|
||||
|
||||
module.exports = Wallet;
|
||||
module.exports = Wallet;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ var log = require('../../log');
|
|||
var Async = module.exports.Async = require('../network/Async');
|
||||
var Insight = module.exports.Insight = require('../blockchain/Insight');
|
||||
var StorageLocalEncrypted = module.exports.StorageLocalEncrypted = require('../storage/LocalEncrypted');
|
||||
var preconditions = require('preconditions').singleton();
|
||||
|
||||
/**
|
||||
* @desc
|
||||
|
|
@ -23,10 +24,8 @@ var StorageLocalEncrypted = module.exports.StorageLocalEncrypted = require('../s
|
|||
* @param {Storage} config.Storage - the class to instantiate to store the wallet (StorageLocalEncrypted by default)
|
||||
* @param {Object} config.storage - the configuration to be sent to the Storage constructor
|
||||
* @param {Network} config.Network - the class to instantiate to make network requests to copayers (the Async module by default)
|
||||
* @param {Object} config.network - the configuration to be sent to the Network constructor
|
||||
* @param {Object} config.network - the configurations to be sent to the Network and Blockchain constructors
|
||||
* @param {Blockchain} config.Blockchain - the class to instantiate to get information about the blockchain (Insight by default)
|
||||
* @param {Object} config.blockchain - the configuration to be sent to the Blockchain constructor
|
||||
* @param {string} config.networkName - the name of the bitcoin network to use ('testnet' or 'livenet')
|
||||
* @TODO: Investigate what parameters go inside this object
|
||||
* @param {Object} config.wallet - default configuration for the wallet
|
||||
* @TODO: put `version` inside of the config object
|
||||
|
|
@ -41,10 +40,15 @@ function WalletFactory(config, version) {
|
|||
this.Blockchain = config.Blockchain || Insight;
|
||||
|
||||
this.storage = new this.Storage(config.storage);
|
||||
this.network = new this.Network(config.network);
|
||||
this.blockchain = new this.Blockchain(config.blockchain);
|
||||
this.networks = {
|
||||
'livenet': new this.Network(config.network.livenet),
|
||||
'testnet': new this.Network(config.network.testnet),
|
||||
};
|
||||
this.blockchains = {
|
||||
'livenet': new this.Blockchain(config.network.livenet),
|
||||
'testnet': new this.Blockchain(config.network.testnet),
|
||||
};
|
||||
|
||||
this.networkName = config.networkName;
|
||||
this.walletDefaults = config.wallet;
|
||||
this.version = version;
|
||||
};
|
||||
|
|
@ -71,33 +75,41 @@ WalletFactory.prototype._checkRead = function(walletId) {
|
|||
return !!ret;
|
||||
};
|
||||
|
||||
/**
|
||||
* @desc obtain network name from serialized wallet
|
||||
* @param {Object} wallet object
|
||||
* @return {string} network name
|
||||
*/
|
||||
WalletFactory.prototype.obtainNetworkName = function(obj) {
|
||||
return obj.networkName ||
|
||||
obj.opts.networkName ||
|
||||
obj.publicKeyRing.networkName ||
|
||||
obj.privateKey.networkName;
|
||||
};
|
||||
|
||||
/**
|
||||
* @desc Deserialize an object to a Wallet
|
||||
* @param {Object} obj
|
||||
* @param {Object} wallet object
|
||||
* @param {string[]} skipFields - fields to skip when importing
|
||||
* @return {Wallet}
|
||||
*/
|
||||
WalletFactory.prototype.fromObj = function(obj, skipFields) {
|
||||
var networkName = this.obtainNetworkName(obj);
|
||||
preconditions.checkState(networkName);
|
||||
|
||||
// not stored options
|
||||
obj.opts.reconnectDelay = this.walletDefaults.reconnectDelay;
|
||||
|
||||
// this is only used if private key or public key ring is skipped
|
||||
obj.opts.networkName = this.networkName;
|
||||
|
||||
skipFields = skipFields || [];
|
||||
skipFields.forEach(function(k){
|
||||
skipFields.forEach(function(k) {
|
||||
if (obj[k]) {
|
||||
delete obj[k];
|
||||
} else
|
||||
} else
|
||||
throw new Error('unknown field:' + k);
|
||||
});
|
||||
|
||||
var w = Wallet.fromObj(obj, this.storage, this.network, this.blockchain);
|
||||
var w = Wallet.fromObj(obj, this.storage, this.networks[networkName], this.blockchains[networkName]);
|
||||
if (!w) return false;
|
||||
w.verbose = this.verbose;
|
||||
this._checkVersion(w.version);
|
||||
this._checkNetwork(w.getNetworkName());
|
||||
return w;
|
||||
};
|
||||
|
||||
|
|
@ -147,13 +159,9 @@ WalletFactory.prototype.read = function(walletId, skipFields) {
|
|||
var s = this.storage;
|
||||
|
||||
obj.id = walletId;
|
||||
obj.opts = s.get(walletId, 'opts');
|
||||
obj.publicKeyRing = s.get(walletId, 'publicKeyRing');
|
||||
obj.txProposals = s.get(walletId, 'txProposals');
|
||||
obj.privateKey = s.get(walletId, 'privateKey');
|
||||
obj.addressBook = s.get(walletId, 'addressBook');
|
||||
obj.backupOffered = s.get(walletId, 'backupOffered');
|
||||
obj.lastTimestamp = s.get(walletId, 'lastTimestamp');
|
||||
_.each(Wallet.PERSISTED_PROPERTIES, function(value) {
|
||||
obj[value] = s.get(walletId, value);
|
||||
});
|
||||
|
||||
var w = this.fromObj(obj, skipFields);
|
||||
return w;
|
||||
|
|
@ -179,14 +187,17 @@ WalletFactory.prototype.read = function(walletId, skipFields) {
|
|||
* @return {Wallet}
|
||||
*/
|
||||
WalletFactory.prototype.create = function(opts) {
|
||||
|
||||
opts = opts || {};
|
||||
opts.networkName = opts.networkName || 'testnet';
|
||||
|
||||
log.debug('### CREATING NEW WALLET.' + (opts.id ? ' USING ID: ' + opts.id : ' NEW ID') + (opts.privateKey ? ' USING PrivateKey: ' + opts.privateKey.getId() : ' NEW PrivateKey'));
|
||||
|
||||
var privOpts = {
|
||||
networkName: this.networkName,
|
||||
networkName: opts.networkName,
|
||||
};
|
||||
|
||||
if (opts.privateKeyHex && opts.privateKeyHex.length>1) {
|
||||
if (opts.privateKeyHex && opts.privateKeyHex.length > 1) {
|
||||
privOpts.extendedPrivateKeyString = opts.privateKeyHex;
|
||||
}
|
||||
|
||||
|
|
@ -197,7 +208,7 @@ WalletFactory.prototype.create = function(opts) {
|
|||
opts.lockTimeoutMin = this.walletDefaults.idleDurationMin;
|
||||
|
||||
opts.publicKeyRing = opts.publicKeyRing || new PublicKeyRing({
|
||||
networkName: this.networkName,
|
||||
networkName: opts.networkName,
|
||||
requiredCopayers: requiredCopayers,
|
||||
totalCopayers: totalCopayers,
|
||||
});
|
||||
|
|
@ -208,16 +219,15 @@ WalletFactory.prototype.create = function(opts) {
|
|||
log.debug('\t### PublicKeyRing Initialized');
|
||||
|
||||
opts.txProposals = opts.txProposals || new TxProposals({
|
||||
networkName: this.networkName,
|
||||
networkName: opts.networkName,
|
||||
});
|
||||
log.debug('\t### TxProposals Initialized');
|
||||
|
||||
this.storage._setPassphrase(opts.passphrase);
|
||||
|
||||
opts.storage = this.storage;
|
||||
opts.network = this.network;
|
||||
opts.blockchain = this.blockchain;
|
||||
opts.verbose = this.verbose;
|
||||
opts.network = this.networks[opts.networkName];
|
||||
opts.blockchain = this.blockchains[opts.networkName];
|
||||
|
||||
opts.spendUnconfirmed = opts.spendUnconfirmed || this.walletDefaults.spendUnconfirmed;
|
||||
opts.reconnectDelay = opts.reconnectDelay || this.walletDefaults.reconnectDelay;
|
||||
|
|
@ -245,20 +255,9 @@ WalletFactory.prototype._checkVersion = function(inVersion) {
|
|||
//We only check for major version differences
|
||||
if (thisV0 < inV0) {
|
||||
throw new Error('Major difference in software versions' +
|
||||
'. Received:' + inVersion +
|
||||
'. Current version:' + this.version +
|
||||
'. Aborting.');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @desc Throw an error if the network name is different to {@link WalletFactory#networkName}
|
||||
* @param {string} inNetworkName - the network name to check
|
||||
* @throws {Error}
|
||||
*/
|
||||
WalletFactory.prototype._checkNetwork = function(inNetworkName) {
|
||||
if (this.networkName !== inNetworkName) {
|
||||
throw new Error('This Wallet is configured for ' + inNetworkName + ' while currently Copay is configured for: ' + this.networkName + '. Check your settings.');
|
||||
'. Received:' + inVersion +
|
||||
'. Current version:' + this.version +
|
||||
'. Aborting.');
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -271,8 +270,9 @@ WalletFactory.prototype._checkNetwork = function(inNetworkName) {
|
|||
WalletFactory.prototype.open = function(walletId, passphrase) {
|
||||
this.storage._setPassphrase(passphrase);
|
||||
var w = this.read(walletId);
|
||||
if (w)
|
||||
if (w) {
|
||||
w.store();
|
||||
}
|
||||
|
||||
this.storage.setLastOpened(walletId);
|
||||
return w;
|
||||
|
|
@ -338,14 +338,16 @@ WalletFactory.prototype.decodeSecret = function(secret) {
|
|||
*/
|
||||
WalletFactory.prototype.joinCreateSession = function(secret, nickname, passphrase, privateHex, cb) {
|
||||
var self = this;
|
||||
var s = self.decodeSecret(secret);
|
||||
if (!s) return cb('badSecret');
|
||||
var decodedSecret = this.decodeSecret(secret);
|
||||
if (!decodedSecret || !decodedSecret.networkName || !decodedSecret.pubKey) {
|
||||
return cb('badSecret');
|
||||
}
|
||||
|
||||
var privOpts = {
|
||||
networkName: this.networkName,
|
||||
networkName: decodedSecret.networkName,
|
||||
};
|
||||
|
||||
if (privateHex && privateHex.length>1) {
|
||||
if (privateHex && privateHex.length > 1) {
|
||||
privOpts.extendedPrivateKeyString = privateHex;
|
||||
}
|
||||
|
||||
|
|
@ -356,25 +358,27 @@ WalletFactory.prototype.joinCreateSession = function(secret, nickname, passphras
|
|||
copayerId: privateKey.getId(),
|
||||
privkey: privateKey.getIdPriv(),
|
||||
key: privateKey.getIdKey(),
|
||||
secretNumber : s.secretNumber,
|
||||
secretNumber: decodedSecret.secretNumber,
|
||||
};
|
||||
self.network.cleanUp();
|
||||
|
||||
var joinNetwork = this.networks[decodedSecret.networkName];
|
||||
joinNetwork.cleanUp();
|
||||
|
||||
// This is a hack to reconize if the connection was rejected or the peer wasn't there.
|
||||
var connectedOnce = false;
|
||||
self.network.on('connected', function(sender, data) {
|
||||
joinNetwork.on('connected', function(sender, data) {
|
||||
connectedOnce = true;
|
||||
});
|
||||
|
||||
self.network.on('serverError', function() {
|
||||
joinNetwork.on('serverError', function() {
|
||||
return cb('joinError');
|
||||
});
|
||||
|
||||
self.network.start(opts, function() {
|
||||
self.network.greet(s.pubKey,opts.secretNumber);
|
||||
self.network.on('data', function(sender, data) {
|
||||
joinNetwork.start(opts, function() {
|
||||
joinNetwork.greet(decodedSecret.pubKey, opts.secretNumber);
|
||||
joinNetwork.on('data', function(sender, data) {
|
||||
if (data.type === 'walletId') {
|
||||
if (data.networkName !== self.networkName) {
|
||||
if (data.networkName !== decodedSecret.networkName) {
|
||||
return cb('badNetwork');
|
||||
}
|
||||
|
||||
|
|
@ -383,8 +387,7 @@ WalletFactory.prototype.joinCreateSession = function(secret, nickname, passphras
|
|||
data.opts.passphrase = passphrase;
|
||||
data.opts.id = data.walletId;
|
||||
var w = self.create(data.opts);
|
||||
w.sendWalletReady(s.pubKey);
|
||||
//w.seedCopayer(s.pubKey);
|
||||
w.sendWalletReady(decodedSecret.pubKey);
|
||||
return cb(null, w);
|
||||
} else {
|
||||
return cb('walletFull', w);
|
||||
|
|
|
|||
|
|
@ -11,12 +11,11 @@ var io = require('socket.io-client');
|
|||
var preconditions = require('preconditions').singleton();
|
||||
|
||||
function Network(opts) {
|
||||
var self = this;
|
||||
preconditions.checkArgument(opts);
|
||||
preconditions.checkArgument(opts.url);
|
||||
opts = opts || {};
|
||||
this.maxPeers = opts.maxPeers || 12;
|
||||
this.host = opts.host || 'localhost';
|
||||
this.port = opts.port || 3001;
|
||||
this.schema = opts.schema || 'https';
|
||||
this.url = opts.url;
|
||||
this.secretNumber = opts.secretNumber;
|
||||
this.cleanUp();
|
||||
}
|
||||
|
|
@ -74,12 +73,12 @@ Network.prototype.connectedCopayers = function() {
|
|||
return ret;
|
||||
};
|
||||
|
||||
Network.prototype._sendHello = function(copayerId,secretNumber) {
|
||||
Network.prototype._sendHello = function(copayerId, secretNumber) {
|
||||
|
||||
this.send(copayerId, {
|
||||
type: 'hello',
|
||||
copayerId: this.copayerId,
|
||||
secretNumber : secretNumber
|
||||
secretNumber: secretNumber
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -197,11 +196,10 @@ Network.prototype._onMessage = function(enc) {
|
|||
var self = this;
|
||||
switch (payload.type) {
|
||||
case 'hello':
|
||||
if (typeof payload.secretNumber === 'undefined' || payload.secretNumber !== this.secretNumber)
|
||||
{
|
||||
if (typeof payload.secretNumber === 'undefined' || payload.secretNumber !== this.secretNumber) {
|
||||
this._sendRejectConnection(sender);
|
||||
this._deletePeer(enc.pubkey, 'incorrect secret number');
|
||||
return;
|
||||
return;
|
||||
}
|
||||
// if we locked allowed copayers, check if it belongs
|
||||
if (this.allowedCopayerIds && !this.allowedCopayerIds[payload.copayerId]) {
|
||||
|
|
@ -274,8 +272,8 @@ Network.prototype._onError = function(err) {
|
|||
this.criticalError = err.message;
|
||||
};
|
||||
|
||||
Network.prototype.greet = function(copayerId,secretNumber) {
|
||||
this._sendHello(copayerId,secretNumber);
|
||||
Network.prototype.greet = function(copayerId, secretNumber) {
|
||||
this._sendHello(copayerId, secretNumber);
|
||||
var peerId = this.peerFromCopayer(copayerId);
|
||||
this._addCopayerMap(peerId, copayerId);
|
||||
};
|
||||
|
|
@ -326,11 +324,10 @@ Network.prototype.start = function(opts, openCallback) {
|
|||
};
|
||||
|
||||
Network.prototype.createSocket = function() {
|
||||
var hostPort = this.schema + '://' + this.host + ':' + this.port;
|
||||
return io.connect(hostPort, {
|
||||
return io.connect(this.url, {
|
||||
reconnection: true,
|
||||
'force new connection': true,
|
||||
'secure': this.schema === 'https',
|
||||
'secure': this.url.indexOf('https') === 0,
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@ angular.module('copayApp.services')
|
|||
$scope.loading = false;
|
||||
});
|
||||
|
||||
|
||||
w.on('corrupt', function(peerId) {
|
||||
notification.error('Error', 'Received corrupt message from ' + peerId);
|
||||
});
|
||||
|
|
@ -176,7 +175,7 @@ angular.module('copayApp.services')
|
|||
w.getBalance(function(err, balanceSat, balanceByAddrSat, safeBalanceSat) {
|
||||
if (err) throw err;
|
||||
|
||||
var satToUnit = 1 / config.unitToSatoshi;
|
||||
var satToUnit = 1 / w.settings.unitToSatoshi;
|
||||
var COIN = bitcore.util.COIN;
|
||||
|
||||
$rootScope.totalBalance = balanceSat * satToUnit;
|
||||
|
|
@ -196,9 +195,9 @@ angular.module('copayApp.services')
|
|||
$rootScope.updatingBalance = false;
|
||||
|
||||
rateService.whenAvailable(function() {
|
||||
$rootScope.totalBalanceAlternative = rateService.toFiat(balanceSat, config.alternativeIsoCode);
|
||||
$rootScope.alternativeIsoCode = config.alternativeIsoCode;
|
||||
$rootScope.lockedBalanceAlternative = rateService.toFiat(balanceSat - safeBalanceSat, config.alternativeIsoCode);
|
||||
$rootScope.totalBalanceAlternative = rateService.toFiat(balanceSat, w.settings.alternativeIsoCode);
|
||||
$rootScope.alternativeIsoCode = w.settings.alternativeIsoCode;
|
||||
$rootScope.lockedBalanceAlternative = rateService.toFiat(balanceSat - safeBalanceSat, w.settings.alternativeIsoCode);
|
||||
|
||||
|
||||
return cb ? cb() : null;
|
||||
|
|
@ -211,7 +210,7 @@ angular.module('copayApp.services')
|
|||
if (!w) return;
|
||||
opts = opts || $rootScope.txsOpts || {};
|
||||
|
||||
var satToUnit = 1 / config.unitToSatoshi;
|
||||
var satToUnit = 1 / w.settings.unitToSatoshi;
|
||||
var myCopayerId = w.getMyCopayerId();
|
||||
var pendingForUs = 0;
|
||||
var inT = w.getTxProposals().sort(function(t1, t2) {
|
||||
|
|
@ -235,7 +234,7 @@ angular.module('copayApp.services')
|
|||
var tx = i.builder.build();
|
||||
var outs = [];
|
||||
tx.outs.forEach(function(o) {
|
||||
var addr = bitcore.Address.fromScriptPubKey(o.getScript(), config.networkName)[0].toString();
|
||||
var addr = bitcore.Address.fromScriptPubKey(o.getScript(), w.getNetworkName())[0].toString();
|
||||
if (!w.addressIsOwn(addr, {
|
||||
excludeMain: true
|
||||
})) {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
"bugs": {
|
||||
"url": "https://github.com/bitpay/copay/issues"
|
||||
},
|
||||
"version": "0.5.0",
|
||||
"version": "0.6.0",
|
||||
"dependencies": {
|
||||
"browser-request": "^0.3.2",
|
||||
"inherits": "^2.0.1",
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ FakeBlockchain.prototype.getTransaction = function(txid, cb) {
|
|||
};
|
||||
|
||||
FakeBlockchain.prototype.getTransactions = function(addresses, cb) {
|
||||
return cb(null, []);
|
||||
cb(null, []);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -6,11 +6,10 @@ if (is_browser) {
|
|||
}
|
||||
var Wallet = copay.Wallet;
|
||||
|
||||
var FakePrivateKey = function () {
|
||||
};
|
||||
var FakePrivateKey = function() {};
|
||||
|
||||
FakePrivateKey.prototype.toObj = function() {
|
||||
return extendedPublicKeyString = 'privHex';
|
||||
return extendedPublicKeyString = 'privHex';
|
||||
};
|
||||
|
||||
var FakeWallet = function() {
|
||||
|
|
@ -37,11 +36,21 @@ var FakeWallet = function() {
|
|||
}
|
||||
};
|
||||
this.blockchain = {
|
||||
getSubscriptions: function(){ return []; },
|
||||
subscribe: function(){}
|
||||
getSubscriptions: function() {
|
||||
return [];
|
||||
},
|
||||
subscribe: function() {},
|
||||
getTransactions: function() {}
|
||||
};
|
||||
|
||||
this.privateKey = new FakePrivateKey();
|
||||
this.settings = {
|
||||
unitName: 'bits',
|
||||
unitToSatoshi: 100,
|
||||
unitDecimals: 2,
|
||||
alternativeName: 'US Dollar',
|
||||
alternativeIsoCode: 'USD',
|
||||
};
|
||||
};
|
||||
|
||||
FakeWallet.prototype.createTx = function(toAddress, amountSatStr, comment, opts, cb) {
|
||||
|
|
@ -52,6 +61,9 @@ FakeWallet.prototype.createTx = function(toAddress, amountSatStr, comment, opts,
|
|||
FakeWallet.prototype.sendTx = function(ntxid, cb) {
|
||||
cb(8);
|
||||
}
|
||||
FakeWallet.prototype.getAddressesStr = function() {
|
||||
return ['2Mw2YXxyMD7fhtPhHYY39X6BVWiBRaez5Zn'];
|
||||
};
|
||||
|
||||
FakeWallet.prototype.set = function(balance, safeBalance, balanceByAddr) {
|
||||
this.balance = balance;
|
||||
|
|
@ -98,8 +110,7 @@ FakeWallet.prototype.getBalance = function(cb) {
|
|||
return cb(null, this.balance, this.balanceByAddr, this.safeBalance);
|
||||
};
|
||||
|
||||
FakeWallet.prototype.removeTxWithSpentInputs = function (cb) {
|
||||
};
|
||||
FakeWallet.prototype.removeTxWithSpentInputs = function(cb) {};
|
||||
|
||||
FakeWallet.prototype.setEnc = function(enc) {
|
||||
this.enc = enc;
|
||||
|
|
@ -109,7 +120,10 @@ FakeWallet.prototype.toEncryptedObj = function() {
|
|||
return this.enc;
|
||||
};
|
||||
|
||||
FakeWallet.prototype.close = function() {
|
||||
FakeWallet.prototype.close = function() {};
|
||||
|
||||
FakeWallet.prototype.getNetworkName = function() {
|
||||
return 'testnet';
|
||||
};
|
||||
|
||||
// TODO a try catch was here
|
||||
|
|
|
|||
|
|
@ -86,7 +86,6 @@ describe('PayPro (in Wallet) model', function() {
|
|||
};
|
||||
|
||||
c.networkName = walletConfig.networkName;
|
||||
c.verbose = walletConfig.verbose;
|
||||
c.version = '0.0.1';
|
||||
|
||||
return new Wallet(c);
|
||||
|
|
|
|||
|
|
@ -102,7 +102,6 @@ describe('Wallet model', function() {
|
|||
};
|
||||
|
||||
c.networkName = walletConfig.networkName;
|
||||
c.verbose = walletConfig.verbose;
|
||||
c.version = '0.0.1';
|
||||
|
||||
|
||||
|
|
@ -363,7 +362,18 @@ describe('Wallet model', function() {
|
|||
var s = Wallet.decodeSecret(sb);
|
||||
s.pubKey.should.equal(id);
|
||||
s.secretNumber.should.equal(secretNumber);
|
||||
s.networkName.should.equal(w.getNetworkName());
|
||||
});
|
||||
|
||||
it('#getSecret decodeSecret livenet', function() {
|
||||
var w = cachedCreateW2();
|
||||
var stub = sinon.stub(w, 'getNetworkName');
|
||||
stub.returns('livenet');
|
||||
var sb = w.getSecret();
|
||||
should.exist(sb);
|
||||
var s = Wallet.decodeSecret(sb);
|
||||
s.networkName.should.equal('livenet');
|
||||
stub.restore();
|
||||
});
|
||||
|
||||
|
||||
|
|
@ -1533,4 +1543,4 @@ describe('Wallet model', function() {
|
|||
should.exist(n.networkNonce);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -40,9 +40,7 @@ var UNSPENT = [{
|
|||
}];
|
||||
|
||||
var FAKE_OPTS = {
|
||||
host: 'something.com',
|
||||
port: 123,
|
||||
schema: 'http'
|
||||
url: 'http://something.com:123',
|
||||
}
|
||||
|
||||
describe('Insight model', function() {
|
||||
|
|
@ -348,7 +346,7 @@ describe('Insight model', function() {
|
|||
});
|
||||
|
||||
describe('Events', function() {
|
||||
it('should emmit event on a new block', function(done) {
|
||||
it('should emit event on a new block', function(done) {
|
||||
var blockchain = new Insight(FAKE_OPTS);
|
||||
var socket = blockchain.getSocket();
|
||||
blockchain.on('connect', function() {
|
||||
|
|
@ -362,7 +360,7 @@ describe('Insight model', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('should emmit event on a transaction for subscribed addresses', function(done) {
|
||||
it('should emit event on a transaction for subscribed addresses', function(done) {
|
||||
var blockchain = new Insight(FAKE_OPTS);
|
||||
var socket = blockchain.getSocket();
|
||||
blockchain.subscribe('2NFjCBFZSsxiwWAD7CKQ3hzWFtf9DcqTucY');
|
||||
|
|
@ -378,7 +376,7 @@ describe('Insight model', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('should\'t emmit event on a transaction for non subscribed addresses', function(done) {
|
||||
it('should\'t emit event on a transaction for non subscribed addresses', function(done) {
|
||||
var blockchain = new Insight(FAKE_OPTS);
|
||||
var socket = blockchain.getSocket();
|
||||
blockchain.on('connect', function() {
|
||||
|
|
@ -392,7 +390,7 @@ describe('Insight model', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('should emmit event on connection', function(done) {
|
||||
it('should emit event on connection', function(done) {
|
||||
var blockchain = new Insight(FAKE_OPTS);
|
||||
var socket = blockchain.getSocket();
|
||||
blockchain.on('connect', function() {
|
||||
|
|
@ -400,7 +398,7 @@ describe('Insight model', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('should emmit event on disconnection', function(done) {
|
||||
it('should emit event on disconnection', function(done) {
|
||||
var blockchain = new Insight(FAKE_OPTS);
|
||||
var socket = blockchain.getSocket();
|
||||
blockchain.on('connect', function() {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,9 @@ describe('Network / Async', function() {
|
|||
|
||||
|
||||
var createN = function(pk) {
|
||||
var n = new Async();
|
||||
var n = new Async({
|
||||
url: 'http://insight.example.com:1234'
|
||||
});
|
||||
var fakeSocket = {};
|
||||
fakeSocket.emit = function() {};
|
||||
fakeSocket.on = function() {};
|
||||
|
|
|
|||
|
|
@ -34,12 +34,6 @@ describe("Unit: Controllers", function() {
|
|||
alternativeIsoCode: 'LOL'
|
||||
};
|
||||
|
||||
it('Copay config should be binded', function() {
|
||||
should.exist(config);
|
||||
should.exist(config.unitToSatoshi);
|
||||
});
|
||||
|
||||
|
||||
describe('More Controller', function() {
|
||||
var ctrl;
|
||||
beforeEach(inject(function($controller, $rootScope) {
|
||||
|
|
@ -110,6 +104,7 @@ describe("Unit: Controllers", function() {
|
|||
var transactionsCtrl;
|
||||
beforeEach(inject(function($controller, $rootScope) {
|
||||
scope = $rootScope.$new();
|
||||
$rootScope.wallet = new FakeWallet(walletConfig);
|
||||
transactionsCtrl = $controller('TransactionsController', {
|
||||
$scope: scope,
|
||||
});
|
||||
|
|
@ -131,7 +126,11 @@ describe("Unit: Controllers", function() {
|
|||
beforeEach(module(function($provide) {
|
||||
$provide.value('request', {
|
||||
'get': function(_, cb) {
|
||||
cb(null, null, [{name: 'lol currency', code: 'LOL', rate: 2}]);
|
||||
cb(null, null, [{
|
||||
name: 'lol currency',
|
||||
code: 'LOL',
|
||||
rate: 2
|
||||
}]);
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
|
@ -139,8 +138,8 @@ describe("Unit: Controllers", function() {
|
|||
scope = $rootScope.$new();
|
||||
scope.rateService = rateService;
|
||||
$rootScope.wallet = new FakeWallet(walletConfig);
|
||||
config.alternativeName = 'lol currency';
|
||||
config.alternativeIsoCode = 'LOL';
|
||||
$rootScope.wallet.settings.alternativeName = 'lol currency';
|
||||
$rootScope.wallet.settings.alternativeIsoCode = 'LOL';
|
||||
var element = angular.element(
|
||||
'<form name="form">' +
|
||||
'<input type="text" id="newaddress" name="newaddress" ng-disabled="loading" placeholder="Address" ng-model="newaddress" valid-address required>' +
|
||||
|
|
@ -224,35 +223,35 @@ describe("Unit: Controllers", function() {
|
|||
sinon.assert.callCount(spy2, 0);
|
||||
sinon.assert.callCount(scope.loadTxs, 1);
|
||||
spy.getCall(0).args[0].should.equal('mkfTyEk7tfgV611Z4ESwDDSZwhsZdbMpVy');
|
||||
spy.getCall(0).args[1].should.equal(1000 * config.unitToSatoshi);
|
||||
spy.getCall(0).args[1].should.equal(1000 * scope.wallet.settings.unitToSatoshi);
|
||||
(typeof spy.getCall(0).args[2]).should.equal('undefined');
|
||||
});
|
||||
|
||||
|
||||
it('should handle big values in 100 BTC', function() {
|
||||
var old = config.unitToSatoshi;
|
||||
config.unitToSatoshi = 100000000;;
|
||||
var old = scope.wallet.settings.unitToSatoshi;
|
||||
scope.wallet.settings.unitToSatoshi = 100000000;;
|
||||
sendForm.address.$setViewValue('mkfTyEk7tfgV611Z4ESwDDSZwhsZdbMpVy');
|
||||
sendForm.amount.$setViewValue(100);
|
||||
var spy = sinon.spy(scope.wallet, 'createTx');
|
||||
scope.loadTxs = sinon.spy();
|
||||
scope.submitForm(sendForm);
|
||||
spy.getCall(0).args[1].should.equal(100 * config.unitToSatoshi);
|
||||
config.unitToSatoshi = old;
|
||||
spy.getCall(0).args[1].should.equal(100 * scope.wallet.settings.unitToSatoshi);
|
||||
scope.wallet.settings.unitToSatoshi = old;
|
||||
});
|
||||
|
||||
|
||||
it('should handle big values in 5000 BTC', function() {
|
||||
var old = config.unitToSatoshi;
|
||||
config.unitToSatoshi = 100000000;;
|
||||
it('should handle big values in 5000 BTC', inject(function($rootScope) {
|
||||
var old = $rootScope.wallet.settings.unitToSatoshi;
|
||||
$rootScope.wallet.settings.unitToSatoshi = 100000000;;
|
||||
sendForm.address.$setViewValue('mkfTyEk7tfgV611Z4ESwDDSZwhsZdbMpVy');
|
||||
sendForm.amount.$setViewValue(5000);
|
||||
var spy = sinon.spy(scope.wallet, 'createTx');
|
||||
scope.loadTxs = sinon.spy();
|
||||
scope.submitForm(sendForm);
|
||||
spy.getCall(0).args[1].should.equal(5000 * config.unitToSatoshi);
|
||||
config.unitToSatoshi = old;
|
||||
});
|
||||
spy.getCall(0).args[1].should.equal(5000 * $rootScope.wallet.settings.unitToSatoshi);
|
||||
$rootScope.wallet.settings.unitToSatoshi = old;
|
||||
}));
|
||||
|
||||
it('should convert bits amount to fiat', function(done) {
|
||||
scope.rateService.whenAvailable(function() {
|
||||
|
|
@ -305,15 +304,15 @@ describe("Unit: Controllers", function() {
|
|||
beforeEach(inject(function($controller, $injector) {
|
||||
$httpBackend = $injector.get('$httpBackend');
|
||||
$httpBackend.when('GET', GH)
|
||||
.respond([{
|
||||
name: "v100.1.6",
|
||||
zipball_url: "https://api.github.com/repos/bitpay/copay/zipball/v0.0.6",
|
||||
tarball_url: "https://api.github.com/repos/bitpay/copay/tarball/v0.0.6",
|
||||
commit: {
|
||||
sha: "ead7352bf2eca705de58d8b2f46650691f2bc2c7",
|
||||
url: "https://api.github.com/repos/bitpay/copay/commits/ead7352bf2eca705de58d8b2f46650691f2bc2c7"
|
||||
}
|
||||
}]);
|
||||
.respond([{
|
||||
name: "v100.1.6",
|
||||
zipball_url: "https://api.github.com/repos/bitpay/copay/zipball/v0.0.6",
|
||||
tarball_url: "https://api.github.com/repos/bitpay/copay/tarball/v0.0.6",
|
||||
commit: {
|
||||
sha: "ead7352bf2eca705de58d8b2f46650691f2bc2c7",
|
||||
url: "https://api.github.com/repos/bitpay/copay/commits/ead7352bf2eca705de58d8b2f46650691f2bc2c7"
|
||||
}
|
||||
}]);
|
||||
}));
|
||||
|
||||
var rootScope;
|
||||
|
|
@ -358,11 +357,6 @@ describe("Unit: Controllers", function() {
|
|||
scope.$apply();
|
||||
});
|
||||
|
||||
it('should return networkName', function() {
|
||||
$httpBackend.flush(); // need flush
|
||||
var networkName = scope.networkName;
|
||||
expect(networkName).equal('testnet');
|
||||
});
|
||||
});
|
||||
|
||||
describe("Unit: Sidebar Controller", function() {
|
||||
|
|
@ -390,6 +384,7 @@ describe("Unit: Controllers", function() {
|
|||
beforeEach(inject(function($compile, $rootScope, $controller) {
|
||||
scope = $rootScope.$new();
|
||||
$rootScope.availableBalance = 123456;
|
||||
$rootScope.wallet = new FakeWallet(walletConfig);
|
||||
|
||||
var element = angular.element(
|
||||
'<form name="form">' +
|
||||
|
|
|
|||
|
|
@ -8,17 +8,23 @@ describe("Unit: Testing Directives", function() {
|
|||
|
||||
beforeEach(module('copayApp.directives'));
|
||||
|
||||
beforeEach(function() {
|
||||
config.unitToSatoshi = 100;
|
||||
config.unitName = 'bits';
|
||||
});
|
||||
var walletConfig = {
|
||||
requiredCopayers: 3,
|
||||
totalCopayers: 5,
|
||||
spendUnconfirmed: 1,
|
||||
reconnectDelay: 100,
|
||||
networkName: 'testnet',
|
||||
alternativeName: 'lol currency',
|
||||
alternativeIsoCode: 'LOL'
|
||||
};
|
||||
|
||||
describe('Check config', function() {
|
||||
it('unit should be set to BITS in config.js', function() {
|
||||
expect(config.unitToSatoshi).to.equal(100);
|
||||
expect(config.unitName).to.equal('bits');
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(inject(function($rootScope) {
|
||||
$rootScope.wallet = new FakeWallet(walletConfig);
|
||||
var w = $rootScope.wallet;
|
||||
w.settings.unitToSatoshi = 100;
|
||||
w.settings.unitName = 'bits';
|
||||
}));
|
||||
|
||||
describe('Validate Address', function() {
|
||||
beforeEach(inject(function($compile, $rootScope) {
|
||||
|
|
@ -36,16 +42,16 @@ describe("Unit: Testing Directives", function() {
|
|||
form = $scope.form;
|
||||
}));
|
||||
|
||||
it('should validate with network', function() {
|
||||
config.networkName = 'testnet';
|
||||
it('should validate with network', inject(function($rootScope) {
|
||||
$rootScope.wallet.getNetworkName = sinon.stub().returns('testnet');
|
||||
form.address.$setViewValue('mkfTyEk7tfgV611Z4ESwDDSZwhsZdbMpVy');
|
||||
expect(form.address.$invalid).to.equal(false);
|
||||
});
|
||||
it('should not validate with other network', function() {
|
||||
config.networkName = 'livenet';
|
||||
}));
|
||||
it('should not validate with other network', inject(function($rootScope) {
|
||||
$rootScope.wallet.getNetworkName = sinon.stub().returns('livenet');
|
||||
form.address.$setViewValue('mkfTyEk7tfgV611Z4ESwDDSZwhsZdbMpVy');
|
||||
expect(form.address.$invalid).to.equal(true);
|
||||
});
|
||||
}));
|
||||
it('should not validate random', function() {
|
||||
form.address.$setViewValue('thisisaninvalidaddress');
|
||||
expect(form.address.$invalid).to.equal(true);
|
||||
|
|
@ -94,9 +100,12 @@ describe("Unit: Testing Directives", function() {
|
|||
|
||||
describe('Unit: BTC', function() {
|
||||
beforeEach(inject(function($compile, $rootScope) {
|
||||
config.unitToSatoshi = 100000000;
|
||||
config.unitName = 'BTC';
|
||||
$scope = $rootScope;
|
||||
var w = new FakeWallet(walletConfig);
|
||||
w.settings.unitToSatoshi = 100000000;
|
||||
w.settings.unitName = 'BTC';
|
||||
$rootScope.wallet = w;
|
||||
|
||||
$rootScope.availableBalance = 0.04;
|
||||
var element = angular.element(
|
||||
'<form name="form">' +
|
||||
|
|
|
|||
|
|
@ -5,6 +5,15 @@
|
|||
describe('Unit: Testing Filters', function() {
|
||||
|
||||
beforeEach(module('copayApp.filters'));
|
||||
var walletConfig = {
|
||||
requiredCopayers: 3,
|
||||
totalCopayers: 5,
|
||||
spendUnconfirmed: 1,
|
||||
reconnectDelay: 100,
|
||||
networkName: 'testnet',
|
||||
alternativeName: 'lol currency',
|
||||
alternativeIsoCode: 'LOL'
|
||||
};
|
||||
|
||||
describe('limitAddress', function() {
|
||||
|
||||
|
|
@ -103,68 +112,76 @@ describe('Unit: Testing Filters', function() {
|
|||
}));
|
||||
});
|
||||
|
||||
describe('noFractionNumber bits', function() {
|
||||
beforeEach(function() {
|
||||
config.unitToSatoshi = 100;
|
||||
config.unitName = 'bits';
|
||||
describe('noFractionNumber', function() {
|
||||
describe('noFractionNumber bits', function() {
|
||||
beforeEach(inject(function($rootScope) {
|
||||
$rootScope.wallet = new FakeWallet(walletConfig);
|
||||
var w = $rootScope.wallet;
|
||||
w.settings.unitToSatoshi = 100;
|
||||
w.settings.unitName = 'bits';
|
||||
}));
|
||||
it('should format number to display correctly', inject(function($filter) {
|
||||
var noFraction = $filter('noFractionNumber');
|
||||
expect(noFraction(3100)).to.equal('3,100');
|
||||
expect(noFraction(3100200)).to.equal('3,100,200');
|
||||
expect(noFraction(3)).to.equal('3');
|
||||
expect(noFraction(0.3)).to.equal(0.3);
|
||||
expect(noFraction(0.30000000)).to.equal(0.3);
|
||||
expect(noFraction(3200.01)).to.equal('3,200.01');
|
||||
expect(noFraction(3200890.010000)).to.equal('3,200,890.01');
|
||||
}));
|
||||
});
|
||||
it('should format number to display correctly', inject(function($filter) {
|
||||
var noFraction = $filter('noFractionNumber');
|
||||
expect(noFraction(3100)).to.equal('3,100');
|
||||
expect(noFraction(3100200)).to.equal('3,100,200');
|
||||
expect(noFraction(3)).to.equal('3');
|
||||
expect(noFraction(0.3)).to.equal(0.3);
|
||||
expect(noFraction(0.30000000)).to.equal(0.3);
|
||||
expect(noFraction(3200.01)).to.equal('3,200.01');
|
||||
expect(noFraction(3200890.010000)).to.equal('3,200,890.01');
|
||||
}));
|
||||
});
|
||||
|
||||
describe('noFractionNumber BTC', function() {
|
||||
beforeEach(function() {
|
||||
config.unitToSatoshi = 100000000;
|
||||
config.unitName = 'BTC';
|
||||
describe('noFractionNumber BTC', function() {
|
||||
beforeEach(inject(function($rootScope) {
|
||||
$rootScope.wallet = new FakeWallet(walletConfig);
|
||||
var w = $rootScope.wallet;
|
||||
w.settings.unitToSatoshi = 100000000;
|
||||
w.settings.unitName = 'BTC';
|
||||
}));
|
||||
it('should format number to display correctly', inject(function($filter) {
|
||||
var noFraction = $filter('noFractionNumber');
|
||||
expect(noFraction(0.30000000)).to.equal(0.3);
|
||||
expect(noFraction(0.00302000)).to.equal(0.00302);
|
||||
expect(noFraction(1.00000001)).to.equal(1.00000001);
|
||||
expect(noFraction(3.10000012)).to.equal(3.10000012);
|
||||
expect(noFraction(0.00100000)).to.equal(0.001);
|
||||
expect(noFraction(0.00100009)).to.equal(0.00100009);
|
||||
expect(noFraction(2000.00312011)).to.equal('2,000.00312011');
|
||||
expect(noFraction(2000998.00312011)).to.equal('2,000,998.00312011');
|
||||
}));
|
||||
});
|
||||
it('should format number to display correctly', inject(function($filter) {
|
||||
var noFraction = $filter('noFractionNumber');
|
||||
expect(noFraction(0.30000000)).to.equal(0.3);
|
||||
expect(noFraction(0.00302000)).to.equal(0.00302);
|
||||
expect(noFraction(1.00000001)).to.equal(1.00000001);
|
||||
expect(noFraction(3.10000012)).to.equal(3.10000012);
|
||||
expect(noFraction(0.00100000)).to.equal(0.001);
|
||||
expect(noFraction(0.00100009)).to.equal(0.00100009);
|
||||
expect(noFraction(2000.00312011)).to.equal('2,000.00312011');
|
||||
expect(noFraction(2000998.00312011)).to.equal('2,000,998.00312011');
|
||||
}));
|
||||
});
|
||||
|
||||
describe('noFractionNumber mBTC', function() {
|
||||
beforeEach(function() {
|
||||
config.unitToSatoshi = 100000;
|
||||
config.unitName = 'mBTC';
|
||||
describe('noFractionNumber mBTC', function() {
|
||||
beforeEach(inject(function($rootScope) {
|
||||
$rootScope.wallet = new FakeWallet(walletConfig);
|
||||
var w = $rootScope.wallet;
|
||||
w.settings.unitToSatoshi = 100000;
|
||||
w.settings.unitName = 'mBTC';
|
||||
}));
|
||||
it('should format number to display correctly', inject(function($filter) {
|
||||
var noFraction = $filter('noFractionNumber');
|
||||
expect(noFraction(0.30000)).to.equal(0.3);
|
||||
expect(noFraction(0.00302)).to.equal(0.00302);
|
||||
expect(noFraction(1.00001)).to.equal(1.00001);
|
||||
expect(noFraction(3.10002)).to.equal(3.10002);
|
||||
expect(noFraction(0.00100000)).to.equal(0.001);
|
||||
expect(noFraction(0.00100009)).to.equal(0.001);
|
||||
expect(noFraction(2000.00312)).to.equal('2,000.00312');
|
||||
expect(noFraction(2000998.00312)).to.equal('2,000,998.00312');
|
||||
}));
|
||||
});
|
||||
it('should format number to display correctly', inject(function($filter) {
|
||||
var noFraction = $filter('noFractionNumber');
|
||||
expect(noFraction(0.30000)).to.equal(0.3);
|
||||
expect(noFraction(0.00302)).to.equal(0.00302);
|
||||
expect(noFraction(1.00001)).to.equal(1.00001);
|
||||
expect(noFraction(3.10002)).to.equal(3.10002);
|
||||
expect(noFraction(0.00100000)).to.equal(0.001);
|
||||
expect(noFraction(0.00100009)).to.equal(0.001);
|
||||
expect(noFraction(2000.00312)).to.equal('2,000.00312');
|
||||
expect(noFraction(2000998.00312)).to.equal('2,000,998.00312');
|
||||
}));
|
||||
});
|
||||
|
||||
describe('noFractionNumber:custom fractionSize', function() {
|
||||
it('should format number to display correctly', inject(function($filter) {
|
||||
var noFraction = $filter('noFractionNumber');
|
||||
expect(noFraction(0.30000, 0)).to.equal('0');
|
||||
expect(noFraction(1.00001, 0)).to.equal('1');
|
||||
expect(noFraction(3.10002, 0)).to.equal('3');
|
||||
expect(noFraction(2000.00312, 0)).to.equal('2,000');
|
||||
expect(noFraction(2000998.00312, 0)).to.equal('2,000,998');
|
||||
}));
|
||||
});
|
||||
describe('noFractionNumber:custom fractionSize', function() {
|
||||
it('should format number to display correctly', inject(function($filter) {
|
||||
var noFraction = $filter('noFractionNumber');
|
||||
expect(noFraction(0.30000, 0)).to.equal('0');
|
||||
expect(noFraction(1.00001, 0)).to.equal('1');
|
||||
expect(noFraction(3.10002, 0)).to.equal('3');
|
||||
expect(noFraction(2000.00312, 0)).to.equal('2,000');
|
||||
expect(noFraction(2000998.00312, 0)).to.equal('2,000,998');
|
||||
}));
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,19 +4,7 @@
|
|||
//
|
||||
//
|
||||
var sinon = require('sinon');
|
||||
|
||||
beforeEach(function() {
|
||||
config.unitToSatoshi = 100;
|
||||
config.unitName = 'bits';
|
||||
});
|
||||
|
||||
describe('Check config', function() {
|
||||
|
||||
it('unit should be set to BITS in config.js', function() {
|
||||
expect(config.unitToSatoshi).to.equal(100);
|
||||
expect(config.unitName).to.equal('bits');
|
||||
});
|
||||
});
|
||||
var preconditions = require('preconditions').singleton();
|
||||
|
||||
describe("Unit: Walletfactory Service", function() {
|
||||
beforeEach(angular.mock.module('copayApp.services'));
|
||||
|
|
|
|||
|
|
@ -15,7 +15,9 @@ var getCommitHash = function() {
|
|||
//exec git command to get the hash of the current commit
|
||||
//git rev-parse HEAD
|
||||
|
||||
var hash = shell.exec('git rev-parse HEAD',{silent:true}).output.trim().substr(0,7);
|
||||
var hash = shell.exec('git rev-parse HEAD', {
|
||||
silent: true
|
||||
}).output.trim().substr(0, 7);
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
|
@ -23,7 +25,7 @@ var createVersion = function() {
|
|||
var json = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
|
||||
var content = 'module.exports.version="' + json.version + '";';
|
||||
|
||||
content = content + '\nmodule.exports.commitHash="' + getCommitHash() + '";';
|
||||
content = content + '\nmodule.exports.commitHash="' + getCommitHash() + '";';
|
||||
fs.writeFileSync("./version.js", content);
|
||||
};
|
||||
|
||||
|
|
@ -43,9 +45,9 @@ var createBundle = function(opts) {
|
|||
b.require('browser-request', {
|
||||
expose: 'request'
|
||||
});
|
||||
b.require('underscore', {
|
||||
expose: 'underscore'
|
||||
});
|
||||
b.require('underscore');
|
||||
b.require('assert');
|
||||
b.require('preconditions');
|
||||
|
||||
b.require('./copay', {
|
||||
expose: 'copay'
|
||||
|
|
@ -130,10 +132,10 @@ if (require.main === module) {
|
|||
};
|
||||
var program = require('commander');
|
||||
program
|
||||
.version('0.0.1')
|
||||
.option('-d, --debug', 'Development. Don\'t minify the codem and include debug packages.')
|
||||
.option('-o, --stdout', 'Specify output as stdout')
|
||||
.parse(process.argv);
|
||||
.version('0.0.1')
|
||||
.option('-d, --debug', 'Development. Don\'t minify the codem and include debug packages.')
|
||||
.option('-o, --stdout', 'Specify output as stdout')
|
||||
.parse(process.argv);
|
||||
|
||||
createVersion();
|
||||
var copayBundle = createBundle(program);
|
||||
|
|
|
|||
|
|
@ -4,39 +4,39 @@
|
|||
<span translate>Addresses</span>
|
||||
<span class="button primary small side-bar" ng-click="newAddr()" ng-disabled="loading"><i class="fi-plus"></i></span>
|
||||
</h1>
|
||||
|
||||
|
||||
<div class="large-12 medium-12" ng-if="!!(addresses|removeEmpty).length">
|
||||
<div class="large-12 medium-12" ng-init="showAll=0">
|
||||
<div class="panel radius oh" ng-repeat="addr in addresses|removeEmpty|limitAddress:showAll">
|
||||
<div class="row collapse">
|
||||
<div class="large-10 medium-9 small-8 column" >
|
||||
<div class="ellipsis list-addr">
|
||||
<i class="fi-thumbnails size-48 show-for-large-up" ng-click="openAddressModal(addr)"> </i>
|
||||
<span>
|
||||
<div class="panel radius oh" ng-repeat="addr in addresses|removeEmpty|limitAddress:showAll">
|
||||
<div class="row collapse">
|
||||
<div class="large-10 medium-9 small-8 column">
|
||||
<div class="ellipsis list-addr">
|
||||
<i class="fi-thumbnails size-48 show-for-large-up" ng-click="openAddressModal(addr)"> </i>
|
||||
<span>
|
||||
<contact address="{{addr.address}}" tooltip-popup-delay="500" tooltip tooltip-placement="right"/>
|
||||
</span>
|
||||
<span class="btn-copy" clip-copy="addr.address"> </span>
|
||||
<small translate class="label" ng-if="addr.isChange">change</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="large-2 medium-3 small-4 column text-right">
|
||||
<span ng-if="$root.updatingBalance">
|
||||
<i class="fi-bitcoin-circle icon-rotate spinner"></i>
|
||||
</span>
|
||||
<span class="size-12" ng-if="!$root.updatingBalance">
|
||||
{{addr.balance || 0|noFractionNumber}} {{$root.unitName}}
|
||||
</span>
|
||||
<span class="btn-copy" clip-copy="addr.address"> </span>
|
||||
<small translate class="label" ng-if="addr.isChange">change</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="large-2 medium-3 small-4 column text-right">
|
||||
<span ng-if="$root.updatingBalance">
|
||||
<i class="fi-bitcoin-circle icon-rotate spinner"></i>
|
||||
</span>
|
||||
<span class="size-12" ng-if="!$root.updatingBalance">
|
||||
{{addr.balance || 0|noFractionNumber}} {{$root.wallet.settings.unitName}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a class="secondary radius" ng-click="showAll=!showAll" ng-show="(addresses|removeEmpty).length != (addresses|removeEmpty|limitAddress).length">
|
||||
<span translate ng-if="!showAll">Show all</span>
|
||||
<span translate ng-if="showAll">Show less</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<a class="secondary radius" ng-click="showAll=!showAll" ng-show="(addresses|removeEmpty).length != (addresses|removeEmpty|limitAddress).length">
|
||||
<span translate ng-if="!showAll">Show all</span>
|
||||
<span translate ng-if="showAll">Show less</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -25,42 +25,31 @@
|
|||
</div>
|
||||
<div>
|
||||
<label for="walletPassword"><span translate>Your Wallet Password</span>
|
||||
<small translate data-options="disable_for_touch:true" class="has-tip text-gray" tooltip="doesn't need to be shared" >Required</small>
|
||||
<small translate data-options="disable_for_touch:true" class="has-tip text-gray" tooltip="doesn't need to be shared">Required</small>
|
||||
</label>
|
||||
<input id="walletPassword" type="password"
|
||||
placeholder="{{'Choose your password'|translate}}" class="form-control"
|
||||
ng-model="$parent.walletPassword"
|
||||
name="walletPassword"
|
||||
check-strength="passwordStrength"
|
||||
tooltip-html-unsafe="Password strength:
|
||||
<input id="walletPassword" type="password" placeholder="{{'Choose your password'|translate}}" class="form-control" ng-model="$parent.walletPassword" name="walletPassword" check-strength="passwordStrength" tooltip-html-unsafe="Password strength:
|
||||
<i>{{passwordStrength}}</i><br/><span
|
||||
class='size-12'>Tip: Use lower and uppercase, numbers and
|
||||
symbols</span>"
|
||||
tooltip-trigger="focus" required
|
||||
tooltip-placement="top">
|
||||
|
||||
<input type="password"
|
||||
placeholder="{{'Repeat password'|translate}}"
|
||||
name="walletPasswordConfirm"
|
||||
ng-model="walletPasswordConfirm"
|
||||
match="walletPassword"
|
||||
required>
|
||||
symbols</span>" tooltip-trigger="focus" required tooltip-placement="top">
|
||||
|
||||
<input type="password" placeholder="{{'Repeat password'|translate}}" name="walletPasswordConfirm" ng-model="walletPasswordConfirm" match="walletPassword" required>
|
||||
|
||||
<div class="text-left">
|
||||
<input id="network-name" type="checkbox" ng-model="networkName" ng-true-value="testnet" ng-false-value="livenet" class="form-control" ng-click="changeNetwork()" ng-checked="networkName == 'testnet' ? true : false">
|
||||
<label for="network-name">Use test network</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a class="expand small" ng-click="hideAdv=!hideAdv">
|
||||
<a class="expand small" ng-click="hideAdv=!hideAdv">
|
||||
<span translate ng-hide="!hideAdv">Show</span>
|
||||
<span translate ng-hide="hideAdv">Hide</span>
|
||||
<span translate>advanced options</span>
|
||||
</a>
|
||||
<div ng-hide="hideAdv">
|
||||
<p>
|
||||
<input type="text"
|
||||
placeholder="{{'Private Key (Hex)'|translate}}"
|
||||
name="private"
|
||||
ng-model="private"
|
||||
>
|
||||
<input type="text" placeholder="{{'Private Key (Hex)'|translate}}" name="private" ng-model="private">
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="row" ng-show="!isSetupWalletPage">
|
||||
<div class="large-6 medium-6 columns">
|
||||
|
|
@ -78,24 +67,17 @@
|
|||
</div>
|
||||
<div class="box-setup-copayers" ng-show="!isSetupWalletPage">
|
||||
<div class="box-setup-copayers p10">
|
||||
<img class="br100 oh box-setup-copay m10" ng-repeat="i in getNumber(totalCopayers) track by $index"
|
||||
src="./img/satoshi.gif"
|
||||
title="Copayer {{$index+1}}-{{totalCopayers}}"
|
||||
ng-class="{'box-setup-copay-required': ($index+1) <= requiredCopayers}"
|
||||
width="50px">
|
||||
<img class="br100 oh box-setup-copay m10" ng-repeat="i in getNumber(totalCopayers) track by $index" src="./img/satoshi.gif" title="Copayer {{$index+1}}-{{totalCopayers}}" ng-class="{'box-setup-copay-required': ($index+1) <= requiredCopayers}" width="50px">
|
||||
</div>
|
||||
</div>
|
||||
<p translate class="comment" ng-show="totalCopayers>1 && !isSetupWalletPage">(*) The limits are imposed by the bitcoin network.</p>
|
||||
<div class="text-right">
|
||||
<a ng-show="!isSetupWalletPage" class="back-button m20r"
|
||||
href="#!/">« <span translate>Back</span></a>
|
||||
<a ng-show="isSetupWalletPage" class="back-button m20r"
|
||||
ng-click="setupWallet()">« <span translate>Back</span></a>
|
||||
<a ng-show="!isSetupWalletPage" class="back-button m20r" href="#!/">« <span translate>Back</span></a>
|
||||
<a ng-show="isSetupWalletPage" class="back-button m20r" ng-click="setupWallet()">« <span translate>Back</span></a>
|
||||
<button translate ng-show="isSetupWalletPage" type="submit" class="button secondary m0" ng-disabled="setupForm.$invalid || loading">
|
||||
Create {{requiredCopayers}}-of-{{totalCopayers}} wallet
|
||||
</button>
|
||||
<a translate class="button secondary m0" ng-show="!isSetupWalletPage"
|
||||
ng-click="setupWallet()">Next</a>
|
||||
<a translate class="button secondary m0" ng-show="!isSetupWalletPage" ng-click="setupWallet()">Next</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -103,4 +85,3 @@
|
|||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -6,9 +6,41 @@
|
|||
</a>
|
||||
<div ng-include="'views/includes/version.html'"></div>
|
||||
</div>
|
||||
|
||||
<div class="line-sidebar-b"></div>
|
||||
<div>
|
||||
<div ng-if="$root.wallet" class="founds size-12 text-center box-founds p10t">
|
||||
<div class="m10b">
|
||||
Balance
|
||||
<span ng-if="$root.updatingBalance">
|
||||
<i class="fi-bitcoin-circle icon-rotate spinner"></i>
|
||||
</span>
|
||||
<span ng-if="$root.wallet && !$root.updatingBalance"
|
||||
data-options="disable_for_touch:true"
|
||||
tooltip="{{totalBalanceBTC |noFractionNumber:8}} BTC"
|
||||
tooltip-trigger="mouseenter"
|
||||
tooltip-placement="bottom">{{totalBalance || 0
|
||||
|noFractionNumber}} {{$root.wallet.settings.unitName}}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
Locked
|
||||
<span ng-if="$root.updatingBalance">
|
||||
<i class="fi-bitcoin-circle icon-rotate spinner"></i>
|
||||
</span>
|
||||
<span ng-if="$root.wallet && !$root.updatingBalance"
|
||||
data-options="disable_for_touch:true"
|
||||
tooltip="{{lockedBalanceBTC |noFractionNumber:8}} BTC"
|
||||
tooltip-trigger="mouseenter"
|
||||
tooltip-placement="bottom">{{lockedBalance || 0|noFractionNumber}} {{$root.wallet.settings.unitName}}
|
||||
</span> <i class="fi-info medium" tooltip="Balance locked in pending transaction proposals" tooltip-placement="bottom"></i>
|
||||
</div>
|
||||
<div class="line-sidebar-b"></div>
|
||||
</div>
|
||||
|
||||
</header>
|
||||
<div class="line-sidebar-b"></div>
|
||||
<div class="founds size-12 box-founds p15" ng-disabled="$root.loading" ng-click="refresh()">
|
||||
<div ng-if="$root.wallet" class="founds size-12 box-founds p15" ng-disabled="$root.loading" ng-click="refresh()">
|
||||
<p class="text-gray">
|
||||
<span>{{$root.wallet.getName()}}</span>
|
||||
<span class="size-12 right">{{$root.wallet.requiredCopayers}}-of-{{$root.wallet.totalCopayers}}</span>
|
||||
|
|
@ -20,7 +52,7 @@
|
|||
<i class="fi-bitcoin-circle icon-rotate spinner"></i>
|
||||
</span>
|
||||
<span ng-if="!$root.updatingBalance">{{totalBalance || 0
|
||||
|noFractionNumber}} {{$root.unitName}}
|
||||
|noFractionNumber}} {{$root.wallet.settings.unitName}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="m10t" ng-show="lockedBalance">
|
||||
|
|
@ -28,7 +60,7 @@
|
|||
<span ng-if="$root.updatingBalance">
|
||||
<i class="fi-bitcoin-circle icon-rotate spinner"></i>
|
||||
</span>
|
||||
<span ng-show="!$root.updatingBalance">{{lockedBalance || 0|noFractionNumber}} {{$root.unitName}}
|
||||
<span ng-show="!$root.updatingBalance">{{lockedBalance || 0|noFractionNumber}} {{$root.wallet.settings.unitName}}
|
||||
</span> <i class="fi-info medium" tooltip="{{'Balance locked in pending transaction proposals'|translate}}" tooltip-placement="bottom"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -20,26 +20,26 @@
|
|||
<span ng-if="$root.updatingBalance">
|
||||
<i class="fi-bitcoin-circle icon-rotate spinner"></i>
|
||||
</span>
|
||||
<span ng-if="!$root.updatingBalance"
|
||||
<span ng-if="$root.wallet && !$root.updatingBalance"
|
||||
class="has-tip"
|
||||
data-options="disable_for_touch:true"
|
||||
tooltip-popup-delay='500'
|
||||
tooltip="{{totalBalanceAlternative |noFractionNumber:2}} {{alternativeIsoCode}}"
|
||||
tooltip-trigger="mouseenter"
|
||||
tooltip-placement="bottom">{{totalBalance || 0 |noFractionNumber}} {{$root.unitName}}
|
||||
tooltip-placement="bottom">{{totalBalance || 0 |noFractionNumber}} {{$root.wallet.settings.unitName}}
|
||||
</span>
|
||||
<div class="m10t" ng-show="lockedBalance">
|
||||
<span translate>Locked</span>
|
||||
<span ng-if="$root.updatingBalance">
|
||||
<i class="fi-bitcoin-circle icon-rotate spinner"></i>
|
||||
</span>
|
||||
<span ng-show="!$root.updatingBalance"
|
||||
<span ng-if="$root.wallet && !$root.updatingBalance"
|
||||
class="has-tip"
|
||||
data-options="disable_for_touch:true"
|
||||
tooltip-popup-delay='500'
|
||||
tooltip="{{lockedBalanceAlternative |noFractionNumber:2}} {{alternativeIsoCode}}"
|
||||
tooltip-trigger="mouseenter"
|
||||
tooltip-placement="bottom">{{lockedBalance || 0|noFractionNumber}} {{$root.unitName}}
|
||||
tooltip-placement="bottom">{{lockedBalance || 0|noFractionNumber}} {{$root.wallet.settings.unitName}}
|
||||
</span> <i class="fi-info medium" tooltip="{{'Balance locked in pending transaction proposals'|translate}}" tooltip-placement="bottom"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -8,20 +8,19 @@
|
|||
</a>
|
||||
</div>
|
||||
<div class="show-for-small-only small-12 columns m10b" ng-show="tx.comment">
|
||||
<p class="size-14 label" >
|
||||
{{tx.comment}} -
|
||||
{{$root.wallet.publicKeyRing.nicknameForCopayer(tx.creator)}}
|
||||
<p class="size-14 label">
|
||||
{{tx.comment}} - {{$root.wallet.publicKeyRing.nicknameForCopayer(tx.creator)}}
|
||||
</p>
|
||||
</div>
|
||||
<div class="large-8 medium-8 small-8 columns">
|
||||
<div ng-repeat="out in tx.outs">
|
||||
<div class="large-3 medium-3 small-3 columns">
|
||||
<p class="size-14 hide-for-small-only">{{out.value | noFractionNumber}} {{$root.unitName}}</p>
|
||||
<p class="size-12 show-for-small-only">{{out.value | noFractionNumber}} {{$root.unitName}}</p>
|
||||
<p class="size-14 hide-for-small-only">{{out.value | noFractionNumber}} {{$root.wallet.settings.unitName}}</p>
|
||||
<p class="size-12 show-for-small-only">{{out.value | noFractionNumber}} {{$root.wallet.settings.unitName}}</p>
|
||||
</div>
|
||||
<div class="large-1 medium-1 small-2 columns fi-arrow-right"> </div>
|
||||
<div class="large-1 medium-1 small-2 columns fi-arrow-right"></div>
|
||||
<div class="large-8 medium-8 small-7 columns ellipsis">
|
||||
<contact address="{{out.address}}" tooltip-popup-delay="500" tooltip tooltip-placement="right"/>
|
||||
<contact address="{{out.address}}" tooltip-popup-delay="500" tooltip tooltip-placement="right" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -37,25 +36,25 @@
|
|||
</a>
|
||||
<div class="box-status">
|
||||
<a ng-if="c.actions.create" tooltip-popup-delay="1000" tooltip="Created {{c.actions.create | amTimeAgo}}">
|
||||
<i class="fi-crown icon-status icon-active"></i>
|
||||
<i class="fi-crown icon-status icon-active"></i>
|
||||
</a>
|
||||
<a ng-if="!c.actions.create"><i class="fi-crown icon-status"></i></a>
|
||||
|
||||
<a ng-if="c.actions.seen" tooltip-popup-delay="1000" tooltip="Seen {{c.actions.seen | amTimeAgo}}">
|
||||
<i class="fi-eye icon-status icon-active"></i>
|
||||
<i class="fi-eye icon-status icon-active"></i>
|
||||
</a>
|
||||
<a ng-if="!c.actions.seen"><i class="fi-eye icon-status"></i></a>
|
||||
|
||||
<a ng-if="c.actions.rejected" tooltip-popup-delay="1000" tooltip="Rejected {{c.actions.rejected | amTimeAgo}}">
|
||||
<i class="fi-x icon-status icon-active-x"></i>
|
||||
<i class="fi-x icon-status icon-active-x"></i>
|
||||
</a>
|
||||
|
||||
<a ng-if="c.actions.sign" tooltip-popup-delay="1000" tooltip="Signed {{c.actions.sign | amTimeAgo}}">
|
||||
<i class="fi-check icon-status icon-active-check"></i>
|
||||
<i class="fi-check icon-status icon-active-check"></i>
|
||||
</a>
|
||||
|
||||
<a ng-if="!c.actions.sign && !c.actions.rejected && tx.missingSignatures" class="icon-status">
|
||||
<i class="fi-loop icon-rotate"></i>
|
||||
<i class="fi-loop icon-rotate"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
|
@ -100,7 +99,7 @@
|
|||
</div>
|
||||
<div ng-show="!tx.missingSignatures && tx.sentTs">
|
||||
<div class="is-valid m10b">
|
||||
<strong translate>Sent</strong> <span class="text-gray" am-time-ago="tx.sentTs"></span>
|
||||
<strong translate>Sent</strong> <span class="text-gray" am-time-ago="tx.sentTs"></span>
|
||||
</div>
|
||||
<div class="ellipsis small">
|
||||
<span translate>Transaction ID</span>:
|
||||
|
|
@ -110,12 +109,12 @@
|
|||
</div>
|
||||
</div>
|
||||
<p translate class="text-gray m5b" ng-show="!tx.finallyRejected && tx.missingSignatures==1">
|
||||
One signature missing
|
||||
One signature missing
|
||||
</p>
|
||||
<p translate class="text-gray m5b" ng-show="!tx.finallyRejected && tx.missingSignatures>1">
|
||||
{{tx.missingSignatures}} signatures missing</p>
|
||||
{{tx.missingSignatures}} signatures missing</p>
|
||||
<div class="ellipsis small text-gray">
|
||||
<strong translate>Fee</strong>: {{tx.fee|noFractionNumber}} {{$root.unitName}}
|
||||
<strong translate>Fee</strong>: {{tx.fee|noFractionNumber}} {{$root.wallet.settings.unitName}}
|
||||
<strong translate>Proposal ID</strong>: {{tx.ntxid}}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<div ng-controller="VersionController">
|
||||
<small>v{{version}} ({{defaultLanguage}})</small>
|
||||
<small>#{{commitHash}}</small>
|
||||
<small ng-if="networkName=='testnet'">[ {{networkName}} ]</small>
|
||||
<small ng-if="networkName ==='testnet' || networkName ==='livenet'">[ {{networkName}} ]</small>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
<i class="fi-bitcoin-circle icon-rotate spinner"></i>
|
||||
</span>
|
||||
<p class="m15b" ng-if="!$root.updatingBalance">
|
||||
{{address.balance || 0|noFractionNumber}} {{$root.unitName}}
|
||||
{{address.balance || 0|noFractionNumber}} {{$root.wallet.settings.unitName}}
|
||||
</p>
|
||||
<button class="m15t button secondary" open-external address="{{address.address}}">
|
||||
<i class="fi-link"> </i> <span translate>Open in external application</span>
|
||||
|
|
|
|||
|
|
@ -1,62 +1,79 @@
|
|||
<div class="backup" ng-controller="MoreController">
|
||||
<h1 translate>Settings </h1>
|
||||
<div class="oh large-12 columns panel">
|
||||
<h3><i class="fi-download m10r"></i> <span translate>Backup</span> </h3>
|
||||
<p translate class="large-8 columns text-gray">It's important to backup your wallet so that you can recover it in case of disaster</p>
|
||||
<div class="large-4 columns">
|
||||
<a translate class="button primary expand" ng-click="downloadBackup()">Download File</a>
|
||||
</div>
|
||||
<div class="oh large-12 columns panel">
|
||||
<h3><i class="fi-download m10r"></i> <span translate>Backup</span> </h3>
|
||||
<p translate class="large-8 columns text-gray">It's important to backup your wallet so that you can recover it in case of disaster</p>
|
||||
<div class="large-4 columns">
|
||||
<a translate class="button primary expand" ng-click="downloadBackup()">Download File</a>
|
||||
</div>
|
||||
<div class="large-12 columns line-dashed-h m15b"> </div>
|
||||
<div>
|
||||
<div class="oh large-12 columns panel">
|
||||
<h3><i class="fi-minus-circle m10r"></i>
|
||||
<span translate>Delete Wallet</span> </h3>
|
||||
<p translate class="large-8 columns text-gray">If all funds have been removed from your wallet and you do not wish to have the wallet data stored on your computer anymore, you can delete your wallet.</p>
|
||||
<div class="large-4 columns">
|
||||
<a translate class="button warning expand"
|
||||
ng-really-message="'Are you sure to delete this wallet from this computer?'|translate" ng-really-click="deleteWallet()"> Delete</a>
|
||||
</div>
|
||||
<div class="large-12 columns line-dashed-h m15b"></div>
|
||||
<div class="row collapse">
|
||||
<form name="settingsForm" class="large-6 small-12 columns">
|
||||
<fieldset>
|
||||
<legend translate>Wallet Unit</legend>
|
||||
<select class="form-control" ng-model="selectedUnit" ng-options="o.name for o in unitOpts" required>
|
||||
</select>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend translate>Alternative Currency</legend>
|
||||
<select class="form-control" ng-model="selectedAlternative" ng-options="alternative.name for alternative in alternativeOpts" required>
|
||||
</select>
|
||||
</fieldset>
|
||||
|
||||
<div class="text-left">
|
||||
<button translate type="submit" class="large-6 small-12 columns button primary m0 ng-binding" ng-disabled="setupForm.$invalid || loading" disabled="disabled" ng-click="save()">
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="large-12 columns line-dashed-h m15b"></div>
|
||||
<div class="oh large-12 columns panel">
|
||||
<h3><i class="fi-minus-circle m10r"></i> <span translate> Delete Wallet </span></h3>
|
||||
<p translate class="large-8 columns text-gray">If all funds have been removed from your wallet and you do not wish to have the wallet data stored on your computer anymore, you can delete your wallet.</p>
|
||||
<div class="large-4 columns">
|
||||
<a translate class="button warning expand" ng-really-message="'Are you sure to delete this wallet from this computer?'|translate" ng-really-click="deleteWallet()"> Delete</a>
|
||||
</div>
|
||||
</div>
|
||||
<p>
|
||||
<a class="expand small" ng-click="hideAdv=!hideAdv">
|
||||
<span translate ng-hide="!hideAdv">Show</span>
|
||||
<span translate ng-hide="hideAdv">Hide</span>
|
||||
<span translate>advanced options</span>
|
||||
</a>
|
||||
<a class="expand small" ng-click="hideAdv=!hideAdv">
|
||||
<span translate ng-hide="!hideAdv">Show</span>
|
||||
<span translate ng-hide="hideAdv">Hide</span>
|
||||
<span translate>advanced options</span>
|
||||
</a>
|
||||
|
||||
|
||||
<div ng-hide="hideAdv">
|
||||
<div class="oh large-12 columns panel">
|
||||
<h3><i class="fi-minus-circle m10r"></i>
|
||||
<div ng-hide="hideAdv">
|
||||
<div class="oh large-12 columns panel">
|
||||
<h3><i class="fi-minus-circle m10r"></i>
|
||||
<span translate>Master Private Key</span> </h3>
|
||||
<p translate class="large-8 columns text-gray">
|
||||
Your master private key contains the information to sign <b>any</b> transaction on this wallet. Handle with care.
|
||||
</p>
|
||||
<div class="large-4 columns">
|
||||
<a class="button primary expand" ng-click="hidePriv=!hidePriv">
|
||||
<a class="button primary expand" ng-click="hidePriv=!hidePriv">
|
||||
<span translate ng-hide="!hidePriv">Show</span>
|
||||
<span translate ng-hide="hidePriv">Hide</span>
|
||||
</a>
|
||||
</div>
|
||||
<textarea ng-hide="hidePriv" readonly>{{priv}}</textarea>
|
||||
</div>
|
||||
<div class="oh large-12 columns panel">
|
||||
<h3><i class="fi-minus-circle m10r"></i> <span translate>Scan Wallet Addresses</span> </h3>
|
||||
</div>
|
||||
<div class="oh large-12 columns panel">
|
||||
<h3><i class="fi-minus-circle m10r"></i> <span translate>Scan Wallet Addresses</span> </h3>
|
||||
<p translate class="large-8 columns text-gray">
|
||||
This will scan the blockchain looking for addresses derived from your wallet, in case you have funds in addresses not yet generated (e.g.: you restored an old backup). This will also trigger a syncronization of addresses to other connected peers.
|
||||
This will scan the blockchain looking for addresses derived from your wallet, in case you have funds in addresses not yet generated (e.g.: you restored an old backup). This will also trigger a syncronization of addresses to other connected peers.
|
||||
</p>
|
||||
<div class="large-4 columns">
|
||||
<a translate class="button primary expand" ng-click="updateIndexes()">
|
||||
<a translate class="button primary expand" ng-click="updateIndexes()">
|
||||
Scan
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh large-12 columns panel">
|
||||
<h3><i class="fi-minus-circle m10r"></i> <span translate>Purge Pending Transaction Proposals</span> </h3>
|
||||
</div>
|
||||
<div class="oh large-12 columns panel">
|
||||
<h3><i class="fi-minus-circle m10r"></i> <span translate>Purge Pending Transaction Proposals</span> </h3>
|
||||
<p translate class="large-8 columns text-gray">
|
||||
Pending Transactions Proposals will be discarted. This need to be done on <b>ALL<b> peers of a wallet, to prevent the old proposals to be resynced again.
|
||||
Pending Transactions Proposals will be discarted. This need to be done on <b>ALL<b> peers of a wallet, to prevent the old proposals to be resynced again.
|
||||
</p>
|
||||
<div class="large-4 columns">
|
||||
<a translate class="button warning expand" ng-click="purge()">
|
||||
|
|
@ -78,4 +95,3 @@
|
|||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -14,14 +14,14 @@
|
|||
<div class="row collapse">
|
||||
<div class="large-12 columns">
|
||||
<div class="row collapse">
|
||||
<label for="address"><span translate>To address</span>
|
||||
<label for="address"><span translate>To:</span>
|
||||
<small translate ng-hide="!sendForm.address.$pristine || address">required</small>
|
||||
<small translate class="is-valid" ng-show="!sendForm.address.$invalid && address">valid!</small>
|
||||
<small translate class="has-error" ng-show="sendForm.address.$invalid && address">not valid</small>
|
||||
</label>
|
||||
<div class="small-10 columns">
|
||||
<input type="text" id="address" name="address" ng-disabled="loading || !!$root.merchant"
|
||||
placeholder="{{'Send to'|translate}}" ng-model="address" ng-change="onChanged()" valid-address required>
|
||||
placeholder="{{'Bitcoin address'|translate}}" ng-model="address" ng-change="onChanged()" valid-address required>
|
||||
<small class="icon-input" ng-show="!sendForm.address.$invalid && address"><i class="fi-check"></i></small>
|
||||
<small class="icon-input" ng-show="sendForm.address.$invalid && address"><i class="fi-x"></i></small>
|
||||
</div>
|
||||
|
|
@ -77,11 +77,11 @@
|
|||
<a class="small input-note" title="{{'Send all funds'|translate}}"
|
||||
ng-show="$root.availableBalance > 0 && (!$root.merchant || +$root.merchant.total === 0)"
|
||||
ng-click="topAmount(sendForm)">
|
||||
<span translate>Use all funds</span> ({{getAvailableAmount()}} {{$root.unitName}})
|
||||
<span translate>Use all funds</span> ({{getAvailableAmount()}} {{$root.wallet.settings.unitName}})
|
||||
</a>
|
||||
</div>
|
||||
<div class="small-3 columns">
|
||||
<span class="postfix">{{$root.unitName}}</span>
|
||||
<span class="postfix">{{$root.wallet.settings.unitName}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -138,13 +138,13 @@
|
|||
</p>
|
||||
<h6 translate>Total amount for this transaction:</h6>
|
||||
<p class="text-gray" ng-class="{'hidden': sendForm.amount.$invalid || !amount > 0}">
|
||||
<b>{{amount + defaultFee |noFractionNumber}}</b> {{$root.unitName}}
|
||||
<b>{{amount + defaultFee |noFractionNumber}}</b> {{$root.wallet.settings.unitName}}
|
||||
<small ng-if="isRateAvailable">
|
||||
{{ rateService.toFiat((amount + defaultFee) * unitToSatoshi, alternativeIsoCode) | noFractionNumber: 2 }} {{ alternativeIsoCode }}
|
||||
<br>
|
||||
</small>
|
||||
<small>
|
||||
<span translate>Including fee of</span> {{defaultFee|noFractionNumber}} {{$root.unitName}}
|
||||
<span translate>Including fee of</span> {{defaultFee|noFractionNumber}} {{$root.wallet.settings.unitName}}
|
||||
</small>
|
||||
</p>
|
||||
<div ng-show="wallet.isShared()">
|
||||
|
|
|
|||
|
|
@ -10,45 +10,20 @@
|
|||
<form name="settingsForm">
|
||||
<fieldset>
|
||||
<legend translate>Language</legend>
|
||||
<select class="form-control" ng-model="selectedLanguage"
|
||||
ng-options="o.name for o in availableLanguages" required>
|
||||
<select class="form-control" ng-model="selectedLanguage" ng-options="o.name for o in availableLanguages" required>
|
||||
</select>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend translate>Bitcoin Network</legend>
|
||||
<input id="network-name" type="checkbox" ng-model="networkName"
|
||||
ng-true-value="livenet" ng-false-value="testnet" class="form-control" ng-click="changeNetwork()"
|
||||
ng-disabled="forceNetwork"
|
||||
ng-checked="networkName == 'livenet' ? true : false">
|
||||
<label for="network-name">Livenet</label>
|
||||
<div translate ng-show="forceNetwork">
|
||||
Network has been fixed to <strong>{{networkName}}</strong> in this setup. See <a href="https://copay.io">copay.io</a> for options to use Copay on both livenet and testnet.
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend translate>Wallet Unit</legend>
|
||||
<select class="form-control" ng-model="selectedUnit" ng-options="o.name for o in unitOpts" required>
|
||||
</select>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend translate>Alternative Currency</legend>
|
||||
<select class="form-control" ng-model="selectedAlternative" ng-options="alternative.name for alternative in alternativeOpts" required>
|
||||
</select>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend translate>Insight API server</legend>
|
||||
<label for="insight-host">Host</label>
|
||||
<input type="text" ng-model="insightHost" class="form-control" name="insight-host">
|
||||
<label for="insight-port" translate>Port</label>
|
||||
<input type="number" ng-model="insightPort" class="form-control" name="insight-port">
|
||||
<input id="insight-secure" type="checkbox" ng-model="insightSecure" class="form-control" ng-click="changeInsightSSL()">
|
||||
<label for="insight-secure" translate>Use SSL</label>
|
||||
<legend translate>Insight API servers</legend>
|
||||
<label for="insight-livenet">Livenet</label>
|
||||
<input type="text" ng-model="insightLivenet" class="form-control" name="insight-livenet">
|
||||
<label for="insight-testnet">Testnet</label>
|
||||
<input type="text" ng-model="insightTestnet" class="form-control" name="insight-testnet">
|
||||
|
||||
<p translate class="small">
|
||||
Insight API server is open-source software. You can run your own instance, check <a href="http://insight.is" target="_blank">Insight API Homepage</a></p>
|
||||
|
||||
Insight API server is open-source software. You can run your own instances, check <a href="http://insight.is" target="_blank">Insight API Homepage</a>
|
||||
</p>
|
||||
</fieldset>
|
||||
|
||||
<div class="text-right">
|
||||
<a class="back-button text-white m20r" href="#!/">« <span translate>Back</span></a>
|
||||
<button translate type="submit" class="button primary m0 ng-binding" ng-disabled="setupForm.$invalid || loading" disabled="disabled" ng-click="save()">
|
||||
|
|
@ -60,4 +35,3 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@
|
|||
<div class="last-transactions" ng-repeat="tx in txs | paged">
|
||||
<div ng-include="'views/includes/transaction.html'"></div>
|
||||
</div>
|
||||
<p ng-show="txs.length == 0"><span translate>No transactions proposals yet.</span></p>
|
||||
<p ng-show="txs.length == 0"><span translate>No transactions proposals yet.</span>
|
||||
</p>
|
||||
<pagination ng-show="txs.length > txpItemsPerPage" total-items="txs.length" items-per-page="txpItemsPerPage" page="txpCurrentPage" on-select-page="show()" class="pagination-small primary"></pagination>
|
||||
</div>
|
||||
|
||||
|
|
@ -20,10 +21,8 @@
|
|||
|
||||
<div class="large-12">
|
||||
<div class="m10b size-12" ng-hide="wallet.totalCopayers == 1">
|
||||
<a class="text-gray active" ng-click="toogleLast()"
|
||||
ng-disabled="loading" loading="Updating" ng-hide="lastShowed && !loading">[ <span translate>Show</span> ]</a>
|
||||
<a class="text-gray" ng-click="toogleLast()" ng-disabled="loading"
|
||||
loading="Updating" ng-show="lastShowed && !loading">[ <span translate>Hide</span> ]</a>
|
||||
<a class="text-gray active" ng-click="toogleLast()" ng-disabled="loading" loading="Updating" ng-hide="lastShowed && !loading">[ <span translate>Show</span> ]</a>
|
||||
<a class="text-gray" ng-click="toogleLast()" ng-disabled="loading" loading="Updating" ng-show="lastShowed && !loading">[ <span translate>Hide</span> ]</a>
|
||||
</div>
|
||||
|
||||
<div class="btransactions" ng-if="lastShowed">
|
||||
|
|
@ -52,9 +51,9 @@
|
|||
<div class="last-transactions-content">
|
||||
<div class="large-5 medium-5 small-12 columns">
|
||||
<div ng-repeat="vin in btx.vinSimple">
|
||||
<small class="right m5t">{{vin.value| noFractionNumber}} {{$root.unitName}}</small>
|
||||
<small class="right m5t">{{vin.value| noFractionNumber}} {{$root.wallet.settings.unitName}}</small>
|
||||
<p class="ellipsis text-gray size-12">
|
||||
<contact address="{{vin.addr}}" tooltip-popup-delay="500" tooltip tooltip-placement="right"/>
|
||||
<contact address="{{vin.addr}}" tooltip-popup-delay="500" tooltip tooltip-placement="right" />
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -66,20 +65,20 @@
|
|||
</div>
|
||||
<div class="large-6 medium-6 small-12 columns">
|
||||
<div ng-repeat="vout in btx.voutSimple">
|
||||
<small class="right m5t">{{vout.value| noFractionNumber}} {{$root.unitName}}</small>
|
||||
<small class="right m5t">{{vout.value| noFractionNumber}} {{$root.wallet.settings.unitName}}</small>
|
||||
<p class="ellipsis text-gray size-12">
|
||||
<contact address="{{vout.addr}}" tooltip-popup-delay="500" tooltip tooltip-placement="right"/>
|
||||
<contact address="{{vout.addr}}" tooltip-popup-delay="500" tooltip tooltip-placement="right" />
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="last-transactions-footer">
|
||||
<div class="large-6 medium-6 small-6 columns">
|
||||
<p class="size-12"><span translate>Fee</span>: {{btx.fees | noFractionNumber}} {{$root.unitName}}</p>
|
||||
<p class="size-12"><span translate>Confirmations</span>: {{btx.confirmations || 0}}</p>
|
||||
<p class="size-12"><span translate>Fee</span>: {{btx.fees | noFractionNumber}} {{$root.wallet.settings.unitName}}</p>
|
||||
<p class="size-12"><span translate>Confirmations</span>: {{btx.confirmations || 0}}</p>
|
||||
</div>
|
||||
<div class="large-6 medium-6 small-6 columns text-right">
|
||||
<p class="label size-14"><span translate>Total</span>: {{btx.valueOut| noFractionNumber}} {{$root.unitName}}</p>
|
||||
<p class="label size-14"><span translate>Total</span>: {{btx.valueOut| noFractionNumber}} {{$root.wallet.settings.unitName}}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -87,4 +86,3 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue