Adds bitcoin cash basic support (unit convertion, integrations, request specific amount, etc)

This commit is contained in:
Gustavo Maximiliano Cortez 2017-08-24 17:02:49 -03:00
commit 94363704ab
No known key found for this signature in database
GPG key ID: 15EDAD8D9F2EB1AF
24 changed files with 376 additions and 302 deletions

View file

@ -88,9 +88,9 @@ angular.module('copayApp.controllers').controller('addressesController', functio
$scope.lowWarning = resp.warning; $scope.lowWarning = resp.warning;
$scope.lowUtxosNb = resp.lowUtxos.length; $scope.lowUtxosNb = resp.lowUtxos.length;
$scope.allUtxosNb = resp.allUtxos.length; $scope.allUtxosNb = resp.allUtxos.length;
$scope.lowUtxosSum = txFormatService.formatAmountStr(lodash.sum(resp.lowUtxos || 0, 'satoshis')); $scope.lowUtxosSum = txFormatService.formatAmountStr($scope.wallet, lodash.sum(resp.lowUtxos || 0, 'satoshis'));
$scope.allUtxosSum = txFormatService.formatAmountStr(allSum); $scope.allUtxosSum = txFormatService.formatAmountStr($scope.wallet, allSum);
$scope.minFee = txFormatService.formatAmountStr(resp.minFee || 0); $scope.minFee = txFormatService.formatAmountStr($scope.wallet, resp.minFee || 0);
$scope.minFeePer = per.toFixed(2) + '%'; $scope.minFeePer = per.toFixed(2) + '%';

View file

@ -21,6 +21,8 @@ angular.module('copayApp.controllers').controller('amountController', function($
$scope.nextStep = data.stateParams.nextStep; $scope.nextStep = data.stateParams.nextStep;
$scope.currency = data.stateParams.currency; $scope.currency = data.stateParams.currency;
$scope.forceCurrency = data.stateParams.forceCurrency; $scope.forceCurrency = data.stateParams.forceCurrency;
$scope.forceChain = data.stateParams.forceChain || null;
$scope.chain = $scope.forceChain || data.stateParams.chain || 'BTC';
$scope.showMenu = $ionicHistory.backView() && ($ionicHistory.backView().stateName == 'tabs.send' || $scope.showMenu = $ionicHistory.backView() && ($ionicHistory.backView().stateName == 'tabs.send' ||
$ionicHistory.backView().stateName == 'tabs.bitpayCard'); $ionicHistory.backView().stateName == 'tabs.bitpayCard');
@ -63,7 +65,6 @@ angular.module('copayApp.controllers').controller('amountController', function($
}); });
var config = configService.getSync().wallet.settings; var config = configService.getSync().wallet.settings;
$scope.unitName = config.unitName;
if (data.stateParams.currency) { if (data.stateParams.currency) {
$scope.alternativeIsoCode = data.stateParams.currency; $scope.alternativeIsoCode = data.stateParams.currency;
} else { } else {
@ -124,6 +125,12 @@ angular.module('copayApp.controllers').controller('amountController', function($
} }
}; };
$scope.toggleChain = function() {
if ($scope.forceCurrency || $scope.forceChain) return;
$scope.chain = $scope.chain == 'BTC' ? 'BCH' : 'BTC';
};
function checkFontSize() { function checkFontSize() {
if ($scope.amount && $scope.amount.length >= SMALL_FONT_SIZE_LIMIT) $scope.smallFont = true; if ($scope.amount && $scope.amount.length >= SMALL_FONT_SIZE_LIMIT) $scope.smallFont = true;
else $scope.smallFont = false; else $scope.smallFont = false;
@ -227,7 +234,8 @@ angular.module('copayApp.controllers').controller('amountController', function($
$state.transitionTo($scope.nextStep, { $state.transitionTo($scope.nextStep, {
id: _id, id: _id,
amount: $scope.useSendMax ? null : _amount, amount: $scope.useSendMax ? null : _amount,
currency: $scope.showAlternativeAmount ? $scope.alternativeIsoCode : $scope.unitName, currency: $scope.showAlternativeAmount ? $scope.alternativeIsoCode : $scope.chain,
chain: $scope.chain,
useSendMax: $scope.useSendMax useSendMax: $scope.useSendMax
}); });
} else { } else {
@ -239,6 +247,7 @@ angular.module('copayApp.controllers').controller('amountController', function($
toName: $scope.toName, toName: $scope.toName,
toEmail: $scope.toEmail, toEmail: $scope.toEmail,
toColor: $scope.toColor, toColor: $scope.toColor,
chain: $scope.chain,
useSendMax: $scope.useSendMax useSendMax: $scope.useSendMax
}); });
} }

View file

@ -216,7 +216,7 @@ angular.module('copayApp.controllers').controller('buyAmazonController', functio
}); });
var initialize = function(wallet) { var initialize = function(wallet) {
var parsedAmount = txFormatService.parseAmount(amount, currency); var parsedAmount = txFormatService.parseAmount(wallet, amount, currency);
$scope.currencyIsoCode = parsedAmount.currency; $scope.currencyIsoCode = parsedAmount.currency;
$scope.amountUnitStr = parsedAmount.amountUnitStr; $scope.amountUnitStr = parsedAmount.amountUnitStr;
var dataSrc = { var dataSrc = {
@ -260,7 +260,7 @@ angular.module('copayApp.controllers').controller('buyAmazonController', functio
invoiceUrl: invoice.url, invoiceUrl: invoice.url,
invoiceTime: invoice.invoiceTime invoiceTime: invoice.invoiceTime
}; };
$scope.totalAmountStr = txFormatService.formatAmountStr(ctxp.amount); $scope.totalAmountStr = txFormatService.formatAmountStr(wallet, ctxp.amount);
setTotalAmount(parsedAmount.amountSat, invoiceFeeSat, ctxp.fee); setTotalAmount(parsedAmount.amountSat, invoiceFeeSat, ctxp.fee);
}); });
}); });
@ -292,7 +292,8 @@ angular.module('copayApp.controllers').controller('buyAmazonController', functio
$scope.wallets = profileService.getWallets({ $scope.wallets = profileService.getWallets({
onlyComplete: true, onlyComplete: true,
network: $scope.network, network: $scope.network,
hasFunds: true hasFunds: true,
chain: 'BTC'
}); });
if (lodash.isEmpty($scope.wallets)) { if (lodash.isEmpty($scope.wallets)) {
showErrorAndBack(null, gettextCatalog.getString('No wallets available')); showErrorAndBack(null, gettextCatalog.getString('No wallets available'));

View file

@ -33,6 +33,52 @@ angular.module('copayApp.controllers').controller('buyCoinbaseController', funct
} }
}; };
var processPaymentInfo = function() {
ongoingProcess.set('connectingCoinbase', true);
coinbaseService.init(function(err, res) {
if (err) {
ongoingProcess.set('connectingCoinbase', false);
showErrorAndBack(err);
return;
}
var accessToken = res.accessToken;
coinbaseService.buyPrice(accessToken, coinbaseService.getAvailableCurrency(), function(err, b) {
$scope.buyPrice = b.data || null;
});
$scope.paymentMethods = [];
$scope.selectedPaymentMethodId = { value : null };
coinbaseService.getPaymentMethods(accessToken, function(err, p) {
if (err) {
ongoingProcess.set('connectingCoinbase', false);
showErrorAndBack(err);
return;
}
var hasPrimary;
var pm;
for(var i = 0; i < p.data.length; i++) {
pm = p.data[i];
if (pm.allow_buy) {
$scope.paymentMethods.push(pm);
}
if (pm.allow_buy && pm.primary_buy) {
hasPrimary = true;
$scope.selectedPaymentMethodId.value = pm.id;
}
}
if (lodash.isEmpty($scope.paymentMethods)) {
ongoingProcess.set('connectingCoinbase', false);
showErrorAndBack('No payment method available to buy');
return;
}
if (!hasPrimary) $scope.selectedPaymentMethodId.value = $scope.paymentMethods[0].id;
$scope.buyRequest();
});
});
};
$scope.$on("$ionicView.beforeLeave", function(event, data) { $scope.$on("$ionicView.beforeLeave", function(event, data) {
$ionicConfig.views.swipeBackEnabled(true); $ionicConfig.views.swipeBackEnabled(true);
}); });
@ -42,81 +88,22 @@ angular.module('copayApp.controllers').controller('buyCoinbaseController', funct
}); });
$scope.$on("$ionicView.beforeEnter", function(event, data) { $scope.$on("$ionicView.beforeEnter", function(event, data) {
$scope.isFiat = data.stateParams.currency != 'bits' && data.stateParams.currency != 'BTC' ? true : false; $scope.isFiat = data.stateParams.currency != 'BCH' && data.stateParams.currency != 'BTC' ? true : false;
var parsedAmount = txFormatService.parseAmount( amount = data.stateParams.amount;
data.stateParams.amount, currency = data.stateParams.currency;
data.stateParams.currency);
// Buy always in BTC $scope.network = coinbaseService.getNetwork();
amount = (parsedAmount.amountSat / 100000000).toFixed(8); $scope.wallets = profileService.getWallets({
currency = 'BTC'; onlyComplete: true,
network: $scope.network,
$scope.amountUnitStr = parsedAmount.amountUnitStr; chain: 'BTC'
ongoingProcess.set('calculatingFee', true);
coinbaseService.checkEnoughFundsForFee(amount, function(err) {
ongoingProcess.set('calculatingFee', false);
if (err) {
showErrorAndBack(err);
return;
}
$scope.network = coinbaseService.getNetwork();
$scope.wallets = profileService.getWallets({
onlyComplete: true,
network: $scope.network
});
if (lodash.isEmpty($scope.wallets)) {
showErrorAndBack('No wallets available');
return;
}
$scope.wallet = $scope.wallets[0]; // Default first wallet
ongoingProcess.set('connectingCoinbase', true);
coinbaseService.init(function(err, res) {
if (err) {
ongoingProcess.set('connectingCoinbase', false);
showErrorAndBack(err);
return;
}
var accessToken = res.accessToken;
coinbaseService.buyPrice(accessToken, coinbaseService.getAvailableCurrency(), function(err, b) {
$scope.buyPrice = b.data || null;
});
$scope.paymentMethods = [];
$scope.selectedPaymentMethodId = { value : null };
coinbaseService.getPaymentMethods(accessToken, function(err, p) {
if (err) {
ongoingProcess.set('connectingCoinbase', false);
showErrorAndBack(err);
return;
}
var hasPrimary;
var pm;
for(var i = 0; i < p.data.length; i++) {
pm = p.data[i];
if (pm.allow_buy) {
$scope.paymentMethods.push(pm);
}
if (pm.allow_buy && pm.primary_buy) {
hasPrimary = true;
$scope.selectedPaymentMethodId.value = pm.id;
}
}
if (lodash.isEmpty($scope.paymentMethods)) {
ongoingProcess.set('connectingCoinbase', false);
showErrorAndBack('No payment method available to buy');
return;
}
if (!hasPrimary) $scope.selectedPaymentMethodId.value = $scope.paymentMethods[0].id;
$scope.buyRequest();
});
});
}); });
if (lodash.isEmpty($scope.wallets)) {
showErrorAndBack('No wallets available');
return;
}
$scope.onWalletSelect($scope.wallets[0]); // Default first wallet
}); });
$scope.buyRequest = function() { $scope.buyRequest = function() {
@ -248,6 +235,25 @@ angular.module('copayApp.controllers').controller('buyCoinbaseController', funct
$scope.onWalletSelect = function(wallet) { $scope.onWalletSelect = function(wallet) {
$scope.wallet = wallet; $scope.wallet = wallet;
var parsedAmount = txFormatService.parseAmount(
wallet,
amount,
currency);
// Buy always in BTC
amount = (parsedAmount.amountSat / 100000000).toFixed(8);
currency = 'BTC';
$scope.amountUnitStr = parsedAmount.amountUnitStr;
ongoingProcess.set('calculatingFee', true);
coinbaseService.checkEnoughFundsForFee(amount, function(err) {
ongoingProcess.set('calculatingFee', false);
if (err) {
showErrorAndBack(err);
return;
}
processPaymentInfo();
});
}; };
$scope.goBackHome = function() { $scope.goBackHome = function() {

View file

@ -35,36 +35,7 @@ angular.module('copayApp.controllers').controller('buyGlideraController', functi
} }
}; };
$scope.$on("$ionicView.beforeLeave", function(event, data) { var processPaymentInfo = function() {
$ionicConfig.views.swipeBackEnabled(true);
});
$scope.$on("$ionicView.enter", function(event, data) {
$ionicConfig.views.swipeBackEnabled(false);
});
$scope.$on("$ionicView.beforeEnter", function(event, data) {
$scope.isFiat = data.stateParams.currency != 'bits' && data.stateParams.currency != 'BTC' ? true : false;
var parsedAmount = txFormatService.parseAmount(
data.stateParams.amount,
data.stateParams.currency);
amount = parsedAmount.amount;
currency = parsedAmount.currency;
$scope.amountUnitStr = parsedAmount.amountUnitStr;
$scope.network = glideraService.getNetwork();
$scope.wallets = profileService.getWallets({
onlyComplete: true,
network: $scope.network
});
if (lodash.isEmpty($scope.wallets)) {
showErrorAndBack('No wallets available');
return;
}
$scope.wallet = $scope.wallets[0]; // Default first wallet
ongoingProcess.set('connectingGlidera', true); ongoingProcess.set('connectingGlidera', true);
glideraService.init(function(err, data) { glideraService.init(function(err, data) {
if (err) { if (err) {
@ -88,6 +59,33 @@ angular.module('copayApp.controllers').controller('buyGlideraController', functi
$scope.buyInfo = buy; $scope.buyInfo = buy;
}); });
}); });
};
$scope.$on("$ionicView.beforeLeave", function(event, data) {
$ionicConfig.views.swipeBackEnabled(true);
});
$scope.$on("$ionicView.enter", function(event, data) {
$ionicConfig.views.swipeBackEnabled(false);
});
$scope.$on("$ionicView.beforeEnter", function(event, data) {
$scope.isFiat = data.stateParams.currency != 'BCH' && data.stateParams.currency != 'BTC' ? true : false;
amount = data.stateParams.amount;
currency = data.stateParams.currency;
$scope.network = glideraService.getNetwork();
$scope.wallets = profileService.getWallets({
onlyComplete: true,
network: $scope.network,
chain: 'BTC'
});
if (lodash.isEmpty($scope.wallets)) {
showErrorAndBack('No wallets available');
return;
}
$scope.onWalletSelect($scope.wallets[0]); // Default first wallet
}); });
var ask2FaCode = function(mode, cb) { var ask2FaCode = function(mode, cb) {
@ -105,7 +103,7 @@ angular.module('copayApp.controllers').controller('buyGlideraController', functi
popupService.showPrompt(title, message, null, function(twoFaCode) { popupService.showPrompt(title, message, null, function(twoFaCode) {
if (typeof twoFaCode == 'undefined') return cb(); if (typeof twoFaCode == 'undefined') return cb();
return cb(twoFaCode); return cb(twoFaCode);
}); });
} else { } else {
return cb(); return cb();
} }
@ -116,7 +114,7 @@ angular.module('copayApp.controllers').controller('buyGlideraController', functi
var okText = 'Confirm'; var okText = 'Confirm';
var cancelText = 'Cancel'; var cancelText = 'Cancel';
popupService.showConfirm(null, message, okText, cancelText, function(ok) { popupService.showConfirm(null, message, okText, cancelText, function(ok) {
if (!ok) return; if (!ok) return;
ongoingProcess.set('buyingBitcoin', true, statusChangeHandler); ongoingProcess.set('buyingBitcoin', true, statusChangeHandler);
glideraService.get2faCode($scope.token, function(err, tfa) { glideraService.get2faCode($scope.token, function(err, tfa) {
if (err) { if (err) {
@ -162,6 +160,15 @@ angular.module('copayApp.controllers').controller('buyGlideraController', functi
$scope.onWalletSelect = function(wallet) { $scope.onWalletSelect = function(wallet) {
$scope.wallet = wallet; $scope.wallet = wallet;
var parsedAmount = txFormatService.parseAmount(
wallet,
amount,
currency);
amount = parsedAmount.amount;
currency = parsedAmount.currency;
$scope.amountUnitStr = parsedAmount.amountUnitStr;
processPaymentInfo();
}; };
$scope.goBackHome = function() { $scope.goBackHome = function() {

View file

@ -214,7 +214,7 @@ angular.module('copayApp.controllers').controller('buyMercadoLibreController', f
}); });
var initialize = function(wallet) { var initialize = function(wallet) {
var parsedAmount = txFormatService.parseAmount(amount, currency); var parsedAmount = txFormatService.parseAmount(wallet, amount, currency);
$scope.currencyIsoCode = parsedAmount.currency; $scope.currencyIsoCode = parsedAmount.currency;
$scope.amountUnitStr = parsedAmount.amountUnitStr; $scope.amountUnitStr = parsedAmount.amountUnitStr;
var dataSrc = { var dataSrc = {
@ -258,7 +258,7 @@ angular.module('copayApp.controllers').controller('buyMercadoLibreController', f
invoiceUrl: invoice.url, invoiceUrl: invoice.url,
invoiceTime: invoice.invoiceTime invoiceTime: invoice.invoiceTime
}; };
$scope.totalAmountStr = txFormatService.formatAmountStr(ctxp.amount); $scope.totalAmountStr = txFormatService.formatAmountStr(wallet, ctxp.amount);
setTotalAmount(parsedAmount.amountSat, invoiceFeeSat, ctxp.fee); setTotalAmount(parsedAmount.amountSat, invoiceFeeSat, ctxp.fee);
}); });
}); });
@ -284,7 +284,8 @@ angular.module('copayApp.controllers').controller('buyMercadoLibreController', f
$scope.network = mercadoLibreService.getNetwork(); $scope.network = mercadoLibreService.getNetwork();
$scope.wallets = profileService.getWallets({ $scope.wallets = profileService.getWallets({
onlyComplete: true, onlyComplete: true,
network: $scope.network network: $scope.network,
chain: 'BTC'
}); });
if (lodash.isEmpty($scope.wallets)) { if (lodash.isEmpty($scope.wallets)) {
showErrorAndBack(null, gettextCatalog.getString('No wallets available')); showErrorAndBack(null, gettextCatalog.getString('No wallets available'));

View file

@ -69,14 +69,15 @@ angular.module('copayApp.controllers').controller('confirmController', function(
$scope.$on("$ionicView.beforeEnter", function(event, data) { $scope.$on("$ionicView.beforeEnter", function(event, data) {
function setWalletSelector(network, minAmount, cb) { function setWalletSelector(chain, network, minAmount, cb) {
// no min amount? (sendMax) => look for no empty wallets // no min amount? (sendMax) => look for no empty wallets
minAmount = minAmount || 1; minAmount = minAmount || 1;
$scope.wallets = profileService.getWallets({ $scope.wallets = profileService.getWallets({
onlyComplete: true, onlyComplete: true,
network: network network: network,
chain: chain
}); });
if (!$scope.wallets || !$scope.wallets.length) { if (!$scope.wallets || !$scope.wallets.length) {
@ -137,6 +138,7 @@ angular.module('copayApp.controllers').controller('confirmController', function(
toEmail: data.stateParams.toEmail, toEmail: data.stateParams.toEmail,
toColor: data.stateParams.toColor, toColor: data.stateParams.toColor,
network: (new bitcore.Address(data.stateParams.toAddress)).network.name, network: (new bitcore.Address(data.stateParams.toAddress)).network.name,
chain: data.stateParams.chain || 'BTC',
txp: {}, txp: {},
}; };
@ -146,23 +148,21 @@ angular.module('copayApp.controllers').controller('confirmController', function(
$scope.isWindowsPhoneApp = isWindowsPhoneApp; $scope.isWindowsPhoneApp = isWindowsPhoneApp;
$scope.showAddress = false; $scope.showAddress = false;
updateTx(tx, null, {}, function() {
$scope.walletSelectorTitle = gettextCatalog.getString('Send from'); $scope.walletSelectorTitle = gettextCatalog.getString('Send from');
setWalletSelector(tx.network, tx.toAmount, function(err) { setWalletSelector(tx.chain, tx.network, tx.toAmount, function(err) {
if (err) { if (err) {
return exitWithError('Could not update wallets'); return exitWithError('Could not update wallets');
} }
if ($scope.wallets.length > 1) {
$scope.showWalletSelector();
} else if ($scope.wallets.length) {
setWallet($scope.wallets[0], tx);
}
});
if ($scope.wallets.length > 1) {
$scope.showWalletSelector();
} else if ($scope.wallets.length) {
setWallet($scope.wallets[0], tx);
}
}); });
}); });
@ -238,7 +238,7 @@ angular.module('copayApp.controllers').controller('confirmController', function(
if (!tx.toAmount) return; if (!tx.toAmount) return;
// Amount // Amount
tx.amountStr = txFormatService.formatAmountStr(tx.toAmount); tx.amountStr = txFormatService.formatAmountStr(wallet, tx.toAmount);
tx.amountValueStr = tx.amountStr.split(' ')[0]; tx.amountValueStr = tx.amountStr.split(' ')[0];
tx.amountUnitStr = tx.amountStr.split(' ')[1]; tx.amountUnitStr = tx.amountStr.split(' ')[1];
txFormatService.formatAlternativeStr(tx.toAmount, function(v) { txFormatService.formatAlternativeStr(tx.toAmount, function(v) {
@ -280,7 +280,7 @@ angular.module('copayApp.controllers').controller('confirmController', function(
tx.sendMaxInfo = sendMaxInfo; tx.sendMaxInfo = sendMaxInfo;
tx.toAmount = tx.sendMaxInfo.amount; tx.toAmount = tx.sendMaxInfo.amount;
updateAmount(); updateAmount();
showSendMaxWarning(sendMaxInfo); showSendMaxWarning(wallet, sendMaxInfo);
} }
// txp already generated for this wallet? // txp already generated for this wallet?
@ -292,7 +292,7 @@ angular.module('copayApp.controllers').controller('confirmController', function(
getTxp(lodash.clone(tx), wallet, opts.dryRun, function(err, txp) { getTxp(lodash.clone(tx), wallet, opts.dryRun, function(err, txp) {
if (err) return cb(err); if (err) return cb(err);
txp.feeStr = txFormatService.formatAmountStr(txp.fee); txp.feeStr = txFormatService.formatAmountStr(wallet, txp.fee);
txFormatService.formatAlternativeStr(txp.fee, function(v) { txFormatService.formatAlternativeStr(txp.fee, function(v) {
txp.alternativeFeeStr = v; txp.alternativeFeeStr = v;
}); });
@ -337,26 +337,26 @@ angular.module('copayApp.controllers').controller('confirmController', function(
}; };
function showSendMaxWarning(sendMaxInfo) { function showSendMaxWarning(wallet, sendMaxInfo) {
function verifyExcludedUtxos() { function verifyExcludedUtxos() {
var warningMsg = []; var warningMsg = [];
if (sendMaxInfo.utxosBelowFee > 0) { if (sendMaxInfo.utxosBelowFee > 0) {
warningMsg.push(gettextCatalog.getString("A total of {{amountBelowFeeStr}} were excluded. These funds come from UTXOs smaller than the network fee provided.", { warningMsg.push(gettextCatalog.getString("A total of {{amountBelowFeeStr}} were excluded. These funds come from UTXOs smaller than the network fee provided.", {
amountBelowFeeStr: txFormatService.formatAmountStr(sendMaxInfo.amountBelowFee) amountBelowFeeStr: txFormatService.formatAmountStr(wallet, sendMaxInfo.amountBelowFee)
})); }));
} }
if (sendMaxInfo.utxosAboveMaxSize > 0) { if (sendMaxInfo.utxosAboveMaxSize > 0) {
warningMsg.push(gettextCatalog.getString("A total of {{amountAboveMaxSizeStr}} were excluded. The maximum size allowed for a transaction was exceeded.", { warningMsg.push(gettextCatalog.getString("A total of {{amountAboveMaxSizeStr}} were excluded. The maximum size allowed for a transaction was exceeded.", {
amountAboveMaxSizeStr: txFormatService.formatAmountStr(sendMaxInfo.amountAboveMaxSize) amountAboveMaxSizeStr: txFormatService.formatAmountStr(wallet, sendMaxInfo.amountAboveMaxSize)
})); }));
} }
return warningMsg.join('\n'); return warningMsg.join('\n');
}; };
var msg = gettextCatalog.getString("{{fee}} will be deducted for bitcoin networking fees.", { var msg = gettextCatalog.getString("{{fee}} will be deducted for bitcoin networking fees.", {
fee: txFormatService.formatAmountStr(sendMaxInfo.fee) fee: txFormatService.formatAmountStr(wallet, sendMaxInfo.fee)
}); });
var warningMsg = verifyExcludedUtxos(); var warningMsg = verifyExcludedUtxos();

View file

@ -15,7 +15,7 @@ angular.module('copayApp.controllers').controller('customAmountController', func
showErrorAndBack('Error', 'No wallet selected'); showErrorAndBack('Error', 'No wallet selected');
return; return;
} }
$scope.showShareButton = platformInfo.isCordova ? (platformInfo.isIOS ? 'iOS' : 'Android') : null; $scope.showShareButton = platformInfo.isCordova ? (platformInfo.isIOS ? 'iOS' : 'Android') : null;
$scope.wallet = profileService.getWallet(walletId); $scope.wallet = profileService.getWallet(walletId);
@ -25,11 +25,13 @@ angular.module('copayApp.controllers').controller('customAmountController', func
showErrorAndBack('Error', 'Could not get the address'); showErrorAndBack('Error', 'Could not get the address');
return; return;
} }
$scope.address = addr; $scope.address = addr;
$scope.chain = (data.stateParams.chain).toLowerCase();
var parsedAmount = txFormatService.parseAmount( var parsedAmount = txFormatService.parseAmount(
data.stateParams.amount, $scope.wallet,
data.stateParams.amount,
data.stateParams.currency); data.stateParams.currency);
// Amount in USD or BTC // Amount in USD or BTC
@ -37,16 +39,16 @@ angular.module('copayApp.controllers').controller('customAmountController', func
var currency = parsedAmount.currency; var currency = parsedAmount.currency;
$scope.amountUnitStr = parsedAmount.amountUnitStr; $scope.amountUnitStr = parsedAmount.amountUnitStr;
if (currency != 'BTC') { if (currency != 'BTC' && currency != 'BCH') {
// Convert to BTC // Convert to BTC or BCH
var config = configService.getSync().wallet.settings; var config = configService.getSync().wallet.settings;
var amountUnit = txFormatService.satToUnit(parsedAmount.amountSat); var amountUnit = txFormatService.satToUnit(parsedAmount.amountSat);
var btcParsedAmount = txFormatService.parseAmount(amountUnit, config.unitName); var btcParsedAmount = txFormatService.parseAmount($scope.wallet, amountUnit, $scope.wallet.chain);
$scope.amountBtc = btcParsedAmount.amount; $scope.amountBtc = btcParsedAmount.amount;
$scope.altAmountStr = btcParsedAmount.amountUnitStr; $scope.altAmountStr = btcParsedAmount.amountUnitStr;
} else { } else {
$scope.amountBtc = amount; // BTC $scope.amountBtc = amount; // BTC or BCH
$scope.altAmountStr = txFormatService.formatAlternativeStr(parsedAmount.amountSat); $scope.altAmountStr = txFormatService.formatAlternativeStr(parsedAmount.amountSat);
} }
}); });
@ -66,7 +68,7 @@ angular.module('copayApp.controllers').controller('customAmountController', func
} }
$scope.copyToClipboard = function() { $scope.copyToClipboard = function() {
return 'bitcoin:' + $scope.address + '?amount=' + $scope.amountBtc; return 'bitcoin:' + $scope.address + '?amount=' + $scope.amountBtc + '&chain=' + $scope.chain;
}; };
}); });

View file

@ -219,7 +219,7 @@ angular.module('copayApp.controllers').controller('txpDetailsController', functi
copayerId: $scope.wallet.credentials.copayerId copayerId: $scope.wallet.credentials.copayerId
}); });
$scope.tx = txFormatService.processTx(tx); $scope.tx = txFormatService.processTx($scope.wallet, tx);
if (!action && tx.status == 'pending') if (!action && tx.status == 'pending')
$scope.tx.pendingForUs = true; $scope.tx.pendingForUs = true;

View file

@ -34,124 +34,7 @@ angular.module('copayApp.controllers').controller('sellCoinbaseController', func
}, onSendStatusChange); }, onSendStatusChange);
}; };
var checkTransaction = lodash.throttle(function(count, txp) { var processPaymentInfo = function() {
$log.warn('Check if transaction has been received by Coinbase. Try ' + count + '/5');
// TX amount in BTC
var satToBtc = 1 / 100000000;
var amountBTC = (txp.amount * satToBtc).toFixed(8);
coinbaseService.init(function(err, res) {
if (err) {
$log.error(err);
checkTransaction(count, txp);
return;
}
var accessToken = res.accessToken;
var accountId = res.accountId;
var sellPrice = null;
coinbaseService.sellPrice(accessToken, coinbaseService.getAvailableCurrency(), function(err, sell) {
if (err) {
$log.debug(err);
checkTransaction(count, txp);
return;
}
sellPrice = sell.data;
coinbaseService.getTransactions(accessToken, accountId, function(err, ctxs) {
if (err) {
$log.debug(err);
checkTransaction(count, txp);
return;
}
var coinbaseTransactions = ctxs.data;
var txFound = false;
var ctx;
for(var i = 0; i < coinbaseTransactions.length; i++) {
ctx = coinbaseTransactions[i];
if (ctx.type == 'send' && ctx.from && ctx.amount.amount == amountBTC ) {
$log.warn('Transaction found!', ctx);
txFound = true;
$log.debug('Saving transaction to process later...');
ctx['payment_method'] = $scope.selectedPaymentMethodId.value;
ctx['status'] = 'pending'; // Forcing "pending" status to process later
ctx['price_sensitivity'] = $scope.selectedPriceSensitivity.data;
ctx['sell_price_amount'] = sellPrice ? sellPrice.amount : '';
ctx['sell_price_currency'] = sellPrice ? sellPrice.currency : 'USD';
ctx['description'] = appConfigService.nameCase + ' Wallet: ' + $scope.wallet.name;
coinbaseService.savePendingTransaction(ctx, null, function(err) {
ongoingProcess.set('sellingBitcoin', false, statusChangeHandler);
if (err) $log.debug(err);
});
return;
}
}
if (!txFound) {
// Transaction sent, but could not be verified by Coinbase.com
$log.warn('Transaction not found in Coinbase.');
if (count < 5) {
checkTransaction(count + 1, txp);
} else {
ongoingProcess.set('sellingBitcoin', false, statusChangeHandler);
showError('No transaction found');
return;
}
}
});
});
});
}, 8000, {
'leading': true
});
var statusChangeHandler = function (processName, showName, isOn) {
$log.debug('statusChangeHandler: ', processName, showName, isOn);
if ( processName == 'sellingBitcoin' && !isOn) {
$scope.sendStatus = 'success';
$timeout(function() {
$scope.$digest();
}, 100);
} else if (showName) {
$scope.sendStatus = showName;
}
};
$scope.$on("$ionicView.beforeLeave", function(event, data) {
$ionicConfig.views.swipeBackEnabled(true);
});
$scope.$on("$ionicView.enter", function(event, data) {
$ionicConfig.views.swipeBackEnabled(false);
});
$scope.$on("$ionicView.beforeEnter", function(event, data) {
$scope.isFiat = data.stateParams.currency != 'bits' && data.stateParams.currency != 'BTC' ? true : false;
var parsedAmount = txFormatService.parseAmount(
data.stateParams.amount,
data.stateParams.currency);
amount = parsedAmount.amount;
currency = parsedAmount.currency;
$scope.amountUnitStr = parsedAmount.amountUnitStr;
$scope.priceSensitivity = coinbaseService.priceSensitivity;
$scope.selectedPriceSensitivity = { data: coinbaseService.selectedPriceSensitivity };
$scope.network = coinbaseService.getNetwork();
$scope.wallets = profileService.getWallets({
m: 1, // Only 1-signature wallet
onlyComplete: true,
network: $scope.network,
hasFunds: true,
minAmount: parsedAmount.amountSat
});
if (lodash.isEmpty($scope.wallets)) {
showErrorAndBack('Insufficient funds');
return;
}
$scope.wallet = $scope.wallets[0]; // Default first wallet
ongoingProcess.set('connectingCoinbase', true); ongoingProcess.set('connectingCoinbase', true);
coinbaseService.init(function(err, res) { coinbaseService.init(function(err, res) {
if (err) { if (err) {
@ -193,7 +76,121 @@ angular.module('copayApp.controllers').controller('sellCoinbaseController', func
if (!hasPrimary) $scope.selectedPaymentMethodId.value = $scope.paymentMethods[0].id; if (!hasPrimary) $scope.selectedPaymentMethodId.value = $scope.paymentMethods[0].id;
$scope.sellRequest(); $scope.sellRequest();
}); });
}); });
};
var checkTransaction = lodash.throttle(function(count, txp) {
$log.warn('Check if transaction has been received by Coinbase. Try ' + count + '/5');
// TX amount in BTC
var satToBtc = 1 / 100000000;
var amountBTC = (txp.amount * satToBtc).toFixed(8);
coinbaseService.init(function(err, res) {
if (err) {
$log.error(err);
checkTransaction(count, txp);
return;
}
var accessToken = res.accessToken;
var accountId = res.accountId;
var sellPrice = null;
coinbaseService.sellPrice(accessToken, coinbaseService.getAvailableCurrency(), function(err, sell) {
if (err) {
$log.debug(err);
checkTransaction(count, txp);
return;
}
sellPrice = sell.data;
coinbaseService.getTransactions(accessToken, accountId, function(err, ctxs) {
if (err) {
$log.debug(err);
checkTransaction(count, txp);
return;
}
var coinbaseTransactions = ctxs.data;
var txFound = false;
var ctx;
for(var i = 0; i < coinbaseTransactions.length; i++) {
ctx = coinbaseTransactions[i];
if (ctx.type == 'send' && ctx.from && ctx.amount.amount == amountBTC ) {
$log.warn('Transaction found!', ctx);
txFound = true;
$log.debug('Saving transaction to process later...');
ctx['payment_method'] = $scope.selectedPaymentMethodId.value;
ctx['status'] = 'pending'; // Forcing "pending" status to process later
ctx['price_sensitivity'] = $scope.selectedPriceSensitivity.data;
ctx['sell_price_amount'] = sellPrice ? sellPrice.amount : '';
ctx['sell_price_currency'] = sellPrice ? sellPrice.currency : 'USD';
ctx['description'] = appConfigService.nameCase + ' Wallet: ' + $scope.wallet.name;
coinbaseService.savePendingTransaction(ctx, null, function(err) {
ongoingProcess.set('sellingBitcoin', false, statusChangeHandler);
if (err) $log.debug(err);
});
return;
}
}
if (!txFound) {
// Transaction sent, but could not be verified by Coinbase.com
$log.warn('Transaction not found in Coinbase.');
if (count < 5) {
checkTransaction(count + 1, txp);
} else {
ongoingProcess.set('sellingBitcoin', false, statusChangeHandler);
showError('No transaction found');
return;
}
}
});
});
});
}, 8000, {
'leading': true
});
var statusChangeHandler = function (processName, showName, isOn) {
$log.debug('statusChangeHandler: ', processName, showName, isOn);
if ( processName == 'sellingBitcoin' && !isOn) {
$scope.sendStatus = 'success';
$timeout(function() {
$scope.$digest();
}, 100);
} else if (showName) {
$scope.sendStatus = showName;
}
};
$scope.$on("$ionicView.beforeLeave", function(event, data) {
$ionicConfig.views.swipeBackEnabled(true);
});
$scope.$on("$ionicView.enter", function(event, data) {
$ionicConfig.views.swipeBackEnabled(false);
});
$scope.$on("$ionicView.beforeEnter", function(event, data) {
$scope.isFiat = data.stateParams.currency != 'BCH' && data.stateParams.currency != 'BTC' ? true : false;
amount = data.stateParams.amount;
currency = data.stateParams.currency;
$scope.priceSensitivity = coinbaseService.priceSensitivity;
$scope.selectedPriceSensitivity = { data: coinbaseService.selectedPriceSensitivity };
$scope.network = coinbaseService.getNetwork();
$scope.wallets = profileService.getWallets({
m: 1, // Only 1-signature wallet
onlyComplete: true,
network: $scope.network,
hasFunds: true,
chain: 'BTC'
});
if (lodash.isEmpty($scope.wallets)) {
showErrorAndBack('Insufficient funds');
return;
}
$scope.onWalletSelect($scope.wallets[0]); // Default first wallet
}); });
$scope.sellRequest = function() { $scope.sellRequest = function() {
@ -236,7 +233,7 @@ angular.module('copayApp.controllers').controller('sellCoinbaseController', func
var cancelText = 'Cancel'; var cancelText = 'Cancel';
popupService.showConfirm(null, message, okText, cancelText, function(ok) { popupService.showConfirm(null, message, okText, cancelText, function(ok) {
if (!ok) return; if (!ok) return;
ongoingProcess.set('sellingBitcoin', true, statusChangeHandler); ongoingProcess.set('sellingBitcoin', true, statusChangeHandler);
coinbaseService.init(function(err, res) { coinbaseService.init(function(err, res) {
if (err) { if (err) {
@ -294,8 +291,8 @@ angular.module('copayApp.controllers').controller('sellCoinbaseController', func
checkTransaction(1, txSent); checkTransaction(1, txSent);
}); });
}); });
}); });
}); });
}); });
}; };
@ -306,6 +303,15 @@ angular.module('copayApp.controllers').controller('sellCoinbaseController', func
$scope.onWalletSelect = function(wallet) { $scope.onWalletSelect = function(wallet) {
$scope.wallet = wallet; $scope.wallet = wallet;
var parsedAmount = txFormatService.parseAmount(
wallet,
amount,
currency);
amount = parsedAmount.amount;
currency = parsedAmount.currency;
$scope.amountUnitStr = parsedAmount.amountUnitStr;
processPaymentInfo();
}; };
$scope.goBackHome = function() { $scope.goBackHome = function() {

View file

@ -35,39 +35,7 @@ angular.module('copayApp.controllers').controller('sellGlideraController', funct
} }
}; };
$scope.$on("$ionicView.beforeLeave", function(event, data) { var processPaymentInfo = function() {
$ionicConfig.views.swipeBackEnabled(true);
});
$scope.$on("$ionicView.enter", function(event, data) {
$ionicConfig.views.swipeBackEnabled(false);
});
$scope.$on("$ionicView.beforeEnter", function(event, data) {
$scope.isFiat = data.stateParams.currency != 'bits' && data.stateParams.currency != 'BTC' ? true : false;
var parsedAmount = txFormatService.parseAmount(
data.stateParams.amount,
data.stateParams.currency);
amount = parsedAmount.amount;
currency = parsedAmount.currency;
$scope.amountUnitStr = parsedAmount.amountUnitStr;
$scope.network = glideraService.getNetwork();
$scope.wallets = profileService.getWallets({
m: 1, // Only 1-signature wallet
onlyComplete: true,
network: $scope.network,
hasFunds: true,
minAmount: parsedAmount.amountSat
});
if (lodash.isEmpty($scope.wallets)) {
showErrorAndBack('Insufficient funds');
return;
}
$scope.wallet = $scope.wallets[0]; // Default first wallet
ongoingProcess.set('connectingGlidera', true); ongoingProcess.set('connectingGlidera', true);
glideraService.init(function(err, data) { glideraService.init(function(err, data) {
if (err) { if (err) {
@ -91,6 +59,35 @@ angular.module('copayApp.controllers').controller('sellGlideraController', funct
$scope.sellInfo = sell; $scope.sellInfo = sell;
}); });
}); });
};
$scope.$on("$ionicView.beforeLeave", function(event, data) {
$ionicConfig.views.swipeBackEnabled(true);
});
$scope.$on("$ionicView.enter", function(event, data) {
$ionicConfig.views.swipeBackEnabled(false);
});
$scope.$on("$ionicView.beforeEnter", function(event, data) {
$scope.isFiat = data.stateParams.currency != 'BCH' && data.stateParams.currency != 'BTC' ? true : false;
amount = data.stateParams.amount;
currency = data.stateParams.currency;
$scope.network = glideraService.getNetwork();
$scope.wallets = profileService.getWallets({
m: 1, // Only 1-signature wallet
onlyComplete: true,
network: $scope.network,
hasFunds: true,
chain: 'BTC'
});
if (lodash.isEmpty($scope.wallets)) {
showErrorAndBack('Insufficient funds');
return;
}
$scope.onWalletSelect($scope.wallets[0]); // Default first wallet
}); });
var ask2FaCode = function(mode, cb) { var ask2FaCode = function(mode, cb) {
@ -108,7 +105,7 @@ angular.module('copayApp.controllers').controller('sellGlideraController', funct
popupService.showPrompt(title, message, null, function(twoFaCode) { popupService.showPrompt(title, message, null, function(twoFaCode) {
if (typeof twoFaCode == 'undefined') return cb(); if (typeof twoFaCode == 'undefined') return cb();
return cb(twoFaCode); return cb(twoFaCode);
}); });
} else { } else {
return cb(); return cb();
} }
@ -119,7 +116,7 @@ angular.module('copayApp.controllers').controller('sellGlideraController', funct
var okText = 'Confirm'; var okText = 'Confirm';
var cancelText = 'Cancel'; var cancelText = 'Cancel';
popupService.showConfirm(null, message, okText, cancelText, function(ok) { popupService.showConfirm(null, message, okText, cancelText, function(ok) {
if (!ok) return; if (!ok) return;
ongoingProcess.set('sellingBitcoin', true, statusChangeHandler); ongoingProcess.set('sellingBitcoin', true, statusChangeHandler);
glideraService.get2faCode($scope.token, function(err, tfa) { glideraService.get2faCode($scope.token, function(err, tfa) {
if (err) { if (err) {
@ -231,6 +228,15 @@ angular.module('copayApp.controllers').controller('sellGlideraController', funct
$scope.onWalletSelect = function(wallet) { $scope.onWalletSelect = function(wallet) {
$scope.wallet = wallet; $scope.wallet = wallet;
var parsedAmount = txFormatService.parseAmount(
wallet,
amount,
currency);
amount = parsedAmount.amount;
currency = parsedAmount.currency;
$scope.amountUnitStr = parsedAmount.amountUnitStr;
processPaymentInfo();
}; };
$scope.goBackHome = function() { $scope.goBackHome = function() {

View file

@ -8,7 +8,8 @@ angular.module('copayApp.controllers').controller('tabReceiveController', functi
$scope.requestSpecificAmount = function() { $scope.requestSpecificAmount = function() {
$state.go('tabs.paymentRequest.amount', { $state.go('tabs.paymentRequest.amount', {
id: $scope.wallet.credentials.walletId id: $scope.wallet.credentials.walletId,
forceChain: $scope.wallet.chain
}); });
}; };

View file

@ -218,7 +218,7 @@ angular.module('copayApp.controllers').controller('topUpController', function($s
// Save TX in memory // Save TX in memory
createdTx = ctxp; createdTx = ctxp;
$scope.totalAmountStr = txFormatService.formatAmountStr(ctxp.amount); $scope.totalAmountStr = txFormatService.formatAmountStr(wallet, ctxp.amount);
setTotalAmount(parsedAmount.amountSat, invoiceFeeSat, ctxp.fee); setTotalAmount(parsedAmount.amountSat, invoiceFeeSat, ctxp.fee);
@ -256,7 +256,8 @@ angular.module('copayApp.controllers').controller('topUpController', function($s
$scope.wallets = profileService.getWallets({ $scope.wallets = profileService.getWallets({
onlyComplete: true, onlyComplete: true,
network: bitpayService.getEnvironment().network, network: bitpayService.getEnvironment().network,
hasFunds: true hasFunds: true,
chain: 'BTC'
}); });
if (lodash.isEmpty($scope.wallets)) { if (lodash.isEmpty($scope.wallets)) {
@ -319,7 +320,7 @@ angular.module('copayApp.controllers').controller('topUpController', function($s
}); });
return; return;
} }
var parsedAmount = txFormatService.parseAmount(a, c); var parsedAmount = txFormatService.parseAmount(wallet, a, c);
initializeTopUp(wallet, parsedAmount); initializeTopUp(wallet, parsedAmount);
}); });
}; };

View file

@ -112,7 +112,7 @@ angular.module('copayApp.controllers').controller('txDetailsController', functio
return popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Transaction not available at this time')); return popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Transaction not available at this time'));
} }
$scope.btx = txFormatService.processTx(tx); $scope.btx = txFormatService.processTx($scope.wallet, tx);
txFormatService.formatAlternativeStr(tx.fees, function(v) { txFormatService.formatAlternativeStr(tx.fees, function(v) {
$scope.btx.feeFiatStr = v; $scope.btx.feeFiatStr = v;
$scope.btx.feeRateStr = ($scope.btx.fees / ($scope.btx.amount + $scope.btx.fees) * 100).toFixed(2) + '%'; $scope.btx.feeRateStr = ($scope.btx.fees / ($scope.btx.amount + $scope.btx.fees) * 100).toFixed(2) + '%';

View file

@ -27,12 +27,10 @@ angular.module('copayApp.filters', [])
} }
}) })
.filter('formatFiatAmount', ['$filter', '$locale', 'configService', .filter('formatFiatAmount', ['$filter', '$locale', 'configService',
function(filter, locale, configService) { function(filter, locale) {
var numberFilter = filter('number'); var numberFilter = filter('number');
var formats = locale.NUMBER_FORMATS; var formats = locale.NUMBER_FORMATS;
var config = configService.getSync().wallet.settings;
return function(amount) { return function(amount) {
if (!config) return amount;
var fractionSize = 2; var fractionSize = 2;
var value = numberFilter(amount, fractionSize); var value = numberFilter(amount, fractionSize);

View file

@ -287,7 +287,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
*/ */
.state('tabs.send.amount', { .state('tabs.send.amount', {
url: '/amount/:recipientType/:toAddress/:toName/:toEmail/:toColor', url: '/amount/:recipientType/:toAddress/:toName/:toEmail/:toColor/:chain',
views: { views: {
'tab-send@tabs': { 'tab-send@tabs': {
controller: 'amountController', controller: 'amountController',
@ -296,7 +296,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
} }
}) })
.state('tabs.send.confirm', { .state('tabs.send.confirm', {
url: '/confirm/:recipientType/:toAddress/:toName/:toAmount/:toEmail/:toColor/:description/:useSendMax', url: '/confirm/:recipientType/:toAddress/:toName/:toAmount/:toEmail/:toColor/:description/:chain/:useSendMax',
views: { views: {
'tab-send@tabs': { 'tab-send@tabs': {
controller: 'confirmController', controller: 'confirmController',
@ -681,7 +681,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
}) })
.state('tabs.paymentRequest.amount', { .state('tabs.paymentRequest.amount', {
url: '/amount', url: '/amount/:forceChain',
views: { views: {
'tab-receive@tabs': { 'tab-receive@tabs': {
controller: 'amountController', controller: 'amountController',
@ -690,7 +690,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
} }
}) })
.state('tabs.paymentRequest.confirm', { .state('tabs.paymentRequest.confirm', {
url: '/confirm/:amount/:currency', url: '/confirm/:amount/:currency/:chain',
views: { views: {
'tab-receive@tabs': { 'tab-receive@tabs': {
controller: 'customAmountController', controller: 'customAmountController',
@ -923,6 +923,9 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
controllerAs: 'glidera', controllerAs: 'glidera',
templateUrl: 'views/glidera.html' templateUrl: 'views/glidera.html'
} }
},
params: {
forceChain: 'BTC'
} }
}) })
.state('tabs.buyandsell.glidera.amount', { .state('tabs.buyandsell.glidera.amount', {
@ -976,6 +979,9 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
controllerAs: 'coinbase', controllerAs: 'coinbase',
templateUrl: 'views/coinbase.html' templateUrl: 'views/coinbase.html'
} }
},
params: {
forceChain: 'BTC'
} }
}) })
.state('tabs.preferences.coinbase', { .state('tabs.preferences.coinbase', {
@ -1064,7 +1070,8 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
params: { params: {
nextStep: 'tabs.giftcards.mercadoLibre.buy', nextStep: 'tabs.giftcards.mercadoLibre.buy',
currency: 'BRL', currency: 'BRL',
forceCurrency: true forceCurrency: true,
forceChain: 'BTC'
} }
}) })
.state('tabs.giftcards.mercadoLibre.buy', { .state('tabs.giftcards.mercadoLibre.buy', {
@ -1115,7 +1122,8 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
params: { params: {
nextStep: 'tabs.giftcards.amazon.buy', nextStep: 'tabs.giftcards.amazon.buy',
currency: 'USD', currency: 'USD',
forceCurrency: true forceCurrency: true,
forceChain: 'BTC'
} }
}) })
.state('tabs.giftcards.amazon.buy', { .state('tabs.giftcards.amazon.buy', {
@ -1155,6 +1163,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
params: { params: {
id: null, id: null,
currency: 'USD', currency: 'USD',
forceChain: 'BTC',
useSendMax: null useSendMax: null
} }
}) })

View file

@ -143,6 +143,14 @@ angular.module('copayApp.services').factory('configService', function(storageSer
configCache.bitpayAccount = defaultConfig.bitpayAccount; configCache.bitpayAccount = defaultConfig.bitpayAccount;
} }
if (configCache.wallet.settings.unitCode == 'bit') {
// Convert to BTC. Bits will be disabled
configCache.wallet.settings.unitName = defaultConfig.wallet.settings.unitName;
configCache.wallet.settings.unitToSatoshi = defaultConfig.wallet.settings.unitToSatoshi;
configCache.wallet.settings.unitDecimals = defaultConfig.wallet.settings.unitDecimals;
configCache.wallet.settings.unitCode = defaultConfig.wallet.settings.unitCode;
}
} else { } else {
configCache = lodash.clone(defaultConfig); configCache = lodash.clone(defaultConfig);
}; };

View file

@ -64,7 +64,6 @@ angular.module('copayApp.services').factory('feeService', function($log, $timeou
} }
var walletClient = bwcService.getClient(); var walletClient = bwcService.getClient();
var unitName = configService.getSync().wallet.settings.unitName;
walletClient.getFeeLevels('livenet', function(errLivenet, levelsLivenet) { walletClient.getFeeLevels('livenet', function(errLivenet, levelsLivenet) {
walletClient.getFeeLevels('testnet', function(errTestnet, levelsTestnet) { walletClient.getFeeLevels('testnet', function(errTestnet, levelsTestnet) {

View file

@ -89,6 +89,7 @@ angular.module('copayApp.services')
wallet.copayerId = wallet.credentials.copayerId; wallet.copayerId = wallet.credentials.copayerId;
wallet.m = wallet.credentials.m; wallet.m = wallet.credentials.m;
wallet.n = wallet.credentials.n; wallet.n = wallet.credentials.n;
wallet.chain = wallet.credentials.chain;
root.updateWalletSettings(wallet); root.updateWalletSettings(wallet);
root.wallet[walletId] = wallet; root.wallet[walletId] = wallet;
@ -222,11 +223,13 @@ angular.module('copayApp.services')
return ((config.bwsFor && config.bwsFor[walletId]) || defaults.bws.url); return ((config.bwsFor && config.bwsFor[walletId]) || defaults.bws.url);
}; };
var client = bwcService.getClient(JSON.stringify(credentials), { var client = bwcService.getClient(JSON.stringify(credentials), {
bwsurl: getBWSURL(credentials.walletId), bwsurl: getBWSURL(credentials.walletId),
}); });
// TODO: Should return "chain" = "BTC" or "BCH"
client.credentials.chain = 'BTC';
var skipKeyValidation = shouldSkipValidation(credentials.walletId); var skipKeyValidation = shouldSkipValidation(credentials.walletId);
if (!skipKeyValidation) if (!skipKeyValidation)
root.runValidation(client, 500); root.runValidation(client, 500);
@ -749,6 +752,12 @@ angular.module('copayApp.services')
var ret = lodash.values(root.wallet); var ret = lodash.values(root.wallet);
if (opts.chain) {
ret = lodash.filter(ret, function(x) {
return (x.credentials.chain == opts.chain);
});
}
if (opts.network) { if (opts.network) {
ret = lodash.filter(ret, function(x) { ret = lodash.filter(ret, function(x) {
return (x.credentials.network == opts.network); return (x.credentials.network == opts.network);
@ -848,7 +857,7 @@ angular.module('copayApp.services')
}); });
}; };
function process(notifications) { function process(wallet, notifications) {
if (!notifications) return []; if (!notifications) return [];
var shown = lodash.sortBy(notifications, 'createdOn').reverse(); var shown = lodash.sortBy(notifications, 'createdOn').reverse();
@ -861,7 +870,7 @@ angular.module('copayApp.services')
x.types = [x.type]; x.types = [x.type];
if (x.data && x.data.amount) if (x.data && x.data.amount)
x.amountStr = txFormatService.formatAmountStr(x.data.amount); x.amountStr = txFormatService.formatAmountStr(wallet, x.data.amount);
x.action = function() { x.action = function() {
// TODO? // TODO?
@ -939,7 +948,7 @@ angular.module('copayApp.services')
notifications = lodash.sortBy(notifications, 'createdOn'); notifications = lodash.sortBy(notifications, 'createdOn');
notifications = lodash.compact(lodash.flatten(notifications)).slice(0, MAX); notifications = lodash.compact(lodash.flatten(notifications)).slice(0, MAX);
var total = notifications.length; var total = notifications.length;
return cb(null, process(notifications), total); return cb(null, process(wallet, notifications), total);
}; };
}); });
}); });

View file

@ -17,10 +17,10 @@ angular.module('copayApp.services').factory('txFormatService', function($filter,
return this.Utils.formatAmount(satoshis, config.unitCode, opts); return this.Utils.formatAmount(satoshis, config.unitCode, opts);
}; };
root.formatAmountStr = function(satoshis) { root.formatAmountStr = function(wallet, satoshis) {
console.log('[txFormatService.js:20]',wallet); //TODO/
if (isNaN(satoshis)) return; if (isNaN(satoshis)) return;
var config = configService.getSync().wallet.settings; return root.formatAmount(satoshis) + ' ' + wallet.chain;
return root.formatAmount(satoshis) + ' ' + config.unitName;
}; };
root.toFiat = function(satoshis, code, cb) { root.toFiat = function(satoshis, code, cb) {
@ -86,7 +86,7 @@ angular.module('copayApp.services').factory('txFormatService', function($filter,
}; };
}; };
root.processTx = function(tx) { root.processTx = function(wallet, tx) {
if (!tx || tx.action == 'invalid') if (!tx || tx.action == 'invalid')
return tx; return tx;
@ -101,7 +101,7 @@ angular.module('copayApp.services').factory('txFormatService', function($filter,
tx.hasMultiplesOutputs = true; tx.hasMultiplesOutputs = true;
} }
tx.amount = lodash.reduce(tx.outputs, function(total, o) { tx.amount = lodash.reduce(tx.outputs, function(total, o) {
o.amountStr = root.formatAmountStr(o.amount); o.amountStr = root.formatAmountStr(wallet, o.amount);
o.alternativeAmountStr = root.formatAlternativeStr(o.amount); o.alternativeAmountStr = root.formatAlternativeStr(o.amount);
return total + o.amount; return total + o.amount;
}, 0); }, 0);
@ -109,9 +109,9 @@ angular.module('copayApp.services').factory('txFormatService', function($filter,
tx.toAddress = tx.outputs[0].toAddress; tx.toAddress = tx.outputs[0].toAddress;
} }
tx.amountStr = root.formatAmountStr(tx.amount); tx.amountStr = root.formatAmountStr(wallet, tx.amount);
tx.alternativeAmountStr = root.formatAlternativeStr(tx.amount); tx.alternativeAmountStr = root.formatAlternativeStr(tx.amount);
tx.feeStr = root.formatAmountStr(tx.fee || tx.fees); tx.feeStr = root.formatAmountStr(wallet, tx.fee || tx.fees);
if (tx.amountStr) { if (tx.amountStr) {
tx.amountValueStr = tx.amountStr.split(' ')[0]; tx.amountValueStr = tx.amountStr.split(' ')[0];
@ -145,8 +145,6 @@ angular.module('copayApp.services').factory('txFormatService', function($filter,
lodash.each(txps, function(tx) { lodash.each(txps, function(tx) {
tx = txFormatService.processTx(tx);
// no future transactions... // no future transactions...
if (tx.createdOn > now) if (tx.createdOn > now)
tx.createdOn = now; tx.createdOn = now;
@ -157,6 +155,8 @@ angular.module('copayApp.services').factory('txFormatService', function($filter,
return; return;
} }
tx = txFormatService.processTx(tx.wallet, tx);
var action = lodash.find(tx.actions, { var action = lodash.find(tx.actions, {
copayerId: tx.wallet.copayerId copayerId: tx.wallet.copayerId
}); });
@ -180,7 +180,7 @@ angular.module('copayApp.services').factory('txFormatService', function($filter,
return txps; return txps;
}; };
root.parseAmount = function(amount, currency) { root.parseAmount = function(wallet, amount, currency) {
var config = configService.getSync().wallet.settings; var config = configService.getSync().wallet.settings;
var satToBtc = 1 / 100000000; var satToBtc = 1 / 100000000;
var unitToSatoshi = config.unitToSatoshi; var unitToSatoshi = config.unitToSatoshi;
@ -189,21 +189,21 @@ angular.module('copayApp.services').factory('txFormatService', function($filter,
var alternativeIsoCode = config.alternativeIsoCode; var alternativeIsoCode = config.alternativeIsoCode;
// If fiat currency // If fiat currency
if (currency != 'bits' && currency != 'BTC' && currency != 'sat') { if (currency != 'BCH' && currency != 'BTC' && currency != 'sat') {
amountUnitStr = $filter('formatFiatAmount')(amount) + ' ' + currency; amountUnitStr = $filter('formatFiatAmount')(amount) + ' ' + currency;
amountSat = rateService.fromFiat(amount, currency).toFixed(0); amountSat = rateService.fromFiat(amount, currency).toFixed(0);
} else if (currency == 'sat') { } else if (currency == 'sat') {
amountSat = amount; amountSat = amount;
amountUnitStr = root.formatAmountStr(amountSat); amountUnitStr = root.formatAmountStr(wallet, amountSat);
// convert sat to BTC // convert sat to BTC or BCH
amount = (amountSat * satToBtc).toFixed(8); amount = (amountSat * satToBtc).toFixed(8);
currency = 'BTC'; currency = wallet.chain;
} else { } else {
amountSat = parseInt((amount * unitToSatoshi).toFixed(0)); amountSat = parseInt((amount * unitToSatoshi).toFixed(0));
amountUnitStr = root.formatAmountStr(amountSat); amountUnitStr = root.formatAmountStr(wallet, amountSat);
// convert unit to BTC // convert unit to BTC or BCH
amount = (amountSat * satToBtc).toFixed(8); amount = (amountSat * satToBtc).toFixed(8);
currency = 'BTC'; currency = wallet.chain;
} }
return { return {

View file

@ -2,8 +2,8 @@
angular.module('copayApp.services').factory('walletService', function($log, $timeout, lodash, trezor, ledger, intelTEE, storageService, configService, rateService, uxLanguage, $filter, gettextCatalog, bwcError, $ionicPopup, fingerprintService, ongoingProcess, gettext, $rootScope, txFormatService, $ionicModal, $state, bwcService, bitcore, popupService) { angular.module('copayApp.services').factory('walletService', function($log, $timeout, lodash, trezor, ledger, intelTEE, storageService, configService, rateService, uxLanguage, $filter, gettextCatalog, bwcError, $ionicPopup, fingerprintService, ongoingProcess, gettext, $rootScope, txFormatService, $ionicModal, $state, bwcService, bitcore, popupService) {
// Ratio low amount warning (fee/amount) in incoming TX // Ratio low amount warning (fee/amount) in incoming TX
var LOW_AMOUNT_RATIO = 0.15; var LOW_AMOUNT_RATIO = 0.15;
// Ratio of "many utxos" warning in total balance (fee/amount) // Ratio of "many utxos" warning in total balance (fee/amount)
var TOTAL_LOW_WARNING_RATIO = .3; var TOTAL_LOW_WARNING_RATIO = .3;
@ -130,7 +130,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
lodash.each(txps, function(tx) { lodash.each(txps, function(tx) {
tx = txFormatService.processTx(tx); tx = txFormatService.processTx(wallet, tx);
// no future transactions... // no future transactions...
if (tx.createdOn > now) if (tx.createdOn > now)
@ -213,14 +213,13 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
// Selected unit // Selected unit
cache.unitToSatoshi = config.settings.unitToSatoshi; cache.unitToSatoshi = config.settings.unitToSatoshi;
cache.satToUnit = 1 / cache.unitToSatoshi; cache.satToUnit = 1 / cache.unitToSatoshi;
cache.unitName = config.settings.unitName;
//STR //STR
cache.totalBalanceStr = txFormatService.formatAmount(cache.totalBalanceSat) + ' ' + cache.unitName; cache.totalBalanceStr = txFormatService.formatAmount(cache.totalBalanceSat) + ' ' + wallet.chain;
cache.lockedBalanceStr = txFormatService.formatAmount(cache.lockedBalanceSat) + ' ' + cache.unitName; cache.lockedBalanceStr = txFormatService.formatAmount(cache.lockedBalanceSat) + ' ' + wallet.chain;
cache.availableBalanceStr = txFormatService.formatAmount(cache.availableBalanceSat) + ' ' + cache.unitName; cache.availableBalanceStr = txFormatService.formatAmount(cache.availableBalanceSat) + ' ' + wallet.chain;
cache.spendableBalanceStr = txFormatService.formatAmount(cache.spendableAmount) + ' ' + cache.unitName; cache.spendableBalanceStr = txFormatService.formatAmount(cache.spendableAmount) + ' ' + wallet.chain;
cache.pendingBalanceStr = txFormatService.formatAmount(cache.pendingAmount) + ' ' + cache.unitName; cache.pendingBalanceStr = txFormatService.formatAmount(cache.pendingAmount) + ' ' + wallet.chain;
cache.alternativeName = config.settings.alternativeName; cache.alternativeName = config.settings.alternativeName;
cache.alternativeIsoCode = config.settings.alternativeIsoCode; cache.alternativeIsoCode = config.settings.alternativeIsoCode;
@ -366,7 +365,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
wallet.hasUnsafeConfirmed = false; wallet.hasUnsafeConfirmed = false;
lodash.each(txs, function(tx) { lodash.each(txs, function(tx) {
tx = txFormatService.processTx(tx); tx = txFormatService.processTx(wallet, tx);
// no future transactions... // no future transactions...
if (tx.time > now) if (tx.time > now)
@ -400,7 +399,6 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
var LIMIT = 50; var LIMIT = 50;
var requestLimit = FIRST_LIMIT; var requestLimit = FIRST_LIMIT;
var walletId = wallet.credentials.walletId; var walletId = wallet.credentials.walletId;
var config = configService.getSync().wallet.settings;
var opts = opts || {}; var opts = opts || {};
var progressFn = opts.progressFn || function() {}; var progressFn = opts.progressFn || function() {};
@ -414,17 +412,15 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
var fixTxsUnit = function(txs) { var fixTxsUnit = function(txs) {
if (!txs || !txs[0] || !txs[0].amountStr) return; if (!txs || !txs[0] || !txs[0].amountStr) return;
var cacheUnit = txs[0].amountStr.split(' ')[1]; var cacheChain = txs[0].amountStr.split(' ')[1];
if (cacheUnit == config.unitName) if (cacheChain == wallet.chain)
return; return;
var name = ' ' + config.unitName; $log.debug('Fixing Tx Cache Unit to: ' + wallet.chain)
$log.debug('Fixing Tx Cache Unit to:' + name)
lodash.each(txs, function(tx) { lodash.each(txs, function(tx) {
tx.amountStr = txFormatService.formatAmount(tx.amount) + name; tx.amountStr = txFormatService.formatAmountStr(wallet, tx.amount);
tx.feeStr = txFormatService.formatAmount(tx.fees) + name; tx.feeStr = txFormatService.formatAmountStr(wallet, tx.fees);
}); });
}; };
@ -788,7 +784,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
//prefs.email (may come from arguments) //prefs.email (may come from arguments)
prefs.email = config.emailNotifications.email; prefs.email = config.emailNotifications.email;
prefs.language = uxLanguage.getCurrentLanguage(); prefs.language = uxLanguage.getCurrentLanguage();
prefs.unit = walletSettings.unitCode; // prefs.unit = walletSettings.unitCode; // TODO: remove, not used
updateRemotePreferencesFor(lodash.clone(clients), prefs, function(err) { updateRemotePreferencesFor(lodash.clone(clients), prefs, function(err) {
if (err) return cb(err); if (err) return cb(err);
@ -922,7 +918,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
}; };
// Approx utxo amount, from which the uxto is economically redeemable // Approx utxo amount, from which the uxto is economically redeemable
root.getMinFee = function(wallet, feeLevels, nbOutputs) { root.getMinFee = function(wallet, feeLevels, nbOutputs) {
var lowLevelRate = (lodash.find(feeLevels[wallet.network], { var lowLevelRate = (lodash.find(feeLevels[wallet.network], {
level: 'normal', level: 'normal',
@ -933,7 +929,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
}; };
// Approx utxo amount, from which the uxto is economically redeemable // Approx utxo amount, from which the uxto is economically redeemable
root.getLowAmount = function(wallet, feeLevels, nbOutputs) { root.getLowAmount = function(wallet, feeLevels, nbOutputs) {
var minFee = root.getMinFee(wallet,feeLevels, nbOutputs); var minFee = root.getMinFee(wallet,feeLevels, nbOutputs);
return parseInt( minFee / LOW_AMOUNT_RATIO); return parseInt( minFee / LOW_AMOUNT_RATIO);

View file

@ -139,6 +139,19 @@
} }
} }
.amount { .amount {
.icon-toggle {
font-size: 1.2em;
width: auto;
margin: 0.8em auto;
border: 1px solid $v-subtle-gray;
color: $v-dark-gray;
border-radius: 3px;
padding: 0 10px;
cursor: pointer;
@media(max-height: 280px) {
margin: 0.1em auto;
}
}
&__editable { &__editable {
&--minimize { &--minimize {
font-size: 22px; font-size: 22px;
@ -196,7 +209,6 @@
&__result-equiv { &__result-equiv {
color: $v-mid-gray; color: $v-mid-gray;
font-size: 1.2em; font-size: 1.2em;
margin-top: 2rem;
@media(max-height: 480px) { @media(max-height: 480px) {
margin-top: 0; margin-top: 0;
font-size: 16px; font-size: 16px;

View file

@ -48,16 +48,19 @@
<div class="amount"> <div class="amount">
<div class="amount__editable" ng-class="{'amount__editable--minimize': smallFont, 'amount__editable--standard': !smallFont, 'amount__editable--placeholder': !amount}"> <div class="amount__editable" ng-class="{'amount__editable--minimize': smallFont, 'amount__editable--standard': !smallFont, 'amount__editable--placeholder': !amount}">
<span class="amount__number">{{amount || "0.00" }}</span> <span class="amount__number">{{amount || "0.00" }}</span>
<a class="amount__currency-toggle" ng-click="toggleAlternative()" ng-show="showAlternativeAmount">{{alternativeIsoCode}}</a> <a class="amount__currency-toggle" ng-show="showAlternativeAmount">{{alternativeIsoCode}}</a>
<a class="amount__currency-toggle" ng-click="toggleAlternative()" ng-show="!showAlternativeAmount">{{unitName}}</a> <a class="amount__currency-toggle" ng-click="toggleChain()" ng-show="!showAlternativeAmount">{{chain}}</a>
</div>
<div class="icon-toggle" ng-if="!forceCurrency" ng-click="toggleAlternative()">
<i class="icon ion-arrow-swap"></i>
</div> </div>
<div ng-class="{'amount__results--minimize': smallFont, 'amount__results--standard': !smallFont, 'amount__results--placeholder': !amountResult}" ng-show="!showAlternativeAmount"> <div ng-class="{'amount__results--minimize': smallFont, 'amount__results--standard': !smallFont, 'amount__results--placeholder': !amountResult}" ng-show="!showAlternativeAmount">
<div class="amount__result" ng-show="globalResult">{{globalResult}} {{unitName}}</div> <div class="amount__result" ng-show="globalResult">{{globalResult}} {{chain}}</div>
<div class="amount__result-equiv">&asymp; {{amountResult || '0.00'}} {{alternativeIsoCode}}</div> <div class="amount__result-equiv">&asymp; {{amountResult || '0.00'}} {{alternativeIsoCode}}</div>
</div> </div>
<div ng-class="{'amount__results--minimize': smallFont, 'amount__results--standard': !smallFont, 'amount__results--placeholder': !amountResult}" ng-show="showAlternativeAmount"> <div ng-class="{'amount__results--minimize': smallFont, 'amount__results--standard': !smallFont, 'amount__results--placeholder': !amountResult}" ng-show="showAlternativeAmount">
<div class="amount__result" ng-show="globalResult">{{globalResult}} {{alternativeIsoCode}}</div> <div class="amount__result" ng-show="globalResult">{{globalResult}} {{alternativeIsoCode}}</div>
<div class="amount__result-equiv">{{alternativeResult || '0.00'}} {{unitName}}</div> <div class="amount__result-equiv">{{alternativeResult || '0.00'}} {{chain}}</div>
</div> </div>
</div> </div>
</div> </div>

View file

@ -21,7 +21,7 @@
<ion-content scroll="false"> <ion-content scroll="false">
<div class="address" ng-if="address && amountBtc"> <div class="address" ng-if="address && amountBtc">
<div class="qr-code" copy-to-clipboard="copyToClipboard()"> <div class="qr-code" copy-to-clipboard="copyToClipboard()">
<qrcode size="220" data="bitcoin:{{address + '?amount=' + amountBtc}}" color="#334"></qrcode> <qrcode size="220" data="bitcoin:{{address + '?amount=' + amountBtc + '&chain=' + chain}}" color="#334"></qrcode>
</div> </div>
<div class="info"> <div class="info">
<div class="item single-line" copy-to-clipboard="address"> <div class="item single-line" copy-to-clipboard="address">