Merge https://github.com/bitpay/copay into copay-cash
This commit is contained in:
commit
a0261a6c9f
146 changed files with 16800 additions and 5578 deletions
|
|
@ -14,7 +14,7 @@ angular.module('copayApp.controllers').controller('addressbookAddController', fu
|
|||
$timeout(function() {
|
||||
var form = addressbookForm;
|
||||
if (data && form) {
|
||||
data = data.replace('bitcoin:', '');
|
||||
data = data.replace(/^bitcoin(cash)?:/, '');
|
||||
form.address.$setViewValue(data);
|
||||
form.address.$isValid = true;
|
||||
form.address.$render();
|
||||
|
|
|
|||
|
|
@ -1,11 +1,23 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('addressbookViewController', function($scope, $state, $timeout, $stateParams, lodash, addressbookService, popupService, $ionicHistory, platformInfo, gettextCatalog) {
|
||||
angular.module('copayApp.controllers').controller('addressbookViewController', function($scope, $state, $timeout, lodash, addressbookService, popupService, $ionicHistory, platformInfo, gettextCatalog, bitcoreCash) {
|
||||
$scope.isChromeApp = platformInfo.isChromeApp;
|
||||
$scope.addressbookEntry = {};
|
||||
$scope.addressbookEntry.name = $stateParams.name;
|
||||
$scope.addressbookEntry.email = $stateParams.email;
|
||||
$scope.addressbookEntry.address = $stateParams.address;
|
||||
var coin;
|
||||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
$scope.addressbookEntry = {};
|
||||
$scope.addressbookEntry.name = data.stateParams.name;
|
||||
$scope.addressbookEntry.email = data.stateParams.email;
|
||||
$scope.addressbookEntry.address = data.stateParams.address;
|
||||
|
||||
var cashAddress = bitcoreCash.Address.isValid($scope.addressbookEntry.address, 'livenet');
|
||||
if (cashAddress) {
|
||||
coin = 'bch';
|
||||
} else {
|
||||
coin = 'btc';
|
||||
}
|
||||
});
|
||||
|
||||
$scope.sendTo = function() {
|
||||
$ionicHistory.removeBackView();
|
||||
|
|
@ -14,7 +26,8 @@ angular.module('copayApp.controllers').controller('addressbookViewController', f
|
|||
$state.transitionTo('tabs.send.amount', {
|
||||
toAddress: $scope.addressbookEntry.address,
|
||||
toName: $scope.addressbookEntry.name,
|
||||
toEmail: $scope.addressbookEntry.email
|
||||
toEmail: $scope.addressbookEntry.email,
|
||||
coin: coin
|
||||
});
|
||||
}, 100);
|
||||
};
|
||||
|
|
@ -31,7 +44,7 @@ angular.module('copayApp.controllers').controller('addressbookViewController', f
|
|||
}
|
||||
$ionicHistory.goBack();
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,13 +1,8 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('addressesController', function($scope, $log, $stateParams, $state, $timeout, $ionicHistory, $ionicScrollDelegate, configService, popupService, gettextCatalog, ongoingProcess, lodash, profileService, walletService, bwcError, platformInfo, appConfigService, txFormatService, feeService) {
|
||||
angular.module('copayApp.controllers').controller('addressesController', function($scope, $log, $stateParams, $state, $timeout, $ionicHistory, $ionicScrollDelegate, popupService, gettextCatalog, ongoingProcess, lodash, profileService, walletService, bwcError, platformInfo, appConfigService, txFormatService, feeService) {
|
||||
var UNUSED_ADDRESS_LIMIT = 5;
|
||||
var BALANCE_ADDRESS_LIMIT = 5;
|
||||
var config = configService.getSync().wallet.settings;
|
||||
var unitName = config.unitName;
|
||||
var unitToSatoshi = config.unitToSatoshi;
|
||||
var satToUnit = 1 / unitToSatoshi;
|
||||
var unitDecimals = config.unitDecimals;
|
||||
var withBalance, cachedWallet;
|
||||
|
||||
$scope.isCordova = platformInfo.isCordova;
|
||||
|
|
@ -55,7 +50,7 @@ angular.module('copayApp.controllers').controller('addressesController', functio
|
|||
$scope.latestWithBalance = lodash.slice(withBalance, 0, BALANCE_ADDRESS_LIMIT);
|
||||
|
||||
lodash.each(withBalance, function(a) {
|
||||
a.balanceStr = txFormatService.formatAmount(a.amount);
|
||||
a.balanceStr = txFormatService.formatAmountStr($scope.wallet.coin, a.amount);
|
||||
});
|
||||
|
||||
$scope.viewAll = {
|
||||
|
|
@ -75,11 +70,11 @@ angular.module('copayApp.controllers').controller('addressesController', functio
|
|||
|
||||
|
||||
|
||||
feeService.getFeeLevels(function(err, levels){
|
||||
feeService.getFeeLevels($scope.wallet.coin, function(err, levels){
|
||||
walletService.getLowUtxos($scope.wallet, levels, function(err, resp) {
|
||||
if (err) return;
|
||||
|
||||
if (resp.allUtxos && resp.allUtxos.length) {
|
||||
if (resp && resp.allUtxos && resp.allUtxos.length) {
|
||||
|
||||
|
||||
var allSum = lodash.sum(resp.allUtxos || 0, 'satoshis');
|
||||
|
|
@ -88,9 +83,9 @@ angular.module('copayApp.controllers').controller('addressesController', functio
|
|||
$scope.lowWarning = resp.warning;
|
||||
$scope.lowUtxosNb = resp.lowUtxos.length;
|
||||
$scope.allUtxosNb = resp.allUtxos.length;
|
||||
$scope.lowUtxosSum = txFormatService.formatAmountStr(lodash.sum(resp.lowUtxos || 0, 'satoshis'));
|
||||
$scope.allUtxosSum = txFormatService.formatAmountStr(allSum);
|
||||
$scope.minFee = txFormatService.formatAmountStr(resp.minFee || 0);
|
||||
$scope.lowUtxosSum = txFormatService.formatAmountStr($scope.wallet.coin, lodash.sum(resp.lowUtxos || 0, 'satoshis'));
|
||||
$scope.allUtxosSum = txFormatService.formatAmountStr($scope.wallet.coin, allSum);
|
||||
$scope.minFee = txFormatService.formatAmountStr($scope.wallet.coin, resp.minFee || 0);
|
||||
$scope.minFeePer = per.toFixed(2) + '%';
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('advancedSettingsController', function($scope, $log, configService, platformInfo) {
|
||||
angular.module('copayApp.controllers').controller('advancedSettingsController', function($scope, $log, configService, platformInfo, externalLinkService, gettextCatalog) {
|
||||
|
||||
var updateConfig = function() {
|
||||
var config = configService.getSync();
|
||||
|
|
@ -14,6 +14,7 @@ angular.module('copayApp.controllers').controller('advancedSettingsController',
|
|||
$scope.hideNextSteps = {
|
||||
value: config.hideNextSteps.enabled
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
$scope.spendUnconfirmedChange = function() {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,14 @@ angular.module('copayApp.controllers').controller('amountController', function($
|
|||
var SMALL_FONT_SIZE_LIMIT = 10;
|
||||
var LENGTH_EXPRESSION_LIMIT = 19;
|
||||
var isNW = platformInfo.isNW;
|
||||
|
||||
var unitIndex = 0;
|
||||
var altUnitIndex = 0;
|
||||
var availableUnits = [];
|
||||
var fiatCode;
|
||||
|
||||
var fixedUnit;
|
||||
|
||||
$scope.isChromeApp = platformInfo.isChromeApp;
|
||||
|
||||
$scope.$on('$ionicView.leave', function() {
|
||||
|
|
@ -16,19 +24,100 @@ angular.module('copayApp.controllers').controller('amountController', function($
|
|||
});
|
||||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
var config = configService.getSync().wallet.settings;
|
||||
|
||||
function setAvailableUnits() {
|
||||
|
||||
availableUnits = [];
|
||||
|
||||
var hasBTCWallets = profileService.getWallets({
|
||||
coin: 'btc'
|
||||
}).length;
|
||||
|
||||
if (hasBTCWallets) {
|
||||
availableUnits.push({
|
||||
name: 'Bitcoin',
|
||||
id: 'btc',
|
||||
shortName: 'BTC',
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
var hasBCHWallets = profileService.getWallets({
|
||||
coin: 'bch'
|
||||
}).length;
|
||||
|
||||
|
||||
|
||||
if (hasBCHWallets) {
|
||||
availableUnits.push({
|
||||
name: 'Bitcoin Cash',
|
||||
id: 'bch',
|
||||
shortName: 'BCH',
|
||||
});
|
||||
};
|
||||
|
||||
unitIndex = 0;
|
||||
|
||||
if (data.stateParams.coin) {
|
||||
var coins = data.stateParams.coin.split(',');
|
||||
var newAvailableUnits = [];
|
||||
|
||||
lodash.each(coins, function(c) {
|
||||
var coin = lodash.find(availableUnits, {
|
||||
id: c
|
||||
});
|
||||
if (!coin) {
|
||||
$log.warn('Could not find desired coin:' + data.stateParams.coin)
|
||||
} else {
|
||||
newAvailableUnits.push(coin);
|
||||
}
|
||||
});
|
||||
|
||||
if (newAvailableUnits.length > 0) {
|
||||
availableUnits = newAvailableUnits;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// currency have preference
|
||||
var fiatName;
|
||||
if (data.stateParams.currency) {
|
||||
fiatCode = data.stateParams.currency;
|
||||
altUnitIndex = unitIndex
|
||||
unitIndex = availableUnits.length;
|
||||
} else {
|
||||
fiatCode = config.alternativeIsoCode || 'USD';
|
||||
fiatName = config.alternanativeName || fiatCode;
|
||||
altUnitIndex = availableUnits.length;
|
||||
}
|
||||
|
||||
availableUnits.push({
|
||||
name: fiatName || fiatCode,
|
||||
// TODO
|
||||
id: fiatCode,
|
||||
shortName: fiatCode,
|
||||
isFiat: true,
|
||||
});
|
||||
|
||||
if (data.stateParams.fixedUnit) {
|
||||
fixedUnit = true;
|
||||
}
|
||||
};
|
||||
|
||||
// Go to...
|
||||
_id = data.stateParams.id; // Optional (BitPay Card ID or Wallet ID)
|
||||
$scope.nextStep = data.stateParams.nextStep;
|
||||
$scope.currency = data.stateParams.currency;
|
||||
$scope.forceCurrency = data.stateParams.forceCurrency;
|
||||
|
||||
$scope.showMenu = $ionicHistory.backView() && ($ionicHistory.backView().stateName == 'tabs.send' ||
|
||||
$ionicHistory.backView().stateName == 'tabs.bitpayCard');
|
||||
|
||||
setAvailableUnits();
|
||||
updateUnitUI();
|
||||
|
||||
$scope.showMenu = $ionicHistory.backView() && ($ionicHistory.backView().stateName == 'tabs.send' || $ionicHistory.backView().stateName == 'tabs.bitpayCard');
|
||||
$scope.recipientType = data.stateParams.recipientType || null;
|
||||
$scope.toAddress = data.stateParams.toAddress;
|
||||
$scope.toName = data.stateParams.toName;
|
||||
$scope.toEmail = data.stateParams.toEmail;
|
||||
$scope.showAlternativeAmount = !!$scope.nextStep;
|
||||
$scope.toColor = data.stateParams.toColor;
|
||||
$scope.showSendMax = false;
|
||||
|
||||
|
|
@ -52,23 +141,13 @@ angular.module('copayApp.controllers').controller('amountController', function($
|
|||
} else if (e.key.match(reOp)) {
|
||||
$scope.pushOperator(e.key);
|
||||
} else if (e.keyCode === 86) {
|
||||
if (e.ctrlKey || e.metaKey)
|
||||
processClipboard();
|
||||
} else if (e.keyCode === 13)
|
||||
$scope.finish();
|
||||
if (e.ctrlKey || e.metaKey) processClipboard();
|
||||
} else if (e.keyCode === 13) $scope.finish();
|
||||
|
||||
$timeout(function() {
|
||||
$scope.$apply();
|
||||
});
|
||||
});
|
||||
|
||||
var config = configService.getSync().wallet.settings;
|
||||
$scope.unitName = config.unitName;
|
||||
if (data.stateParams.currency) {
|
||||
$scope.alternativeIsoCode = data.stateParams.currency;
|
||||
} else {
|
||||
$scope.alternativeIsoCode = config.alternativeIsoCode || 'USD';
|
||||
}
|
||||
$scope.specificAmount = $scope.specificAlternativeAmount = '';
|
||||
$scope.isCordova = platformInfo.isCordova;
|
||||
unitToSatoshi = config.unitToSatoshi;
|
||||
|
|
@ -114,16 +193,59 @@ angular.module('copayApp.controllers').controller('amountController', function($
|
|||
$scope.finish();
|
||||
};
|
||||
|
||||
$scope.toggleAlternative = function() {
|
||||
if ($scope.forceCurrency) return;
|
||||
$scope.showAlternativeAmount = !$scope.showAlternativeAmount;
|
||||
|
||||
$scope.toggleAlternative = function() {
|
||||
if ($scope.amount && isExpression($scope.amount)) {
|
||||
var amount = evaluate(format($scope.amount));
|
||||
$scope.globalResult = '= ' + processResult(amount);
|
||||
}
|
||||
};
|
||||
|
||||
function updateUnitUI() {
|
||||
$scope.unit = availableUnits[unitIndex].shortName;
|
||||
$scope.alternativeUnit = availableUnits[altUnitIndex].shortName;
|
||||
|
||||
processAmount();
|
||||
$log.debug('Update unit coin @amount unit:' + $scope.unit + " alternativeUnit:" + $scope.alternativeUnit);
|
||||
};
|
||||
|
||||
$scope.changeUnit = function() {
|
||||
if (fixedUnit) return;
|
||||
|
||||
unitIndex++;
|
||||
if (unitIndex >= availableUnits.length) unitIndex = 0;
|
||||
|
||||
|
||||
if (availableUnits[unitIndex].isFiat) {
|
||||
// Always return to BTC... TODO?
|
||||
altUnitIndex = 0;
|
||||
} else {
|
||||
altUnitIndex = lodash.findIndex(availableUnits, {
|
||||
isFiat: true
|
||||
});
|
||||
}
|
||||
|
||||
updateUnitUI();
|
||||
};
|
||||
|
||||
|
||||
$scope.changeAlternativeUnit = function() {
|
||||
|
||||
// Do nothing is fiat is not main unit
|
||||
if (!availableUnits[unitIndex].isFiat) return;
|
||||
|
||||
var nextCoin = lodash.findIndex(availableUnits, function(x) {
|
||||
if (x.isFiat) return false;
|
||||
if (x.id == availableUnits[altUnitIndex].id) return false;
|
||||
return true;
|
||||
});
|
||||
|
||||
if (nextCoin >= 0) {
|
||||
altUnitIndex = nextCoin;
|
||||
updateUnitUI();
|
||||
}
|
||||
};
|
||||
|
||||
function checkFontSize() {
|
||||
if ($scope.amount && $scope.amount.length >= SMALL_FONT_SIZE_LIMIT) $scope.smallFont = true;
|
||||
else $scope.smallFont = false;
|
||||
|
|
@ -132,7 +254,7 @@ angular.module('copayApp.controllers').controller('amountController', function($
|
|||
$scope.pushDigit = function(digit) {
|
||||
if ($scope.amount && $scope.amount.length >= LENGTH_EXPRESSION_LIMIT) return;
|
||||
if ($scope.amount.indexOf('.') > -1 && digit == '.') return;
|
||||
if ($scope.showAlternativeAmount && $scope.amount.indexOf('.') > -1 && $scope.amount[$scope.amount.indexOf('.') + 2]) return;
|
||||
if (availableUnits[unitIndex].isFiat && $scope.amount.indexOf('.') > -1 && $scope.amount[$scope.amount.indexOf('.') + 2]) return;
|
||||
|
||||
$scope.amount = ($scope.amount + digit).replace('..', '.');
|
||||
checkFontSize();
|
||||
|
|
@ -169,7 +291,7 @@ angular.module('copayApp.controllers').controller('amountController', function($
|
|||
};
|
||||
|
||||
$scope.resetAmount = function() {
|
||||
$scope.amount = $scope.alternativeResult = $scope.amountResult = $scope.globalResult = '';
|
||||
$scope.amount = $scope.alternativeAmount = $scope.globalResult = '';
|
||||
$scope.allowSend = false;
|
||||
checkFontSize();
|
||||
};
|
||||
|
|
@ -180,24 +302,39 @@ angular.module('copayApp.controllers').controller('amountController', function($
|
|||
$scope.allowSend = lodash.isNumber(result) && +result > 0;
|
||||
if (lodash.isNumber(result)) {
|
||||
$scope.globalResult = isExpression($scope.amount) ? '= ' + processResult(result) : '';
|
||||
$scope.amountResult = $filter('formatFiatAmount')(toFiat(result));
|
||||
$scope.alternativeResult = txFormatService.formatAmount(fromFiat(result) * unitToSatoshi, true);
|
||||
|
||||
if (availableUnits[unitIndex].isFiat) {
|
||||
|
||||
var a = fromFiat(result);
|
||||
if (a) {
|
||||
$scope.alternativeAmount = txFormatService.formatAmount(a * unitToSatoshi, true);
|
||||
} else {
|
||||
if (result) {
|
||||
$scope.alternativeAmount = 'N/A';
|
||||
} else {
|
||||
$scope.alternativeAmount = null;
|
||||
}
|
||||
$scope.allowSend = false;
|
||||
}
|
||||
} else {
|
||||
$scope.alternativeAmount = $filter('formatFiatAmount')(toFiat(result));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function processResult(val) {
|
||||
if ($scope.showAlternativeAmount)
|
||||
return $filter('formatFiatAmount')(val);
|
||||
else
|
||||
return txFormatService.formatAmount(val.toFixed(unitDecimals) * unitToSatoshi, true);
|
||||
if (availableUnits[unitIndex].isFiat) return $filter('formatFiatAmount')(val);
|
||||
else return txFormatService.formatAmount(val.toFixed(unitDecimals) * unitToSatoshi, true);
|
||||
};
|
||||
|
||||
function fromFiat(val) {
|
||||
return parseFloat((rateService.fromFiat(val, $scope.alternativeIsoCode) * satToUnit).toFixed(unitDecimals));
|
||||
return parseFloat((rateService.fromFiat(val, fiatCode, availableUnits[altUnitIndex].id) * satToUnit).toFixed(unitDecimals));
|
||||
};
|
||||
|
||||
function toFiat(val) {
|
||||
return parseFloat((rateService.toFiat(val * unitToSatoshi, $scope.alternativeIsoCode)).toFixed(2));
|
||||
if (!rateService.getRate(fiatCode)) return;
|
||||
|
||||
return parseFloat((rateService.toFiat(val * unitToSatoshi, fiatCode, availableUnits[unitIndex].id)).toFixed(2));
|
||||
};
|
||||
|
||||
function evaluate(val) {
|
||||
|
|
@ -212,33 +349,50 @@ angular.module('copayApp.controllers').controller('amountController', function($
|
|||
};
|
||||
|
||||
function format(val) {
|
||||
if (!val) return;
|
||||
|
||||
var result = val.toString();
|
||||
|
||||
if (isOperator(lodash.last(val)))
|
||||
result = result.slice(0, -1);
|
||||
if (isOperator(lodash.last(val))) result = result.slice(0, -1);
|
||||
|
||||
return result.replace('x', '*');
|
||||
};
|
||||
|
||||
$scope.finish = function() {
|
||||
|
||||
var unit = availableUnits[unitIndex];
|
||||
var _amount = evaluate(format($scope.amount));
|
||||
var coin = unit.id;
|
||||
if (unit.isFiat) {
|
||||
coin = availableUnits[altUnitIndex].id;
|
||||
}
|
||||
|
||||
if ($scope.nextStep) {
|
||||
|
||||
$state.transitionTo($scope.nextStep, {
|
||||
id: _id,
|
||||
amount: $scope.useSendMax ? null : _amount,
|
||||
currency: $scope.showAlternativeAmount ? $scope.alternativeIsoCode : $scope.unitName,
|
||||
currency: unit.id.toUpperCase(),
|
||||
coin: coin,
|
||||
useSendMax: $scope.useSendMax
|
||||
});
|
||||
} else {
|
||||
var amount = $scope.showAlternativeAmount ? fromFiat(_amount) : _amount;
|
||||
var amount = _amount;
|
||||
|
||||
if (unit.isFiat) {
|
||||
amount = (fromFiat(amount) * unitToSatoshi).toFixed(0);
|
||||
} else {
|
||||
amount = (amount * unitToSatoshi).toFixed(0);
|
||||
}
|
||||
|
||||
$state.transitionTo('tabs.send.confirm', {
|
||||
recipientType: $scope.recipientType,
|
||||
toAmount: $scope.useSendMax ? null : (amount * unitToSatoshi).toFixed(0),
|
||||
toAmount: amount,
|
||||
toAddress: $scope.toAddress,
|
||||
toName: $scope.toName,
|
||||
toEmail: $scope.toEmail,
|
||||
toColor: $scope.toColor,
|
||||
coin: coin,
|
||||
useSendMax: $scope.useSendMax
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
angular.module('copayApp.controllers').controller('buyAmazonController', function($scope, $log, $state, $timeout, $filter, $ionicHistory, $ionicConfig, lodash, amazonService, popupService, profileService, ongoingProcess, configService, walletService, payproService, bwcError, externalLinkService, platformInfo, gettextCatalog, txFormatService) {
|
||||
|
||||
var coin = 'btc';
|
||||
var amount;
|
||||
var currency;
|
||||
var createdTx;
|
||||
|
|
@ -64,7 +65,7 @@ angular.module('copayApp.controllers').controller('buyAmazonController', functio
|
|||
};
|
||||
|
||||
var satToFiat = function(sat, cb) {
|
||||
txFormatService.toFiat(sat, $scope.currencyIsoCode, function(value) {
|
||||
txFormatService.toFiat(coin, sat, $scope.currencyIsoCode, function(value) {
|
||||
return cb(value);
|
||||
});
|
||||
};
|
||||
|
|
@ -216,8 +217,8 @@ angular.module('copayApp.controllers').controller('buyAmazonController', functio
|
|||
});
|
||||
|
||||
var initialize = function(wallet) {
|
||||
var parsedAmount = txFormatService.parseAmount(amount, currency);
|
||||
$scope.currencyIsoCode = parsedAmount.alternativeIsoCode;
|
||||
var parsedAmount = txFormatService.parseAmount(coin, amount, currency);
|
||||
$scope.currencyIsoCode = parsedAmount.currency;
|
||||
$scope.amountUnitStr = parsedAmount.amountUnitStr;
|
||||
var dataSrc = {
|
||||
amount: parsedAmount.amount,
|
||||
|
|
@ -260,7 +261,7 @@ angular.module('copayApp.controllers').controller('buyAmazonController', functio
|
|||
invoiceUrl: invoice.url,
|
||||
invoiceTime: invoice.invoiceTime
|
||||
};
|
||||
$scope.totalAmountStr = txFormatService.formatAmountStr(ctxp.amount);
|
||||
$scope.totalAmountStr = txFormatService.formatAmountStr(coin, ctxp.amount);
|
||||
setTotalAmount(parsedAmount.amountSat, invoiceFeeSat, ctxp.fee);
|
||||
});
|
||||
});
|
||||
|
|
@ -292,7 +293,8 @@ angular.module('copayApp.controllers').controller('buyAmazonController', functio
|
|||
$scope.wallets = profileService.getWallets({
|
||||
onlyComplete: true,
|
||||
network: $scope.network,
|
||||
hasFunds: true
|
||||
hasFunds: true,
|
||||
coin: coin
|
||||
});
|
||||
if (lodash.isEmpty($scope.wallets)) {
|
||||
showErrorAndBack(null, gettextCatalog.getString('No wallets available'));
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
angular.module('copayApp.controllers').controller('buyCoinbaseController', function($scope, $log, $state, $timeout, $ionicHistory, $ionicScrollDelegate, $ionicConfig, lodash, coinbaseService, popupService, profileService, ongoingProcess, walletService, txFormatService) {
|
||||
|
||||
var coin = 'btc';
|
||||
var amount;
|
||||
var currency;
|
||||
|
||||
|
|
@ -33,6 +34,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) {
|
||||
$ionicConfig.views.swipeBackEnabled(true);
|
||||
});
|
||||
|
|
@ -42,81 +89,22 @@ angular.module('copayApp.controllers').controller('buyCoinbaseController', funct
|
|||
});
|
||||
|
||||
$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);
|
||||
$scope.isFiat = data.stateParams.currency != 'BTC' ? true : false;
|
||||
amount = data.stateParams.amount;
|
||||
currency = data.stateParams.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;
|
||||
}
|
||||
|
||||
$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();
|
||||
});
|
||||
});
|
||||
$scope.network = coinbaseService.getNetwork();
|
||||
$scope.wallets = profileService.getWallets({
|
||||
onlyComplete: true,
|
||||
network: $scope.network,
|
||||
coin: coin
|
||||
});
|
||||
|
||||
if (lodash.isEmpty($scope.wallets)) {
|
||||
showErrorAndBack('No wallets available');
|
||||
return;
|
||||
}
|
||||
$scope.onWalletSelect($scope.wallets[0]); // Default first wallet
|
||||
});
|
||||
|
||||
$scope.buyRequest = function() {
|
||||
|
|
@ -209,21 +197,31 @@ angular.module('copayApp.controllers').controller('buyCoinbaseController', funct
|
|||
});
|
||||
};
|
||||
|
||||
var _processBuyOrder = function() {
|
||||
coinbaseService.getBuyOrder(accessToken, accountId, b.data.id, function (err, buyResp) {
|
||||
if (err) {
|
||||
ongoingProcess.set('buyingBitcoin', false, statusChangeHandler);
|
||||
showError(err);
|
||||
return;
|
||||
}
|
||||
var tx = buyResp.data ? buyResp.data.transaction : null;
|
||||
if (tx && tx.id) {
|
||||
processBuyTx(tx);
|
||||
} else {
|
||||
$timeout(function() {
|
||||
_processBuyOrder();
|
||||
}, 5000);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$timeout(function() {
|
||||
var tx = b.data ? b.data.transaction : null;
|
||||
if (tx) {
|
||||
if (tx && tx.id) {
|
||||
processBuyTx(tx);
|
||||
}
|
||||
else {
|
||||
coinbaseService.getBuyOrder(accessToken, accountId, b.data.id, function (err, buyResp) {
|
||||
if (err) {
|
||||
ongoingProcess.set('buyingBitcoin', false, statusChangeHandler);
|
||||
showError(err);
|
||||
return;
|
||||
}
|
||||
var tx = buyResp.data ? buyResp.data.transaction : null;
|
||||
processBuyTx(tx);
|
||||
});
|
||||
_processBuyOrder();
|
||||
}
|
||||
}, 8000);
|
||||
});
|
||||
|
|
@ -238,6 +236,25 @@ angular.module('copayApp.controllers').controller('buyCoinbaseController', funct
|
|||
|
||||
$scope.onWalletSelect = function(wallet) {
|
||||
$scope.wallet = wallet;
|
||||
var parsedAmount = txFormatService.parseAmount(
|
||||
coin,
|
||||
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() {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
angular.module('copayApp.controllers').controller('buyGlideraController', function($scope, $log, $state, $timeout, $ionicHistory, $ionicConfig, lodash, glideraService, popupService, profileService, ongoingProcess, walletService, platformInfo, txFormatService) {
|
||||
|
||||
var coin = 'btc';
|
||||
var amount;
|
||||
var currency;
|
||||
|
||||
|
|
@ -35,36 +36,7 @@ angular.module('copayApp.controllers').controller('buyGlideraController', functi
|
|||
}
|
||||
};
|
||||
|
||||
$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.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
|
||||
|
||||
var processPaymentInfo = function() {
|
||||
ongoingProcess.set('connectingGlidera', true);
|
||||
glideraService.init(function(err, data) {
|
||||
if (err) {
|
||||
|
|
@ -88,6 +60,33 @@ angular.module('copayApp.controllers').controller('buyGlideraController', functi
|
|||
$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 != 'BTC' ? true : false;
|
||||
amount = data.stateParams.amount;
|
||||
currency = data.stateParams.currency;
|
||||
|
||||
$scope.network = glideraService.getNetwork();
|
||||
$scope.wallets = profileService.getWallets({
|
||||
onlyComplete: true,
|
||||
network: $scope.network,
|
||||
coin: coin
|
||||
});
|
||||
|
||||
if (lodash.isEmpty($scope.wallets)) {
|
||||
showErrorAndBack('No wallets available');
|
||||
return;
|
||||
}
|
||||
$scope.onWalletSelect($scope.wallets[0]); // Default first wallet
|
||||
});
|
||||
|
||||
var ask2FaCode = function(mode, cb) {
|
||||
|
|
@ -105,7 +104,7 @@ angular.module('copayApp.controllers').controller('buyGlideraController', functi
|
|||
popupService.showPrompt(title, message, null, function(twoFaCode) {
|
||||
if (typeof twoFaCode == 'undefined') return cb();
|
||||
return cb(twoFaCode);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
return cb();
|
||||
}
|
||||
|
|
@ -116,7 +115,7 @@ angular.module('copayApp.controllers').controller('buyGlideraController', functi
|
|||
var okText = 'Confirm';
|
||||
var cancelText = 'Cancel';
|
||||
popupService.showConfirm(null, message, okText, cancelText, function(ok) {
|
||||
if (!ok) return;
|
||||
if (!ok) return;
|
||||
ongoingProcess.set('buyingBitcoin', true, statusChangeHandler);
|
||||
glideraService.get2faCode($scope.token, function(err, tfa) {
|
||||
if (err) {
|
||||
|
|
@ -162,6 +161,15 @@ angular.module('copayApp.controllers').controller('buyGlideraController', functi
|
|||
|
||||
$scope.onWalletSelect = function(wallet) {
|
||||
$scope.wallet = wallet;
|
||||
var parsedAmount = txFormatService.parseAmount(
|
||||
coin,
|
||||
amount,
|
||||
currency);
|
||||
|
||||
amount = parsedAmount.amount;
|
||||
currency = parsedAmount.currency;
|
||||
$scope.amountUnitStr = parsedAmount.amountUnitStr;
|
||||
processPaymentInfo();
|
||||
};
|
||||
|
||||
$scope.goBackHome = function() {
|
||||
|
|
|
|||
354
src/js/controllers/buyMercadoLibre.js
Normal file
354
src/js/controllers/buyMercadoLibre.js
Normal file
|
|
@ -0,0 +1,354 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('buyMercadoLibreController', function($scope, $log, $state, $timeout, $filter, $ionicHistory, $ionicConfig, lodash, mercadoLibreService, popupService, profileService, ongoingProcess, configService, walletService, payproService, bwcError, externalLinkService, platformInfo, txFormatService, gettextCatalog) {
|
||||
|
||||
var coin = 'btc';
|
||||
var amount;
|
||||
var currency;
|
||||
var createdTx;
|
||||
var message;
|
||||
var invoiceId;
|
||||
var configWallet = configService.getSync().wallet;
|
||||
$scope.isCordova = platformInfo.isCordova;
|
||||
|
||||
$scope.openExternalLink = function(url) {
|
||||
externalLinkService.open(url);
|
||||
};
|
||||
|
||||
var _resetValues = function() {
|
||||
$scope.totalAmountStr = $scope.amount = $scope.invoiceFee = $scope.networkFee = $scope.totalAmount = $scope.wallet = null;
|
||||
createdTx = message = invoiceId = null;
|
||||
};
|
||||
|
||||
var showErrorAndBack = function(title, msg) {
|
||||
title = title || gettextCatalog.getString('Error');
|
||||
$scope.sendStatus = '';
|
||||
$log.error(msg);
|
||||
msg = (msg && msg.errors) ? msg.errors[0].message : msg;
|
||||
popupService.showAlert(title, msg, function() {
|
||||
$ionicHistory.goBack();
|
||||
});
|
||||
};
|
||||
|
||||
var showError = function(title, msg, cb) {
|
||||
cb = cb || function() {};
|
||||
title = title || gettextCatalog.getString('Error');
|
||||
$scope.sendStatus = '';
|
||||
$log.error(msg);
|
||||
msg = (msg && msg.errors) ? msg.errors[0].message : msg;
|
||||
popupService.showAlert(title, msg, cb);
|
||||
};
|
||||
|
||||
var publishAndSign = function(wallet, txp, onSendStatusChange, cb) {
|
||||
if (!wallet.canSign() && !wallet.isPrivKeyExternal()) {
|
||||
var err = 'No signing proposal: No private key';
|
||||
$log.info(err);
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
walletService.publishAndSign(wallet, txp, function(err, txp) {
|
||||
if (err) return cb(err);
|
||||
return cb(null, txp);
|
||||
}, onSendStatusChange);
|
||||
};
|
||||
|
||||
var statusChangeHandler = function(processName, showName, isOn) {
|
||||
$log.debug('statusChangeHandler: ', processName, showName, isOn);
|
||||
if (processName == 'Comprando Vale-Presente' && !isOn) {
|
||||
$scope.sendStatus = 'success';
|
||||
$timeout(function() {
|
||||
$scope.$digest();
|
||||
}, 100);
|
||||
} else if (showName) {
|
||||
$scope.sendStatus = showName;
|
||||
}
|
||||
};
|
||||
|
||||
var satToFiat = function(sat, cb) {
|
||||
txFormatService.toFiat(coin, sat, $scope.currencyIsoCode, function(value) {
|
||||
return cb(value);
|
||||
});
|
||||
};
|
||||
|
||||
var setTotalAmount = function(amountSat, invoiceFeeSat, networkFeeSat) {
|
||||
satToFiat(amountSat, function(a) {
|
||||
$scope.amount = Number(a);
|
||||
|
||||
satToFiat(invoiceFeeSat, function(i) {
|
||||
$scope.invoiceFee = Number(i);
|
||||
|
||||
satToFiat(networkFeeSat, function(n) {
|
||||
$scope.networkFee = Number(n);
|
||||
$scope.totalAmount = $scope.amount + $scope.invoiceFee + $scope.networkFee;
|
||||
$timeout(function() {
|
||||
$scope.$digest();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var createInvoice = function(data, cb) {
|
||||
mercadoLibreService.createBitPayInvoice(data, function(err, dataInvoice) {
|
||||
if (err) {
|
||||
var err_title = gettextCatalog.getString('Error creating the invoice');
|
||||
var err_msg;
|
||||
if (err && err.message && err.message.match(/suspended/i)) {
|
||||
err_title = gettextCatalog.getString('Service not available');
|
||||
err_msg = gettextCatalog.getString('Mercadolibre Gift Card Service is not available at this moment. Please try back later.');
|
||||
} else if (err && err.message) {
|
||||
err_msg = err.message;
|
||||
} else {
|
||||
err_msg = gettextCatalog.getString('Could not access Gift Card Service');
|
||||
};
|
||||
|
||||
return cb({
|
||||
title: err_title,
|
||||
message: err_msg
|
||||
});
|
||||
}
|
||||
|
||||
var accessKey = dataInvoice ? dataInvoice.accessKey : null;
|
||||
|
||||
if (!accessKey) {
|
||||
return cb({
|
||||
message: gettextCatalog.getString('No access key defined')
|
||||
});
|
||||
}
|
||||
|
||||
mercadoLibreService.getBitPayInvoice(dataInvoice.invoiceId, function(err, invoice) {
|
||||
if (err) {
|
||||
return cb({
|
||||
message: gettextCatalog.getString('Could not get the invoice')
|
||||
});
|
||||
}
|
||||
|
||||
return cb(null, invoice, accessKey);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var createTx = function(wallet, invoice, message, cb) {
|
||||
var payProUrl = (invoice && invoice.paymentUrls) ? invoice.paymentUrls.BIP73 : null;
|
||||
|
||||
if (!payProUrl) {
|
||||
return cb({
|
||||
title: gettextCatalog.getString('Error in Payment Protocol'),
|
||||
message: gettextCatalog.getString('Invalid URL')
|
||||
});
|
||||
}
|
||||
|
||||
var outputs = [];
|
||||
var toAddress = invoice.bitcoinAddress;
|
||||
var amountSat = parseInt((invoice.btcDue * 100000000).toFixed(0)); // BTC to Satoshi
|
||||
|
||||
outputs.push({
|
||||
'toAddress': toAddress,
|
||||
'amount': amountSat,
|
||||
'message': message
|
||||
});
|
||||
|
||||
var txp = {
|
||||
toAddress: toAddress,
|
||||
amount: amountSat,
|
||||
outputs: outputs,
|
||||
message: message,
|
||||
payProUrl: payProUrl,
|
||||
excludeUnconfirmedUtxos: configWallet.spendUnconfirmed ? false : true,
|
||||
feeLevel: configWallet.settings.feeLevel || 'normal'
|
||||
};
|
||||
|
||||
walletService.createTx(wallet, txp, function(err, ctxp) {
|
||||
if (err) {
|
||||
return cb({
|
||||
title: gettextCatalog.getString('Could not create transaction'),
|
||||
message: bwcError.msg(err)
|
||||
});
|
||||
}
|
||||
return cb(null, ctxp);
|
||||
});
|
||||
};
|
||||
|
||||
var checkTransaction = lodash.throttle(function(count, dataSrc) {
|
||||
mercadoLibreService.createGiftCard(dataSrc, function(err, giftCard) {
|
||||
$log.debug("creating gift card " + count);
|
||||
if (err) {
|
||||
$scope.sendStatus = '';
|
||||
ongoingProcess.set('Comprando Vale-Presente', false, statusChangeHandler);
|
||||
giftCard = {};
|
||||
giftCard.status = 'FAILURE';
|
||||
}
|
||||
|
||||
if (giftCard && giftCard.cardStatus && (giftCard.cardStatus != 'active' && giftCard.cardStatus != 'inactive' && giftCard.cardStatus != 'expired')) {
|
||||
$scope.sendStatus = '';
|
||||
ongoingProcess.set('Comprando Vale-Presente', false, statusChangeHandler);
|
||||
giftCard = {};
|
||||
giftCard.status = 'FAILURE';
|
||||
}
|
||||
|
||||
|
||||
if (giftCard.status == 'PENDING' && count < 3) {
|
||||
$log.debug("Waiting for payment confirmation");
|
||||
checkTransaction(count + 1, dataSrc);
|
||||
return;
|
||||
}
|
||||
|
||||
var now = moment().unix() * 1000;
|
||||
|
||||
var newData = giftCard;
|
||||
newData['invoiceId'] = dataSrc.invoiceId;
|
||||
newData['accessKey'] = dataSrc.accessKey;
|
||||
newData['invoiceUrl'] = dataSrc.invoiceUrl;
|
||||
newData['amount'] = dataSrc.amount;
|
||||
newData['currency'] = dataSrc.currency;
|
||||
newData['date'] = dataSrc.invoiceTime || now;
|
||||
newData['uuid'] = dataSrc.uuid;
|
||||
|
||||
mercadoLibreService.savePendingGiftCard(newData, null, function(err) {
|
||||
ongoingProcess.set('Comprando Vale-Presente', false, statusChangeHandler);
|
||||
$log.debug("Saving new gift card with status: " + newData.status);
|
||||
$scope.mlGiftCard = newData;
|
||||
});
|
||||
});
|
||||
}, 8000, {
|
||||
'leading': true
|
||||
});
|
||||
|
||||
var initialize = function(wallet) {
|
||||
var parsedAmount = txFormatService.parseAmount(coin, amount, currency);
|
||||
$scope.currencyIsoCode = parsedAmount.currency;
|
||||
$scope.amountUnitStr = parsedAmount.amountUnitStr;
|
||||
var dataSrc = {
|
||||
amount: parsedAmount.amount,
|
||||
currency: parsedAmount.currency,
|
||||
uuid: wallet.id
|
||||
};
|
||||
ongoingProcess.set('loadingTxInfo', true);
|
||||
createInvoice(dataSrc, function(err, invoice, accessKey) {
|
||||
if (err) {
|
||||
ongoingProcess.set('loadingTxInfo', false);
|
||||
showErrorAndBack(err.title, err.message);
|
||||
return;
|
||||
}
|
||||
// Sometimes API does not return this element;
|
||||
invoice['buyerPaidBtcMinerFee'] = invoice.buyerPaidBtcMinerFee || 0;
|
||||
var invoiceFeeSat = (invoice.buyerPaidBtcMinerFee * 100000000).toFixed();
|
||||
|
||||
message = gettextCatalog.getString("{{amountStr}} for Mercado Livre Brazil Gift Card", {
|
||||
amountStr: $scope.amountUnitStr
|
||||
});
|
||||
|
||||
createTx(wallet, invoice, message, function(err, ctxp) {
|
||||
ongoingProcess.set('loadingTxInfo', false);
|
||||
if (err) {
|
||||
_resetValues();
|
||||
showError(err.title, err.message);
|
||||
return;
|
||||
}
|
||||
|
||||
// Save in memory
|
||||
createdTx = ctxp;
|
||||
invoiceId = invoice.id;
|
||||
|
||||
createdTx['giftData'] = {
|
||||
currency: dataSrc.currency,
|
||||
amount: dataSrc.amount,
|
||||
uuid: dataSrc.uuid,
|
||||
accessKey: accessKey,
|
||||
invoiceId: invoice.id,
|
||||
invoiceUrl: invoice.url,
|
||||
invoiceTime: invoice.invoiceTime
|
||||
};
|
||||
$scope.totalAmountStr = txFormatService.formatAmountStr(coin, ctxp.amount);
|
||||
setTotalAmount(parsedAmount.amountSat, invoiceFeeSat, ctxp.fee);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$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) {
|
||||
amount = data.stateParams.amount;
|
||||
currency = data.stateParams.currency;
|
||||
|
||||
if (amount > 2000 || amount < 50) {
|
||||
showErrorAndBack(null, gettextCatalog.getString('Purchase amount must be a value between 50 and 2000'));
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.network = mercadoLibreService.getNetwork();
|
||||
$scope.wallets = profileService.getWallets({
|
||||
onlyComplete: true,
|
||||
network: $scope.network,
|
||||
coin: coin
|
||||
});
|
||||
if (lodash.isEmpty($scope.wallets)) {
|
||||
showErrorAndBack(null, gettextCatalog.getString('No wallets available'));
|
||||
return;
|
||||
}
|
||||
$scope.onWalletSelect($scope.wallets[0]); // Default first wallet
|
||||
});
|
||||
|
||||
$scope.buyConfirm = function() {
|
||||
|
||||
if (!createdTx) {
|
||||
showError(null, gettextCatalog.getString('Transaction has not been created'));
|
||||
return;
|
||||
}
|
||||
|
||||
var title = gettextCatalog.getString('Confirm');
|
||||
var okText = gettextCatalog.getString('Ok');
|
||||
var cancelText = gettextCatalog.getString('Cancel');
|
||||
popupService.showConfirm(title, message, okText, cancelText, function(ok) {
|
||||
if (!ok) {
|
||||
$scope.sendStatus = '';
|
||||
return;
|
||||
}
|
||||
|
||||
ongoingProcess.set('Comprando Vale-Presente', true, statusChangeHandler);
|
||||
publishAndSign($scope.wallet, createdTx, function() {}, function(err, txSent) {
|
||||
if (err) {
|
||||
ongoingProcess.set('Comprando Vale-Presente', false, statusChangeHandler);
|
||||
showError(gettextCatalog.getString('Could not send transaction'), err);
|
||||
return;
|
||||
}
|
||||
checkTransaction(1, createdTx.giftData);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.showWalletSelector = function() {
|
||||
$scope.walletSelectorTitle = 'Buy from';
|
||||
$scope.showWallets = true;
|
||||
};
|
||||
|
||||
$scope.onWalletSelect = function(wallet) {
|
||||
$scope.wallet = wallet;
|
||||
initialize(wallet);
|
||||
};
|
||||
|
||||
$scope.goBackHome = function() {
|
||||
$scope.sendStatus = '';
|
||||
$ionicHistory.nextViewOptions({
|
||||
disableAnimate: true,
|
||||
historyRoot: true
|
||||
});
|
||||
$ionicHistory.clearHistory();
|
||||
$state.go('tabs.home').then(function() {
|
||||
$ionicHistory.nextViewOptions({
|
||||
disableAnimate: true
|
||||
});
|
||||
$state.transitionTo('tabs.giftcards.mercadoLibre').then(function() {
|
||||
$state.transitionTo('tabs.giftcards.mercadoLibre.cards', {
|
||||
invoiceId: invoiceId
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
});
|
||||
192
src/js/controllers/cashScan.js
Normal file
192
src/js/controllers/cashScan.js
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('cashScanController',
|
||||
function($rootScope, $timeout, $scope, $state, $ionicHistory, gettextCatalog, lodash, ongoingProcess, profileService, walletService, $log, txFormatService, bwcError, pushNotificationsService, bwcService, externalLinkService) {
|
||||
var wallet;
|
||||
var errors = bwcService.getErrors();
|
||||
$scope.error = null;
|
||||
$scope.walletDisabled = '#667';
|
||||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
updateAllWallets();
|
||||
});
|
||||
|
||||
$scope.openRecoveryToolLink = function() {
|
||||
var url = 'https://bitpay.github.io/copay-recovery/';
|
||||
var optIn = true;
|
||||
var title = null;
|
||||
var message = gettextCatalog.getString('Open the recovery tool.');
|
||||
var okText = gettextCatalog.getString('Open');
|
||||
var cancelText = gettextCatalog.getString('Go Back');
|
||||
externalLinkService.open(url, optIn, title, message, okText, cancelText);
|
||||
};
|
||||
|
||||
var goHome = function() {
|
||||
$ionicHistory.nextViewOptions({
|
||||
disableAnimate: true,
|
||||
historyRoot: true
|
||||
});
|
||||
$ionicHistory.clearHistory();
|
||||
$state.go('tabs.settings').then(function() {
|
||||
$state.transitionTo('tabs.home');
|
||||
});
|
||||
}
|
||||
|
||||
var updateAllWallets = function() {
|
||||
var walletsBTC = profileService.getWallets({
|
||||
coin: 'btc',
|
||||
onlyComplete: true,
|
||||
network: 'livenet'
|
||||
});
|
||||
|
||||
// Filter out already duplicated wallets
|
||||
var walletsBCH = profileService.getWallets({
|
||||
coin: 'bch',
|
||||
network: 'livenet'
|
||||
});
|
||||
var xPubKeyIndex = lodash.indexBy(walletsBCH, "credentials.xPubKey");
|
||||
|
||||
walletsBTC = lodash.filter(walletsBTC, function(w) {
|
||||
return !xPubKeyIndex[w.credentials.xPubKey];
|
||||
});
|
||||
|
||||
var availableWallets = [];
|
||||
var nonEligibleWallets = [];
|
||||
|
||||
lodash.each(walletsBTC, function(w) {
|
||||
if (w.credentials.derivationStrategy != 'BIP44') {
|
||||
w.excludeReason = gettextCatalog.getString('Non BIP44 wallet');
|
||||
nonEligibleWallets.push(w);
|
||||
} else if (!w.canSign()) {
|
||||
w.excludeReason = gettextCatalog.getString('Read only wallet');
|
||||
nonEligibleWallets.push(w);
|
||||
} else if (w.needsBackup) {
|
||||
w.excludeReason = gettextCatalog.getString('Backup needed');
|
||||
nonEligibleWallets.push(w);
|
||||
} else {
|
||||
availableWallets.push(w);
|
||||
}
|
||||
});
|
||||
|
||||
$scope.availableWallets = availableWallets;
|
||||
$scope.nonEligibleWallets = nonEligibleWallets;
|
||||
|
||||
var i = availableWallets.length;
|
||||
var j = 0;
|
||||
lodash.each(availableWallets, function(wallet) {
|
||||
walletService.getBalance(wallet, {
|
||||
coin: 'bch'
|
||||
}, function(err, balance) {
|
||||
if (err) {
|
||||
wallet.error = (err === 'WALLET_NOT_REGISTERED') ? gettextCatalog.getString('Wallet not registered') : bwcError.msg(err);
|
||||
$log.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
wallet.error = null;
|
||||
wallet.bchBalance = txFormatService.formatAmountStr('bch', balance.availableAmount);
|
||||
if (++j == i) {
|
||||
//Done
|
||||
$timeout(function() {
|
||||
$rootScope.$apply();
|
||||
}, 10);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.duplicate = function(wallet) {
|
||||
$scope.error = null;
|
||||
$log.debug('Duplicating wallet for BCH:' + wallet.id + ':' + wallet.name);
|
||||
|
||||
var opts = {};
|
||||
opts.name = wallet.name + '[BCH]';
|
||||
opts.m = wallet.m;
|
||||
opts.n = wallet.n;
|
||||
opts.myName = wallet.credentials.copayerName;
|
||||
opts.networkName = wallet.network;
|
||||
opts.coin = 'bch';
|
||||
opts.walletPrivKey = wallet.credentials.walletPrivKey;
|
||||
opts.compliantDerivation = wallet.credentials.compliantDerivation;
|
||||
|
||||
|
||||
function setErr(err, cb) {
|
||||
|
||||
if (!cb) cb = function() {};
|
||||
|
||||
$scope.error = bwcError.cb(err, gettextCatalog.getString('Could not duplicate'), function() {
|
||||
return cb(err);
|
||||
});
|
||||
$timeout(function() {
|
||||
$rootScope.$apply();
|
||||
}, 10);
|
||||
}
|
||||
|
||||
function importOrCreate(cb) {
|
||||
walletService.getStatus(wallet, {}, function(err, status) {
|
||||
if (err) return cb(err);
|
||||
|
||||
opts.singleAddress = status.wallet.singleAddress;
|
||||
|
||||
// first try to import
|
||||
profileService.importExtendedPrivateKey(opts.extendedPrivateKey, opts, function(err, newWallet) {
|
||||
if (err && !(err instanceof errors.NOT_AUTHORIZED)) {
|
||||
return setErr(err, cb);
|
||||
}
|
||||
if (err) {
|
||||
// create and store a wallet
|
||||
return profileService.createWallet(opts, function(err, newWallet) {
|
||||
if (err) return setErr(err, cb);
|
||||
return cb(null, newWallet, true);
|
||||
});
|
||||
}
|
||||
return cb(null, newWallet);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Multisig wallets? add Copayers
|
||||
function addCopayers(newWallet, isNew, cb) {
|
||||
if (!isNew) return cb();
|
||||
if (wallet.n == 1) return cb();
|
||||
|
||||
$log.info('Adding copayers for BCH wallet config:' + wallet.m + '-' + wallet.n);
|
||||
|
||||
walletService.copyCopayers(wallet, newWallet, function(err) {
|
||||
if (err) return setErr(err, cb);
|
||||
|
||||
return cb();
|
||||
});
|
||||
};
|
||||
|
||||
walletService.getKeys(wallet, function(err, keys) {
|
||||
if (err) {
|
||||
$scope.error = err;
|
||||
return $timeout(function() {
|
||||
$rootScope.$apply();
|
||||
}, 10);
|
||||
}
|
||||
opts.extendedPrivateKey = keys.xPrivKey;
|
||||
ongoingProcess.set('duplicatingWallet', true);
|
||||
importOrCreate(function(err, newWallet, isNew) {
|
||||
if (err) {
|
||||
ongoingProcess.set('duplicatingWallet', false);
|
||||
return;
|
||||
}
|
||||
walletService.updateRemotePreferences(newWallet);
|
||||
pushNotificationsService.updateSubscription(newWallet);
|
||||
|
||||
addCopayers(newWallet, isNew, function(err) {
|
||||
ongoingProcess.set('duplicatingWallet', false);
|
||||
if (err)
|
||||
return setErr(err);
|
||||
|
||||
if (isNew)
|
||||
walletService.startScan(newWallet, function() {});
|
||||
|
||||
goHome();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('confirmController', function($rootScope, $scope, $interval, $filter, $timeout, $ionicScrollDelegate, gettextCatalog, walletService, platformInfo, lodash, configService, rateService, $stateParams, $window, $state, $log, profileService, bitcore, txFormatService, ongoingProcess, $ionicModal, popupService, $ionicHistory, $ionicConfig, payproService, feeService, bwcError, txConfirmNotification) {
|
||||
angular.module('copayApp.controllers').controller('confirmController', function($rootScope, $scope, $interval, $filter, $timeout, $ionicScrollDelegate, gettextCatalog, walletService, platformInfo, lodash, configService, $stateParams, $window, $state, $log, profileService, bitcore, bitcoreCash, txFormatService, ongoingProcess, $ionicModal, popupService, $ionicHistory, $ionicConfig, payproService, feeService, bwcError, txConfirmNotification, externalLinkService) {
|
||||
|
||||
var countDown = null;
|
||||
var CONFIRM_LIMIT_USD = 20;
|
||||
|
|
@ -28,7 +28,7 @@ angular.module('copayApp.controllers').controller('confirmController', function(
|
|||
function refresh() {
|
||||
$timeout(function() {
|
||||
$scope.$apply();
|
||||
}, 1);
|
||||
}, 10);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -58,9 +58,10 @@ angular.module('copayApp.controllers').controller('confirmController', function(
|
|||
});
|
||||
};
|
||||
|
||||
function setNoWallet(msg) {
|
||||
function setNoWallet(msg, criticalError) {
|
||||
$scope.wallet = null;
|
||||
$scope.noWalletMessage = msg;
|
||||
$scope.criticalError = criticalError;
|
||||
$log.warn('Not ready to make the payment:' + msg);
|
||||
$timeout(function() {
|
||||
$scope.$apply();
|
||||
|
|
@ -69,18 +70,19 @@ angular.module('copayApp.controllers').controller('confirmController', function(
|
|||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
|
||||
function setWalletSelector(network, minAmount, cb) {
|
||||
function setWalletSelector(coin, network, minAmount, cb) {
|
||||
|
||||
// no min amount? (sendMax) => look for no empty wallets
|
||||
minAmount = minAmount || 1;
|
||||
|
||||
$scope.wallets = profileService.getWallets({
|
||||
onlyComplete: true,
|
||||
network: network
|
||||
network: network,
|
||||
coin: coin
|
||||
});
|
||||
|
||||
if (!$scope.wallets || !$scope.wallets.length) {
|
||||
setNoWallet(gettextCatalog.getString('No wallets available'));
|
||||
setNoWallet(gettextCatalog.getString('No wallets available'), true);
|
||||
return cb();
|
||||
}
|
||||
|
||||
|
|
@ -109,7 +111,7 @@ angular.module('copayApp.controllers').controller('confirmController', function(
|
|||
return cb('Could not update any wallet');
|
||||
|
||||
if (lodash.isEmpty(filteredWallets)) {
|
||||
setNoWallet(gettextCatalog.getString('Insufficient funds'));
|
||||
setNoWallet(gettextCatalog.getString('Insufficient funds'), true);
|
||||
}
|
||||
$scope.wallets = lodash.clone(filteredWallets);
|
||||
return cb();
|
||||
|
|
@ -120,6 +122,30 @@ angular.module('copayApp.controllers').controller('confirmController', function(
|
|||
|
||||
// Setup $scope
|
||||
|
||||
var B = data.stateParams.coin == 'bch' ? bitcoreCash : bitcore;
|
||||
var networkName;
|
||||
try {
|
||||
networkName = (new B.Address(data.stateParams.toAddress)).network.name;
|
||||
} catch(e) {
|
||||
var message = gettextCatalog.getString('Copay only supports Bitcoin Cash using new version numbers addresses');
|
||||
var backText = gettextCatalog.getString('Go back');
|
||||
var learnText = gettextCatalog.getString('Learn more');
|
||||
popupService.showConfirm(null, message, backText, learnText, function(back) {
|
||||
$ionicHistory.nextViewOptions({
|
||||
disableAnimate: true,
|
||||
historyRoot: true
|
||||
});
|
||||
$state.go('tabs.send').then(function() {
|
||||
$ionicHistory.clearHistory();
|
||||
if (!back) {
|
||||
var url = 'https://support.bitpay.com/hc/en-us/articles/115004671663';
|
||||
externalLinkService.open(url);
|
||||
}
|
||||
});
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Grab stateParams
|
||||
tx = {
|
||||
toAmount: parseInt(data.stateParams.toAmount),
|
||||
|
|
@ -136,33 +162,32 @@ angular.module('copayApp.controllers').controller('confirmController', function(
|
|||
toName: data.stateParams.toName,
|
||||
toEmail: data.stateParams.toEmail,
|
||||
toColor: data.stateParams.toColor,
|
||||
network: (new bitcore.Address(data.stateParams.toAddress)).network.name,
|
||||
network: networkName,
|
||||
coin: data.stateParams.coin,
|
||||
txp: {},
|
||||
};
|
||||
|
||||
if (tx.coin && tx.coin == 'bch') tx.feeLevel = 'normal';
|
||||
|
||||
// Other Scope vars
|
||||
$scope.isCordova = isCordova;
|
||||
$scope.isWindowsPhoneApp = isWindowsPhoneApp;
|
||||
$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) {
|
||||
if (err) {
|
||||
return exitWithError('Could not update wallets');
|
||||
}
|
||||
|
||||
if ($scope.wallets.length > 1) {
|
||||
$scope.showWalletSelector();
|
||||
} else if ($scope.wallets.length) {
|
||||
setWallet($scope.wallets[0], tx);
|
||||
}
|
||||
});
|
||||
setWalletSelector(tx.coin, tx.network, tx.toAmount, function(err) {
|
||||
if (err) {
|
||||
return exitWithError('Could not update wallets');
|
||||
}
|
||||
|
||||
if ($scope.wallets.length > 1) {
|
||||
$scope.showWalletSelector();
|
||||
} else if ($scope.wallets.length) {
|
||||
setWallet($scope.wallets[0], tx);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
|
@ -227,6 +252,7 @@ angular.module('copayApp.controllers').controller('confirmController', function(
|
|||
};
|
||||
|
||||
function updateTx(tx, wallet, opts, cb) {
|
||||
ongoingProcess.set('calculatingFee', true);
|
||||
|
||||
if (opts.clearCache) {
|
||||
tx.txp = {};
|
||||
|
|
@ -238,10 +264,10 @@ angular.module('copayApp.controllers').controller('confirmController', function(
|
|||
if (!tx.toAmount) return;
|
||||
|
||||
// Amount
|
||||
tx.amountStr = txFormatService.formatAmountStr(tx.toAmount);
|
||||
tx.amountStr = txFormatService.formatAmountStr(wallet.coin, tx.toAmount);
|
||||
tx.amountValueStr = tx.amountStr.split(' ')[0];
|
||||
tx.amountUnitStr = tx.amountStr.split(' ')[1];
|
||||
txFormatService.formatAlternativeStr(tx.toAmount, function(v) {
|
||||
txFormatService.formatAlternativeStr(wallet.coin, tx.toAmount, function(v) {
|
||||
tx.alternativeAmountStr = v;
|
||||
});
|
||||
}
|
||||
|
|
@ -250,19 +276,23 @@ angular.module('copayApp.controllers').controller('confirmController', function(
|
|||
refresh();
|
||||
|
||||
// End of quick refresh, before wallet is selected.
|
||||
if (!wallet) return cb();
|
||||
if (!wallet) {
|
||||
ongoingProcess.set('calculatingFee', false);
|
||||
return cb();
|
||||
}
|
||||
|
||||
feeService.getFeeRate(tx.network, tx.feeLevel, function(err, feeRate) {
|
||||
if (err) return cb(err);
|
||||
feeService.getFeeRate(wallet.coin, tx.network, tx.feeLevel, function(err, feeRate) {
|
||||
if (err) {
|
||||
ongoingProcess.set('calculatingFee', false);
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
if (!usingCustomFee) tx.feeRate = feeRate;
|
||||
tx.feeLevelName = feeService.feeOpts[tx.feeLevel];
|
||||
|
||||
if (!wallet)
|
||||
return cb();
|
||||
|
||||
getSendMaxInfo(lodash.clone(tx), wallet, function(err, sendMaxInfo) {
|
||||
if (err) {
|
||||
ongoingProcess.set('calculatingFee', false);
|
||||
var msg = gettextCatalog.getString('Error getting SendMax information');
|
||||
return setSendError(msg);
|
||||
}
|
||||
|
|
@ -272,6 +302,7 @@ angular.module('copayApp.controllers').controller('confirmController', function(
|
|||
$log.debug('Send max info', sendMaxInfo);
|
||||
|
||||
if (tx.sendMax && sendMaxInfo.amount == 0) {
|
||||
ongoingProcess.set('calculatingFee', false);
|
||||
setNoWallet(gettextCatalog.getString('Insufficient funds'));
|
||||
popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Not enough funds for fee'));
|
||||
return cb('no_funds');
|
||||
|
|
@ -280,20 +311,27 @@ angular.module('copayApp.controllers').controller('confirmController', function(
|
|||
tx.sendMaxInfo = sendMaxInfo;
|
||||
tx.toAmount = tx.sendMaxInfo.amount;
|
||||
updateAmount();
|
||||
showSendMaxWarning(sendMaxInfo);
|
||||
ongoingProcess.set('calculatingFee', false);
|
||||
$timeout(function() {
|
||||
showSendMaxWarning(wallet, sendMaxInfo);
|
||||
}, 200);
|
||||
}
|
||||
|
||||
// txp already generated for this wallet?
|
||||
if (tx.txp[wallet.id]) {
|
||||
ongoingProcess.set('calculatingFee', false);
|
||||
refresh();
|
||||
return cb();
|
||||
}
|
||||
|
||||
getTxp(lodash.clone(tx), wallet, opts.dryRun, function(err, txp) {
|
||||
if (err) return cb(err);
|
||||
ongoingProcess.set('calculatingFee', false);
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
txp.feeStr = txFormatService.formatAmountStr(txp.fee);
|
||||
txFormatService.formatAlternativeStr(txp.fee, function(v) {
|
||||
txp.feeStr = txFormatService.formatAmountStr(wallet.coin, txp.fee);
|
||||
txFormatService.formatAlternativeStr(wallet.coin, txp.fee, function(v) {
|
||||
txp.alternativeFeeStr = v;
|
||||
});
|
||||
|
||||
|
|
@ -321,14 +359,26 @@ angular.module('copayApp.controllers').controller('confirmController', function(
|
|||
}
|
||||
|
||||
function setButtonText(isMultisig, isPayPro) {
|
||||
$scope.buttonText = gettextCatalog.getString(isCordova && !isWindowsPhoneApp ? 'Slide' : 'Click') + ' ';
|
||||
|
||||
if (isPayPro) {
|
||||
$scope.buttonText += gettextCatalog.getString('to pay');
|
||||
if (isCordova && !isWindowsPhoneApp) {
|
||||
$scope.buttonText = gettextCatalog.getString('Slide to pay');
|
||||
} else {
|
||||
$scope.buttonText = gettextCatalog.getString('Click to pay');
|
||||
}
|
||||
} else if (isMultisig) {
|
||||
$scope.buttonText += gettextCatalog.getString('to accept');
|
||||
} else
|
||||
$scope.buttonText += gettextCatalog.getString('to send');
|
||||
if (isCordova && !isWindowsPhoneApp) {
|
||||
$scope.buttonText = gettextCatalog.getString('Slide to accept');
|
||||
} else {
|
||||
$scope.buttonText = gettextCatalog.getString('Click to accept');
|
||||
}
|
||||
} else {
|
||||
if (isCordova && !isWindowsPhoneApp) {
|
||||
$scope.buttonText = gettextCatalog.getString('Slide to send');
|
||||
} else {
|
||||
$scope.buttonText = gettextCatalog.getString('Click to send');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -337,26 +387,26 @@ angular.module('copayApp.controllers').controller('confirmController', function(
|
|||
};
|
||||
|
||||
|
||||
function showSendMaxWarning(sendMaxInfo) {
|
||||
function showSendMaxWarning(wallet, sendMaxInfo) {
|
||||
|
||||
function verifyExcludedUtxos() {
|
||||
var warningMsg = [];
|
||||
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.", {
|
||||
amountBelowFeeStr: txFormatService.formatAmountStr(sendMaxInfo.amountBelowFee)
|
||||
amountBelowFeeStr: txFormatService.formatAmountStr(wallet.coin, sendMaxInfo.amountBelowFee)
|
||||
}));
|
||||
}
|
||||
|
||||
if (sendMaxInfo.utxosAboveMaxSize > 0) {
|
||||
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.coin, sendMaxInfo.amountAboveMaxSize)
|
||||
}));
|
||||
}
|
||||
return warningMsg.join('\n');
|
||||
};
|
||||
|
||||
var msg = gettextCatalog.getString("{{fee}} will be deducted for bitcoin networking fees.", {
|
||||
fee: txFormatService.formatAmountStr(sendMaxInfo.fee)
|
||||
fee: txFormatService.formatAmountStr(wallet.coin, sendMaxInfo.fee)
|
||||
});
|
||||
var warningMsg = verifyExcludedUtxos();
|
||||
|
||||
|
|
@ -422,6 +472,11 @@ angular.module('copayApp.controllers').controller('confirmController', function(
|
|||
|
||||
$scope.wallet = wallet;
|
||||
|
||||
// If select another wallet
|
||||
tx.coin = wallet.coin;
|
||||
tx.feeLevel = wallet.coin == 'bch' ? 'normal' : configFeeLevel;
|
||||
usingCustomFee = null;
|
||||
|
||||
setButtonText(wallet.credentials.m > 1, !!tx.paypro);
|
||||
|
||||
if (tx.paypro)
|
||||
|
|
@ -483,7 +538,7 @@ angular.module('copayApp.controllers').controller('confirmController', function(
|
|||
if (walletService.isEncrypted(wallet))
|
||||
return cb();
|
||||
|
||||
var amountUsd = parseFloat(txFormatService.formatToUSD(txp.amount));
|
||||
var amountUsd = parseFloat(txFormatService.formatToUSD(wallet.coin, txp.amount));
|
||||
if (amountUsd <= CONFIRM_LIMIT_USD)
|
||||
return cb();
|
||||
|
||||
|
|
@ -563,10 +618,13 @@ angular.module('copayApp.controllers').controller('confirmController', function(
|
|||
|
||||
$scope.chooseFeeLevel = function(tx, wallet) {
|
||||
|
||||
if (wallet.coin == 'bch') return;
|
||||
|
||||
var scope = $rootScope.$new(true);
|
||||
scope.network = tx.network;
|
||||
scope.feeLevel = tx.feeLevel;
|
||||
scope.noSave = true;
|
||||
scope.coin = wallet.coin;
|
||||
|
||||
if (usingCustomFee) {
|
||||
scope.customFeePerKB = tx.feeRate;
|
||||
|
|
|
|||
|
|
@ -22,11 +22,16 @@ angular.module('copayApp.controllers').controller('createController',
|
|||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
$scope.formData = {};
|
||||
var defaults = configService.getDefaults();
|
||||
var config = configService.getSync();
|
||||
var tc = $state.current.name == 'tabs.add.create-personal' ? 1 : defaults.wallet.totalCopayers;
|
||||
$scope.formData.account = 1;
|
||||
$scope.formData.bwsurl = defaults.bws.url;
|
||||
$scope.TCValues = lodash.range(2, defaults.limits.totalCopayers + 1);
|
||||
$scope.formData.derivationPath = derivationPathHelper.default;
|
||||
$scope.formData.coin = data.stateParams.coin;
|
||||
|
||||
if (config.cashSupport) $scope.enableCash = true;
|
||||
|
||||
$scope.setTotalCopayers(tc);
|
||||
updateRCSelect(tc);
|
||||
resetPasswordFields();
|
||||
|
|
@ -133,10 +138,11 @@ angular.module('copayApp.controllers').controller('createController',
|
|||
m: $scope.formData.requiredCopayers,
|
||||
n: $scope.formData.totalCopayers,
|
||||
myName: $scope.formData.totalCopayers > 1 ? $scope.formData.myName : null,
|
||||
networkName: $scope.formData.testnetEnabled ? 'testnet' : 'livenet',
|
||||
networkName: $scope.formData.testnetEnabled && $scope.formData.coin != 'bch' ? 'testnet' : 'livenet',
|
||||
bwsurl: $scope.formData.bwsurl,
|
||||
singleAddress: $scope.formData.singleAddressEnabled,
|
||||
walletPrivKey: $scope.formData._walletPrivKey, // Only for testing
|
||||
coin: $scope.formData.coin
|
||||
};
|
||||
|
||||
var setSeed = $scope.formData.seedSource.id == 'set';
|
||||
|
|
@ -170,6 +176,11 @@ angular.module('copayApp.controllers').controller('createController',
|
|||
}
|
||||
|
||||
if ($scope.formData.seedSource.id == walletService.externalSource.ledger.id || $scope.formData.seedSource.id == walletService.externalSource.trezor.id || $scope.formData.seedSource.id == walletService.externalSource.intelTEE.id) {
|
||||
if ($scope.formData.coin == 'bch') {
|
||||
popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Hardware wallets are not yet supported with Bitcoin Cash'));
|
||||
return;
|
||||
}
|
||||
|
||||
var account = $scope.formData.account;
|
||||
if (!account || account < 1) {
|
||||
popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Invalid account number'));
|
||||
|
|
|
|||
|
|
@ -8,6 +8,10 @@ angular.module('copayApp.controllers').controller('customAmountController', func
|
|||
});
|
||||
};
|
||||
|
||||
var setProtocolHandler = function() {
|
||||
$scope.protocolHandler = walletService.getProtocolHandler($scope.wallet);
|
||||
}
|
||||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
var walletId = data.stateParams.id;
|
||||
|
||||
|
|
@ -15,21 +19,25 @@ angular.module('copayApp.controllers').controller('customAmountController', func
|
|||
showErrorAndBack('Error', 'No wallet selected');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$scope.showShareButton = platformInfo.isCordova ? (platformInfo.isIOS ? 'iOS' : 'Android') : null;
|
||||
|
||||
$scope.wallet = profileService.getWallet(walletId);
|
||||
|
||||
setProtocolHandler();
|
||||
|
||||
walletService.getAddress($scope.wallet, false, function(err, addr) {
|
||||
if (!addr) {
|
||||
showErrorAndBack('Error', 'Could not get the address');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$scope.address = addr;
|
||||
|
||||
|
||||
$scope.coin = data.stateParams.coin;
|
||||
var parsedAmount = txFormatService.parseAmount(
|
||||
data.stateParams.amount,
|
||||
$scope.wallet.coin,
|
||||
data.stateParams.amount,
|
||||
data.stateParams.currency);
|
||||
|
||||
// Amount in USD or BTC
|
||||
|
|
@ -37,17 +45,17 @@ angular.module('copayApp.controllers').controller('customAmountController', func
|
|||
var currency = parsedAmount.currency;
|
||||
$scope.amountUnitStr = parsedAmount.amountUnitStr;
|
||||
|
||||
if (currency != 'BTC') {
|
||||
// Convert to BTC
|
||||
if (currency != 'BTC' && currency != 'BCH') {
|
||||
// Convert to BTC or BCH
|
||||
var config = configService.getSync().wallet.settings;
|
||||
var amountUnit = txFormatService.satToUnit(parsedAmount.amountSat);
|
||||
var btcParsedAmount = txFormatService.parseAmount(amountUnit, config.unitName);
|
||||
|
||||
var btcParsedAmount = txFormatService.parseAmount($scope.wallet.coin, amountUnit, $scope.wallet.coin);
|
||||
|
||||
$scope.amountBtc = btcParsedAmount.amount;
|
||||
$scope.altAmountStr = btcParsedAmount.amountUnitStr;
|
||||
} else {
|
||||
$scope.amountBtc = amount; // BTC
|
||||
$scope.altAmountStr = txFormatService.formatAlternativeStr(parsedAmount.amountSat);
|
||||
$scope.amountBtc = amount; // BTC or BCH
|
||||
$scope.altAmountStr = txFormatService.formatAlternativeStr($scope.wallet.coin, parsedAmount.amountSat);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -61,12 +69,16 @@ angular.module('copayApp.controllers').controller('customAmountController', func
|
|||
|
||||
$scope.shareAddress = function() {
|
||||
if (!platformInfo.isCordova) return;
|
||||
var data = 'bitcoin:' + $scope.address + '?amount=' + $scope.amountBtc;
|
||||
var protocol = 'bitcoin';
|
||||
if ($scope.wallet.coin == 'bch') protocol += 'cash';
|
||||
var data = protocol + ':' + $scope.address + '?amount=' + $scope.amountBtc;
|
||||
window.plugins.socialsharing.share(data, null, null, null);
|
||||
}
|
||||
|
||||
$scope.copyToClipboard = function() {
|
||||
return 'bitcoin:' + $scope.address + '?amount=' + $scope.amountBtc;
|
||||
var protocol = 'bitcoin';
|
||||
if ($scope.wallet.coin == 'bch') protocol += 'cash';
|
||||
return protocol + ':' + $scope.address + '?amount=' + $scope.amountBtc;
|
||||
};
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ angular.module('copayApp.controllers').controller('importController',
|
|||
|
||||
var reader = new FileReader();
|
||||
var defaults = configService.getDefaults();
|
||||
var config = configService.getSync();
|
||||
var errors = bwcService.getErrors();
|
||||
|
||||
$scope.init = function() {
|
||||
|
|
@ -15,9 +16,14 @@ angular.module('copayApp.controllers').controller('importController',
|
|||
$scope.formData.bwsurl = defaults.bws.url;
|
||||
$scope.formData.derivationPath = derivationPathHelper.default;
|
||||
$scope.formData.account = 1;
|
||||
$scope.formData.coin = $stateParams.coin;
|
||||
$scope.importErr = false;
|
||||
$scope.isCopay = appConfigService.name == 'copay';
|
||||
$scope.fromHardwareWallet = { value: false };
|
||||
$scope.fromHardwareWallet = {
|
||||
value: false
|
||||
};
|
||||
|
||||
if (config.cashSupport) $scope.enableCash = true;
|
||||
|
||||
if ($stateParams.code)
|
||||
$scope.processWalletInfo($stateParams.code);
|
||||
|
|
@ -59,6 +65,15 @@ angular.module('copayApp.controllers').controller('importController',
|
|||
});
|
||||
};
|
||||
|
||||
$scope.switchTestnetOff = function() {
|
||||
$scope.formData.testnetEnabled = false;
|
||||
$scope.setDerivationPath();
|
||||
$scope.resizeView();
|
||||
$timeout(function() {
|
||||
$scope.$apply();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.processWalletInfo = function(code) {
|
||||
if (!code) return;
|
||||
|
||||
|
|
@ -203,6 +218,7 @@ angular.module('copayApp.controllers').controller('importController',
|
|||
if (evt.target.readyState == FileReader.DONE) { // DONE == 2
|
||||
var opts = {};
|
||||
opts.bwsurl = $scope.formData.bwsurl;
|
||||
opts.coin = $scope.formData.coin;
|
||||
_importBlob(evt.target.result, opts);
|
||||
}
|
||||
}
|
||||
|
|
@ -228,6 +244,7 @@ angular.module('copayApp.controllers').controller('importController',
|
|||
} else {
|
||||
var opts = {};
|
||||
opts.bwsurl = $scope.formData.bwsurl;
|
||||
opts.coin = $scope.formData.coin;
|
||||
_importBlob(backupText, opts);
|
||||
}
|
||||
};
|
||||
|
|
@ -253,6 +270,7 @@ angular.module('copayApp.controllers').controller('importController',
|
|||
opts.account = pathData.account;
|
||||
opts.networkName = pathData.networkName;
|
||||
opts.derivationStrategy = pathData.derivationStrategy;
|
||||
opts.coin = $scope.formData.coin;
|
||||
|
||||
var words = $scope.formData.words || null;
|
||||
|
||||
|
|
@ -279,7 +297,7 @@ angular.module('copayApp.controllers').controller('importController',
|
|||
$log.warn('This wont work for Intel TEE wallets');
|
||||
|
||||
var id = $scope.formData.seedSourceAll.id;
|
||||
var isMultisig = opts.derivationStrategy =='BIP48';
|
||||
var isMultisig = opts.derivationStrategy == 'BIP48';
|
||||
var account = opts.account;
|
||||
opts.entropySourcePath = 'm/' + hwWallet.getEntropyPath(id, isMultisig, account);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,11 +5,14 @@ angular.module('copayApp.controllers').controller('joinController',
|
|||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
var defaults = configService.getDefaults();
|
||||
var config = configService.getSync();
|
||||
$scope.formData = {};
|
||||
$scope.formData.bwsurl = defaults.bws.url;
|
||||
$scope.formData.derivationPath = derivationPathHelper.default;
|
||||
$scope.formData.account = 1;
|
||||
$scope.formData.secret = null;
|
||||
$scope.formData.coin = data.stateParams.coin;
|
||||
if (config.cashSupport) $scope.enableCash = true;
|
||||
resetPasswordFields();
|
||||
updateSeedSourceSelect();
|
||||
});
|
||||
|
|
@ -103,7 +106,8 @@ angular.module('copayApp.controllers').controller('joinController',
|
|||
var opts = {
|
||||
secret: $scope.formData.secret,
|
||||
myName: $scope.formData.myName,
|
||||
bwsurl: $scope.formData.bwsurl
|
||||
bwsurl: $scope.formData.bwsurl,
|
||||
coin: $scope.formData.coin
|
||||
}
|
||||
|
||||
var setSeed = $scope.formData.seedSource.id == 'set';
|
||||
|
|
@ -137,6 +141,11 @@ angular.module('copayApp.controllers').controller('joinController',
|
|||
}
|
||||
|
||||
if ($scope.formData.seedSource.id == walletService.externalSource.ledger.id || $scope.formData.seedSource.id == walletService.externalSource.trezor.id || $scope.formData.seedSource.id == walletService.externalSource.intelTEE.id) {
|
||||
if ($scope.formData.coin == 'bch') {
|
||||
popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Hardware wallets are not yet supported with Bitcoin Cash'));
|
||||
return;
|
||||
}
|
||||
|
||||
var account = $scope.formData.account;
|
||||
if (!account || account < 1) {
|
||||
popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Invalid account number'));
|
||||
|
|
|
|||
24
src/js/controllers/mercadoLibre.js
Normal file
24
src/js/controllers/mercadoLibre.js
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('mercadoLibreController',
|
||||
function($scope, $timeout, $log, mercadoLibreService, externalLinkService, popupService) {
|
||||
|
||||
$scope.openExternalLink = function(url) {
|
||||
externalLinkService.open(url);
|
||||
};
|
||||
|
||||
var init = function() {
|
||||
mercadoLibreService.getPendingGiftCards(function(err, gcds) {
|
||||
if (err) $log.error(err);
|
||||
$scope.giftCards = gcds;
|
||||
$timeout(function() {
|
||||
$scope.$digest();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
$scope.network = mercadoLibreService.getNetwork();
|
||||
init();
|
||||
});
|
||||
});
|
||||
100
src/js/controllers/mercadoLibreCards.js
Normal file
100
src/js/controllers/mercadoLibreCards.js
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('mercadoLibreCardsController',
|
||||
function($scope, $timeout, $ionicModal, $log, $ionicScrollDelegate, lodash, mercadoLibreService, platformInfo, externalLinkService, popupService, ongoingProcess) {
|
||||
|
||||
$scope.openExternalLink = function(url) {
|
||||
externalLinkService.open(url);
|
||||
};
|
||||
|
||||
var updateGiftCards = function(cb) {
|
||||
mercadoLibreService.getPendingGiftCards(function(err, gcds) {
|
||||
if (err) {
|
||||
popupService.showAlert('Could not get gift cards', err);
|
||||
if (cb) return cb();
|
||||
else return;
|
||||
}
|
||||
$scope.giftCards = gcds;
|
||||
$timeout(function() {
|
||||
$scope.$digest();
|
||||
$ionicScrollDelegate.resize();
|
||||
if (cb) return cb();
|
||||
}, 100);
|
||||
});
|
||||
};
|
||||
|
||||
$scope.updatePendingGiftCards = lodash.debounce(function() {
|
||||
updateGiftCards(function() {
|
||||
var index = 0;
|
||||
var gcds = $scope.giftCards;
|
||||
lodash.forEach(gcds, function(dataFromStorage) {
|
||||
if (dataFromStorage.status == 'PENDING') {
|
||||
$log.debug("Creating / Updating gift card");
|
||||
|
||||
mercadoLibreService.createGiftCard(dataFromStorage, function(err, giftCard) {
|
||||
|
||||
if (err) {
|
||||
popupService.showAlert('Error creating gift card', err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (giftCard.status != 'PENDING') {
|
||||
var newData = {};
|
||||
|
||||
if (!giftCard.status) dataFromStorage.status = null; // Fix error from server
|
||||
|
||||
var cardStatus = giftCard.cardStatus;
|
||||
if (cardStatus && (cardStatus != 'active' && cardStatus != 'inactive' && cardStatus != 'expired'))
|
||||
giftCard.status = 'FAILURE';
|
||||
|
||||
lodash.merge(newData, dataFromStorage, giftCard);
|
||||
|
||||
mercadoLibreService.savePendingGiftCard(newData, null, function(err) {
|
||||
$log.debug("Saving new gift card");
|
||||
updateGiftCards();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
}, 1000, {
|
||||
'leading': true
|
||||
});
|
||||
|
||||
$scope.openCardModal = function(card) {
|
||||
$scope.card = card;
|
||||
|
||||
$ionicModal.fromTemplateUrl('views/modals/mercadolibre-card-details.html', {
|
||||
scope: $scope
|
||||
}).then(function(modal) {
|
||||
$scope.mercadoLibreCardDetailsModal = modal;
|
||||
$scope.mercadoLibreCardDetailsModal.show();
|
||||
});
|
||||
|
||||
$scope.$on('modal.hidden', function() {
|
||||
$scope.updatePendingGiftCards();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
$scope.invoiceId = data.stateParams.invoiceId;
|
||||
updateGiftCards(function() {
|
||||
if ($scope.invoiceId) {
|
||||
var card = lodash.find($scope.giftCards, {
|
||||
invoiceId: $scope.invoiceId
|
||||
});
|
||||
if (lodash.isEmpty(card)) {
|
||||
popupService.showAlert(null, 'Card not found');
|
||||
return;
|
||||
}
|
||||
$scope.openCardModal(card);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$scope.$on("$ionicView.afterEnter", function(event, data) {
|
||||
$scope.updatePendingGiftCards();
|
||||
});
|
||||
});
|
||||
|
|
@ -18,14 +18,14 @@ angular.module('copayApp.controllers').controller('feeLevelsController', functio
|
|||
var value = lodash.find($scope.feeLevels[$scope.network], {
|
||||
level: 'superEconomy'
|
||||
});
|
||||
return parseInt((value.feePerKB / 1000).toFixed());
|
||||
return parseInt((value.feePerKb / 1000).toFixed());
|
||||
};
|
||||
|
||||
var getMaxRecommended = function() {
|
||||
var value = lodash.find($scope.feeLevels[$scope.network], {
|
||||
level: 'urgent'
|
||||
});
|
||||
return parseInt((value.feePerKB / 1000).toFixed());
|
||||
return parseInt((value.feePerKb / 1000).toFixed());
|
||||
};
|
||||
|
||||
$scope.ok = function() {
|
||||
|
|
@ -61,7 +61,7 @@ angular.module('copayApp.controllers').controller('feeLevelsController', functio
|
|||
// If no custom fee
|
||||
if (value) {
|
||||
$scope.customFeePerKB = null;
|
||||
$scope.feePerSatByte = (value.feePerKB / 1000).toFixed();
|
||||
$scope.feePerSatByte = (value.feePerKb / 1000).toFixed();
|
||||
$scope.avgConfirmationTime = value.nbBlocks * 10;
|
||||
} else {
|
||||
$scope.avgConfirmationTime = null;
|
||||
|
|
@ -102,7 +102,7 @@ angular.module('copayApp.controllers').controller('feeLevelsController', functio
|
|||
|
||||
$scope.feeOpts = feeService.feeOpts;
|
||||
$scope.loadingFee = true;
|
||||
feeService.getFeeLevels(function(err, levels) {
|
||||
feeService.getFeeLevels($scope.coin, function(err, levels) {
|
||||
$scope.loadingFee = false;
|
||||
if (err || lodash.isEmpty(levels)) {
|
||||
showErrorAndClose(null, err);
|
||||
|
|
|
|||
21
src/js/controllers/modals/mercadoLibreCardDetails.js
Normal file
21
src/js/controllers/modals/mercadoLibreCardDetails.js
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('mercadoLibreCardDetailsController', function($scope, mercadoLibreService, externalLinkService) {
|
||||
|
||||
$scope.remove = function() {
|
||||
mercadoLibreService.savePendingGiftCard($scope.card, {
|
||||
remove: true
|
||||
}, function(err) {
|
||||
$scope.close();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.close = function() {
|
||||
$scope.mercadoLibreCardDetailsModal.hide();
|
||||
};
|
||||
|
||||
$scope.openExternalLink = function(url) {
|
||||
externalLinkService.open(url);
|
||||
};
|
||||
|
||||
});
|
||||
|
|
@ -23,7 +23,7 @@ angular.module('copayApp.controllers').controller('txpDetailsController', functi
|
|||
};
|
||||
|
||||
function displayFeeValues() {
|
||||
txFormatService.formatAlternativeStr($scope.tx.fee, function(v) {
|
||||
txFormatService.formatAlternativeStr($scope.wallet.coin, $scope.tx.fee, function(v) {
|
||||
$scope.tx.feeFiatStr = v;
|
||||
});
|
||||
$scope.tx.feeRateStr = ($scope.tx.fee / ($scope.tx.amount + $scope.tx.fee) * 100).toFixed(2) + '%';
|
||||
|
|
@ -31,17 +31,23 @@ angular.module('copayApp.controllers').controller('txpDetailsController', functi
|
|||
};
|
||||
|
||||
function applyButtonText() {
|
||||
$scope.buttonText = $scope.isCordova && !$scope.isWindowsPhoneApp ? gettextCatalog.getString('Slide') + ' ' : gettextCatalog.getString('Click') + ' ';
|
||||
|
||||
var lastSigner = lodash.filter($scope.tx.actions, {
|
||||
type: 'accept'
|
||||
}).length == $scope.tx.requiredSignatures - 1;
|
||||
|
||||
if (lastSigner) {
|
||||
$scope.buttonText += gettextCatalog.getString('to send');
|
||||
if ($scope.isCordova && !$scope.isWindowsPhoneApp) {
|
||||
$scope.buttonText = gettextCatalog.getString('Slide to send');
|
||||
} else {
|
||||
$scope.buttonText = gettextCatalog.getString('Click to send');
|
||||
}
|
||||
$scope.successText = gettextCatalog.getString('Payment Sent');
|
||||
} else {
|
||||
$scope.buttonText += gettextCatalog.getString('to accept');
|
||||
if ($scope.isCordova && !$scope.isWindowsPhoneApp) {
|
||||
$scope.buttonText = gettextCatalog.getString('Slide to accept');
|
||||
} else {
|
||||
$scope.buttonText = gettextCatalog.getString('Click to accept');
|
||||
}
|
||||
$scope.successText = gettextCatalog.getString('Payment Accepted');
|
||||
}
|
||||
};
|
||||
|
|
@ -219,7 +225,7 @@ angular.module('copayApp.controllers').controller('txpDetailsController', functi
|
|||
copayerId: $scope.wallet.credentials.copayerId
|
||||
});
|
||||
|
||||
$scope.tx = txFormatService.processTx(tx);
|
||||
$scope.tx = txFormatService.processTx($scope.wallet.coin, tx);
|
||||
|
||||
if (!action && tx.status == 'pending')
|
||||
$scope.tx.pendingForUs = true;
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ angular.module('copayApp.controllers').controller('tourController',
|
|||
rateService.whenAvailable(function() {
|
||||
var localCurrency = 'USD';
|
||||
var btcAmount = 1;
|
||||
var rate = rateService.toFiat(btcAmount * 1e8, localCurrency);
|
||||
var rate = rateService.toFiat(btcAmount * 1e8, localCurrency, 'btc');
|
||||
$scope.localCurrencySymbol = '$';
|
||||
$scope.localCurrencyPerBtc = $filter('formatFiatAmount')(parseFloat(rate.toFixed(2), 10));
|
||||
$timeout(function() {
|
||||
|
|
|
|||
|
|
@ -45,8 +45,7 @@ angular.module('copayApp.controllers').controller('paperWalletController',
|
|||
$scope.balanceSat = balance;
|
||||
if ($scope.balanceSat <= 0)
|
||||
popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Not funds found'));
|
||||
var config = configService.getSync().wallet.settings;
|
||||
$scope.balance = txFormatService.formatAmount(balance) + ' ' + config.unitName;
|
||||
$scope.balance = txFormatService.formatAmountStr($scope.wallet.coin, balance);
|
||||
}
|
||||
$scope.$apply();
|
||||
});
|
||||
|
|
@ -60,9 +59,9 @@ angular.module('copayApp.controllers').controller('paperWalletController',
|
|||
$scope.wallet.buildTxFromPrivateKey($scope.privateKey, destinationAddress, null, function(err, testTx) {
|
||||
if (err) return cb(err);
|
||||
var rawTxLength = testTx.serialize().length;
|
||||
feeService.getCurrentFeeRate('livenet', function(err, feePerKB) {
|
||||
feeService.getCurrentFeeRate('btc', 'livenet', function(err, feePerKb) {
|
||||
var opts = {};
|
||||
opts.fee = Math.round((feePerKB * rawTxLength) / 2000);
|
||||
opts.fee = Math.round((feePerKb * rawTxLength) / 2000);
|
||||
$scope.wallet.buildTxFromPrivateKey($scope.privateKey, destinationAddress, opts, function(err, tx) {
|
||||
if (err) return cb(err);
|
||||
$scope.wallet.broadcastRawTx({
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('preferencesController',
|
||||
function($scope, $rootScope, $timeout, $log, $ionicHistory, configService, profileService, fingerprintService, walletService, platformInfo) {
|
||||
function($scope, $rootScope, $timeout, $log, $ionicHistory, configService, profileService, fingerprintService, walletService, platformInfo, externalLinkService, gettextCatalog) {
|
||||
var wallet;
|
||||
var walletId;
|
||||
|
||||
|
|
@ -58,6 +58,16 @@ angular.module('copayApp.controllers').controller('preferencesController',
|
|||
}
|
||||
};
|
||||
|
||||
$scope.openWikiSpendingPassword = function() {
|
||||
var url = 'https://github.com/bitpay/copay/wiki/COPAY---FAQ#what-the-spending-password-does';
|
||||
var optIn = true;
|
||||
var title = null;
|
||||
var message = gettextCatalog.getString('Read more in our Wiki');
|
||||
var okText = gettextCatalog.getString('Open');
|
||||
var cancelText = gettextCatalog.getString('Go Back');
|
||||
externalLinkService.open(url, optIn, title, message, okText, cancelText);
|
||||
};
|
||||
|
||||
$scope.touchIdChange = function() {
|
||||
var newStatus = $scope.touchIdEnabled.value;
|
||||
walletService.setTouchId(wallet, !!newStatus, function(err) {
|
||||
|
|
|
|||
|
|
@ -43,8 +43,9 @@ angular.module('copayApp.controllers').controller('preferencesAltCurrencyControl
|
|||
$scope.findCurrency = function(search) {
|
||||
if (!search) init();
|
||||
$scope.altCurrencyList = lodash.filter(completeAlternativeList, function(item) {
|
||||
var val = item.name;
|
||||
return lodash.includes(val.toLowerCase(), search.toLowerCase());
|
||||
var val = item.name
|
||||
var val2 = item.isoCode;
|
||||
return lodash.includes(val.toLowerCase(), search.toLowerCase()) || lodash.includes(val2.toLowerCase(), search.toLowerCase());
|
||||
});
|
||||
$timeout(function() {
|
||||
$scope.$apply();
|
||||
|
|
|
|||
42
src/js/controllers/preferencesCash.js
Normal file
42
src/js/controllers/preferencesCash.js
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('preferencesCashController', function($scope, $log, $timeout, appConfigService, configService, gettextCatalog, externalLinkService) {
|
||||
var updateConfig = function() {
|
||||
|
||||
var config = configService.getSync();
|
||||
$scope.appName = appConfigService.nameCase;
|
||||
|
||||
$scope.cashSupport = {
|
||||
value: config.cashSupport
|
||||
};
|
||||
|
||||
$timeout(function() {
|
||||
$scope.$apply();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.cashSupportChange = function() {
|
||||
var opts = {
|
||||
cashSupport: $scope.cashSupport.value
|
||||
};
|
||||
configService.set(opts, function(err) {
|
||||
if (err) $log.debug(err);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
$scope.openBitcoinCashWeb = function() {
|
||||
var url = 'https://www.bitcoincash.org/';
|
||||
var optIn = true;
|
||||
var title = null;
|
||||
var message = gettextCatalog.getString('Open bitcoincash.org?');
|
||||
var okText = gettextCatalog.getString('Open');
|
||||
var cancelText = gettextCatalog.getString('Go Back');
|
||||
externalLinkService.open(url, optIn, title, message, okText, cancelText);
|
||||
};
|
||||
|
||||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
updateConfig();
|
||||
});
|
||||
});
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
angular.module('copayApp.controllers').controller('preferencesDeleteWalletController',
|
||||
function($scope, $ionicHistory, gettextCatalog, lodash, profileService, $state, ongoingProcess, popupService, pushNotificationsService) {
|
||||
|
||||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
if (!data.stateParams || !data.stateParams.walletId) {
|
||||
popupService.showAlert(null, gettextCatalog.getString('No wallet selected'), function() {
|
||||
|
|
@ -17,8 +17,7 @@ angular.module('copayApp.controllers').controller('preferencesDeleteWalletContro
|
|||
});
|
||||
return;
|
||||
}
|
||||
$scope.alias = lodash.isEqual($scope.wallet.name, $scope.wallet.credentials.walletName) ? null : $scope.wallet.name + ' ';
|
||||
$scope.walletName = $scope.wallet.credentials.walletName;
|
||||
$scope.walletName = $scope.wallet.name;
|
||||
});
|
||||
|
||||
$scope.showDeletePopup = function() {
|
||||
|
|
|
|||
|
|
@ -32,11 +32,12 @@ angular.module('copayApp.controllers').controller('preferencesFeeController', fu
|
|||
});
|
||||
|
||||
$scope.init = function() {
|
||||
var coin = 'btc'; // TODO: only BTC in preferences
|
||||
$scope.network = $scope.network || 'livenet';
|
||||
$scope.feeOpts = feeService.feeOpts;
|
||||
$scope.currentFeeLevel = $scope.feeLevel || feeService.getCurrentFeeLevel();
|
||||
$scope.loadingFee = true;
|
||||
feeService.getFeeLevels(function(err, levels) {
|
||||
feeService.getFeeLevels(coin, function(err, levels) {
|
||||
$scope.loadingFee = false;
|
||||
if (err) {
|
||||
//Error is already formatted
|
||||
|
|
@ -66,7 +67,7 @@ angular.module('copayApp.controllers').controller('preferencesFeeController', fu
|
|||
return;
|
||||
}
|
||||
|
||||
$scope.feePerSatByte = (value.feePerKB / 1000).toFixed();
|
||||
$scope.feePerSatByte = (value.feePerKb / 1000).toFixed();
|
||||
$scope.avgConfirmationTime = value.nbBlocks * 10;
|
||||
$scope.invalidCustomFeeEntered = false;
|
||||
setMinWarning();
|
||||
|
|
@ -97,7 +98,7 @@ angular.module('copayApp.controllers').controller('preferencesFeeController', fu
|
|||
var value = lodash.find($scope.feeLevels[$scope.network], {
|
||||
level: 'superEconomy'
|
||||
});
|
||||
return parseInt((value.feePerKB / 1000).toFixed());
|
||||
return parseInt((value.feePerKb / 1000).toFixed());
|
||||
};
|
||||
|
||||
var setMinWarning = function() {
|
||||
|
|
|
|||
|
|
@ -1,43 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('preferencesUnitController', function($scope, $log, configService, $ionicHistory, gettextCatalog, walletService, profileService) {
|
||||
|
||||
var config = configService.getSync();
|
||||
$scope.unitList = [{
|
||||
name: 'bits (1,000,000 bits = 1BTC)',
|
||||
shortName: 'bits',
|
||||
value: 100,
|
||||
decimals: 2,
|
||||
code: 'bit',
|
||||
}, {
|
||||
name: 'BTC',
|
||||
shortName: 'BTC',
|
||||
value: 100000000,
|
||||
decimals: 8,
|
||||
code: 'btc',
|
||||
}];
|
||||
|
||||
$scope.save = function(newUnit) {
|
||||
var opts = {
|
||||
wallet: {
|
||||
settings: {
|
||||
unitName: newUnit.shortName,
|
||||
unitToSatoshi: newUnit.value,
|
||||
unitDecimals: newUnit.decimals,
|
||||
unitCode: newUnit.code,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
configService.set(opts, function(err) {
|
||||
if (err) $log.warn(err);
|
||||
|
||||
$ionicHistory.goBack();
|
||||
walletService.updateRemotePreferences(profileService.getWallets())
|
||||
});
|
||||
};
|
||||
|
||||
$scope.$on("$ionicView.enter", function(event, data){
|
||||
$scope.currentUnit = config.wallet.settings.unitCode;
|
||||
});
|
||||
});
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
angular.module('copayApp.controllers').controller('sellCoinbaseController', function($scope, $log, $state, $timeout, $ionicHistory, $ionicScrollDelegate, $ionicConfig, lodash, coinbaseService, popupService, profileService, ongoingProcess, walletService, appConfigService, configService, txFormatService) {
|
||||
|
||||
var coin = 'btc';
|
||||
var amount;
|
||||
var currency;
|
||||
|
||||
|
|
@ -34,124 +35,7 @@ angular.module('copayApp.controllers').controller('sellCoinbaseController', func
|
|||
}, onSendStatusChange);
|
||||
};
|
||||
|
||||
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 != '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
|
||||
|
||||
var processPaymentInfo = function() {
|
||||
ongoingProcess.set('connectingCoinbase', true);
|
||||
coinbaseService.init(function(err, res) {
|
||||
if (err) {
|
||||
|
|
@ -193,7 +77,121 @@ angular.module('copayApp.controllers').controller('sellCoinbaseController', func
|
|||
if (!hasPrimary) $scope.selectedPaymentMethodId.value = $scope.paymentMethods[0].id;
|
||||
$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 != '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,
|
||||
coin: coin
|
||||
});
|
||||
|
||||
if (lodash.isEmpty($scope.wallets)) {
|
||||
showErrorAndBack('Insufficient funds');
|
||||
return;
|
||||
}
|
||||
$scope.onWalletSelect($scope.wallets[0]); // Default first wallet
|
||||
});
|
||||
|
||||
$scope.sellRequest = function() {
|
||||
|
|
@ -236,7 +234,7 @@ angular.module('copayApp.controllers').controller('sellCoinbaseController', func
|
|||
var cancelText = 'Cancel';
|
||||
popupService.showConfirm(null, message, okText, cancelText, function(ok) {
|
||||
if (!ok) return;
|
||||
|
||||
|
||||
ongoingProcess.set('sellingBitcoin', true, statusChangeHandler);
|
||||
coinbaseService.init(function(err, res) {
|
||||
if (err) {
|
||||
|
|
@ -294,8 +292,8 @@ angular.module('copayApp.controllers').controller('sellCoinbaseController', func
|
|||
checkTransaction(1, txSent);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -306,6 +304,15 @@ angular.module('copayApp.controllers').controller('sellCoinbaseController', func
|
|||
|
||||
$scope.onWalletSelect = function(wallet) {
|
||||
$scope.wallet = wallet;
|
||||
var parsedAmount = txFormatService.parseAmount(
|
||||
coin,
|
||||
amount,
|
||||
currency);
|
||||
|
||||
amount = parsedAmount.amount;
|
||||
currency = parsedAmount.currency;
|
||||
$scope.amountUnitStr = parsedAmount.amountUnitStr;
|
||||
processPaymentInfo();
|
||||
};
|
||||
|
||||
$scope.goBackHome = function() {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
angular.module('copayApp.controllers').controller('sellGlideraController', function($scope, $log, $state, $timeout, $ionicHistory, $ionicConfig, lodash, glideraService, popupService, profileService, ongoingProcess, walletService, configService, platformInfo, txFormatService) {
|
||||
|
||||
var coin = 'btc';
|
||||
var amount;
|
||||
var currency;
|
||||
|
||||
|
|
@ -35,39 +36,7 @@ angular.module('copayApp.controllers').controller('sellGlideraController', funct
|
|||
}
|
||||
};
|
||||
|
||||
$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.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
|
||||
|
||||
var processPaymentInfo = function() {
|
||||
ongoingProcess.set('connectingGlidera', true);
|
||||
glideraService.init(function(err, data) {
|
||||
if (err) {
|
||||
|
|
@ -91,6 +60,35 @@ angular.module('copayApp.controllers').controller('sellGlideraController', funct
|
|||
$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 != '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,
|
||||
coin: coin
|
||||
});
|
||||
|
||||
if (lodash.isEmpty($scope.wallets)) {
|
||||
showErrorAndBack('Insufficient funds');
|
||||
return;
|
||||
}
|
||||
$scope.onWalletSelect($scope.wallets[0]); // Default first wallet
|
||||
});
|
||||
|
||||
var ask2FaCode = function(mode, cb) {
|
||||
|
|
@ -108,7 +106,7 @@ angular.module('copayApp.controllers').controller('sellGlideraController', funct
|
|||
popupService.showPrompt(title, message, null, function(twoFaCode) {
|
||||
if (typeof twoFaCode == 'undefined') return cb();
|
||||
return cb(twoFaCode);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
return cb();
|
||||
}
|
||||
|
|
@ -119,7 +117,7 @@ angular.module('copayApp.controllers').controller('sellGlideraController', funct
|
|||
var okText = 'Confirm';
|
||||
var cancelText = 'Cancel';
|
||||
popupService.showConfirm(null, message, okText, cancelText, function(ok) {
|
||||
if (!ok) return;
|
||||
if (!ok) return;
|
||||
ongoingProcess.set('sellingBitcoin', true, statusChangeHandler);
|
||||
glideraService.get2faCode($scope.token, function(err, tfa) {
|
||||
if (err) {
|
||||
|
|
@ -231,6 +229,15 @@ angular.module('copayApp.controllers').controller('sellGlideraController', funct
|
|||
|
||||
$scope.onWalletSelect = function(wallet) {
|
||||
$scope.wallet = wallet;
|
||||
var parsedAmount = txFormatService.parseAmount(
|
||||
coin,
|
||||
amount,
|
||||
currency);
|
||||
|
||||
amount = parsedAmount.amount;
|
||||
currency = parsedAmount.currency;
|
||||
$scope.amountUnitStr = parsedAmount.amountUnitStr;
|
||||
processPaymentInfo();
|
||||
};
|
||||
|
||||
$scope.goBackHome = function() {
|
||||
|
|
|
|||
|
|
@ -206,14 +206,24 @@ angular.module('copayApp.controllers').controller('tabHomeController',
|
|||
};
|
||||
|
||||
var updateAllWallets = function() {
|
||||
$scope.wallets = profileService.getWallets();
|
||||
if (lodash.isEmpty($scope.wallets)) return;
|
||||
var wallets = [];
|
||||
$scope.walletsBtc = profileService.getWallets({coin: 'btc'});
|
||||
$scope.walletsBch = profileService.getWallets({coin: 'bch'});
|
||||
|
||||
var i = $scope.wallets.length;
|
||||
lodash.each($scope.walletsBtc, function(wBtc) {
|
||||
wallets.push(wBtc);
|
||||
});
|
||||
|
||||
lodash.each($scope.walletsBch, function(wBch) {
|
||||
wallets.push(wBch);
|
||||
});
|
||||
|
||||
if (lodash.isEmpty(wallets)) return;
|
||||
|
||||
var i = wallets.length;
|
||||
var j = 0;
|
||||
var timeSpan = 60 * 60 * 24 * 7;
|
||||
|
||||
lodash.each($scope.wallets, function(wallet) {
|
||||
lodash.each(wallets, function(wallet) {
|
||||
walletService.getStatus(wallet, {}, function(err, status) {
|
||||
if (err) {
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@ angular.module('copayApp.controllers').controller('tabReceiveController', functi
|
|||
|
||||
$scope.requestSpecificAmount = function() {
|
||||
$state.go('tabs.paymentRequest.amount', {
|
||||
id: $scope.wallet.credentials.walletId
|
||||
id: $scope.wallet.credentials.walletId,
|
||||
coin: $scope.wallet.coin
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -123,8 +124,13 @@ angular.module('copayApp.controllers').controller('tabReceiveController', functi
|
|||
return wallet;
|
||||
}
|
||||
|
||||
var setProtocolHandler = function() {
|
||||
$scope.protocolHandler = walletService.getProtocolHandler($scope.wallet);
|
||||
}
|
||||
|
||||
$scope.onWalletSelect = function(wallet) {
|
||||
$scope.wallet = wallet;
|
||||
setProtocolHandler();
|
||||
$scope.setAddress();
|
||||
};
|
||||
|
||||
|
|
@ -136,6 +142,8 @@ angular.module('copayApp.controllers').controller('tabReceiveController', functi
|
|||
|
||||
$scope.shareAddress = function() {
|
||||
if (!$scope.isCordova) return;
|
||||
window.plugins.socialsharing.share('bitcoin:' + $scope.addr, null, null, null);
|
||||
var protocol = 'bitcoin';
|
||||
if ($scope.wallet.coin == 'bch') protocol += 'cash';
|
||||
window.plugins.socialsharing.share(protocol + ':' + $scope.addr, null, null, null);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('tabSendController', function($scope, $rootScope, $log, $timeout, $ionicScrollDelegate, addressbookService, profileService, lodash, $state, walletService, incomingData, popupService, platformInfo, bwcError, gettextCatalog, scannerService) {
|
||||
angular.module('copayApp.controllers').controller('tabSendController', function($scope, $rootScope, $log, $timeout, $ionicScrollDelegate, addressbookService, profileService, lodash, $state, walletService, incomingData, popupService, platformInfo, bwcError, gettextCatalog, scannerService, bitcoreCash) {
|
||||
|
||||
var originalList;
|
||||
var CONTACTS_SHOW_LIMIT;
|
||||
|
|
@ -76,6 +76,8 @@ angular.module('copayApp.controllers').controller('tabSendController', function(
|
|||
color: v.color,
|
||||
name: v.name,
|
||||
recipientType: 'wallet',
|
||||
coin: v.coin,
|
||||
network: v.network,
|
||||
getAddress: function(cb) {
|
||||
walletService.getAddress(v, false, cb);
|
||||
},
|
||||
|
|
@ -85,6 +87,14 @@ angular.module('copayApp.controllers').controller('tabSendController', function(
|
|||
}
|
||||
}
|
||||
|
||||
var getCoin = function(address) {
|
||||
var cashAddress = bitcoreCash.Address.isValid(address, 'livenet');
|
||||
if (cashAddress) {
|
||||
return 'bch';
|
||||
}
|
||||
return 'btc';
|
||||
};
|
||||
|
||||
var updateContactsList = function(cb) {
|
||||
addressbookService.list(function(err, ab) {
|
||||
if (err) $log.error(err);
|
||||
|
|
@ -99,6 +109,7 @@ angular.module('copayApp.controllers').controller('tabSendController', function(
|
|||
address: k,
|
||||
email: lodash.isObject(v) ? v.email : null,
|
||||
recipientType: 'contact',
|
||||
coin: getCoin(k),
|
||||
getAddress: function(cb) {
|
||||
return cb(null, k);
|
||||
},
|
||||
|
|
@ -186,7 +197,8 @@ angular.module('copayApp.controllers').controller('tabSendController', function(
|
|||
toAddress: addr,
|
||||
toName: item.name,
|
||||
toEmail: item.email,
|
||||
toColor: item.color
|
||||
toColor: item.color,
|
||||
coin: item.coin
|
||||
})
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ angular.module('copayApp.controllers').controller('tabSettingsController', funct
|
|||
$scope.currentLanguageName = uxLanguage.getCurrentLanguageName();
|
||||
$scope.feeOpts = feeService.feeOpts;
|
||||
$scope.currentFeeLevel = feeService.getCurrentFeeLevel();
|
||||
$scope.wallets = profileService.getWallets();
|
||||
$scope.walletsBtc = profileService.getWallets({ coin: 'btc' });
|
||||
$scope.walletsBch = profileService.getWallets({ coin: 'bch' });
|
||||
$scope.buyAndSellServices = buyAndSellService.getLinked();
|
||||
|
||||
configService.whenAvailable(function(config) {
|
||||
$scope.unitName = config.wallet.settings.unitName;
|
||||
$scope.selectedAlternative = {
|
||||
name: config.wallet.settings.alternativeName,
|
||||
isoCode: config.wallet.settings.alternativeIsoCode
|
||||
|
|
@ -26,6 +26,11 @@ angular.module('copayApp.controllers').controller('tabSettingsController', funct
|
|||
}, 10);
|
||||
});
|
||||
|
||||
$scope.cashSupport = {
|
||||
value: config.cashSupport
|
||||
};
|
||||
|
||||
|
||||
// TODO move this to a generic service
|
||||
bitpayCardService.getCards(function(err, cards) {
|
||||
if (err) $log.error(err);
|
||||
|
|
@ -63,6 +68,8 @@ angular.module('copayApp.controllers').controller('tabSettingsController', funct
|
|||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
$scope.$on("$ionicView.enter", function(event, data) {
|
||||
updateConfig();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
angular.module('copayApp.controllers').controller('topUpController', function($scope, $log, $state, $timeout, $ionicHistory, $ionicConfig, lodash, popupService, profileService, ongoingProcess, walletService, configService, platformInfo, bitpayService, bitpayCardService, payproService, bwcError, txFormatService, sendMaxService, gettextCatalog) {
|
||||
|
||||
$scope.isCordova = platformInfo.isCordova;
|
||||
var coin = 'btc';
|
||||
var cardId;
|
||||
var useSendMax;
|
||||
var amount;
|
||||
|
|
@ -36,7 +37,7 @@ angular.module('copayApp.controllers').controller('topUpController', function($s
|
|||
};
|
||||
|
||||
var satToFiat = function(sat, cb) {
|
||||
txFormatService.toFiat(sat, $scope.currencyIsoCode, function(value) {
|
||||
txFormatService.toFiat(coin, sat, $scope.currencyIsoCode, function(value) {
|
||||
return cb(value);
|
||||
});
|
||||
};
|
||||
|
|
@ -218,7 +219,7 @@ angular.module('copayApp.controllers').controller('topUpController', function($s
|
|||
// Save TX in memory
|
||||
createdTx = ctxp;
|
||||
|
||||
$scope.totalAmountStr = txFormatService.formatAmountStr(ctxp.amount);
|
||||
$scope.totalAmountStr = txFormatService.formatAmountStr(coin, ctxp.amount);
|
||||
|
||||
setTotalAmount(parsedAmount.amountSat, invoiceFeeSat, ctxp.fee);
|
||||
|
||||
|
|
@ -256,7 +257,8 @@ angular.module('copayApp.controllers').controller('topUpController', function($s
|
|||
$scope.wallets = profileService.getWallets({
|
||||
onlyComplete: true,
|
||||
network: bitpayService.getEnvironment().network,
|
||||
hasFunds: true
|
||||
hasFunds: true,
|
||||
coin: coin
|
||||
});
|
||||
|
||||
if (lodash.isEmpty($scope.wallets)) {
|
||||
|
|
@ -319,7 +321,7 @@ angular.module('copayApp.controllers').controller('topUpController', function($s
|
|||
});
|
||||
return;
|
||||
}
|
||||
var parsedAmount = txFormatService.parseAmount(a, c);
|
||||
var parsedAmount = txFormatService.parseAmount(coin, a, c);
|
||||
initializeTopUp(wallet, parsedAmount);
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ angular.module('copayApp.controllers').controller('txDetailsController', functio
|
|||
var txId;
|
||||
var listeners = [];
|
||||
var config = configService.getSync();
|
||||
var blockexplorerUrl;
|
||||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
txId = data.stateParams.txid;
|
||||
|
|
@ -15,6 +16,12 @@ angular.module('copayApp.controllers').controller('txDetailsController', functio
|
|||
$scope.isShared = $scope.wallet.credentials.n > 1;
|
||||
$scope.txsUnsubscribedForNotifications = config.confirmedTxsNotifications ? !config.confirmedTxsNotifications.enabled : true;
|
||||
|
||||
if ($scope.wallet.coin == 'bch') {
|
||||
blockexplorerUrl = 'bch-insight.bitpay.com';
|
||||
} else {
|
||||
blockexplorerUrl = 'insight.bitpay.com';
|
||||
}
|
||||
|
||||
txConfirmNotification.checkIfEnabled(txId, function(res) {
|
||||
$scope.txNotification = {
|
||||
value: res
|
||||
|
|
@ -40,6 +47,16 @@ angular.module('copayApp.controllers').controller('txDetailsController', functio
|
|||
});
|
||||
});
|
||||
|
||||
$scope.readMore = function() {
|
||||
var url = 'https://github.com/bitpay/copay/wiki/COPAY---FAQ#amount-too-low-to-spend';
|
||||
var optIn = true;
|
||||
var title = null;
|
||||
var message = gettextCatalog.getString('Read more in our Wiki');
|
||||
var okText = gettextCatalog.getString('Open');
|
||||
var cancelText = gettextCatalog.getString('Go Back');
|
||||
externalLinkService.open(url, optIn, title, message, okText, cancelText);
|
||||
};
|
||||
|
||||
function updateMemo() {
|
||||
walletService.getTxNote($scope.wallet, $scope.btx.txid, function(err, note) {
|
||||
if (err) {
|
||||
|
|
@ -102,8 +119,8 @@ angular.module('copayApp.controllers').controller('txDetailsController', functio
|
|||
return popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Transaction not available at this time'));
|
||||
}
|
||||
|
||||
$scope.btx = txFormatService.processTx(tx);
|
||||
txFormatService.formatAlternativeStr(tx.fees, function(v) {
|
||||
$scope.btx = txFormatService.processTx($scope.wallet.coin, tx);
|
||||
txFormatService.formatAlternativeStr($scope.wallet.coin, tx.fees, function(v) {
|
||||
$scope.btx.feeFiatStr = v;
|
||||
$scope.btx.feeRateStr = ($scope.btx.fees / ($scope.btx.amount + $scope.btx.fees) * 100).toFixed(2) + '%';
|
||||
});
|
||||
|
|
@ -121,7 +138,7 @@ angular.module('copayApp.controllers').controller('txDetailsController', functio
|
|||
$scope.$digest();
|
||||
});
|
||||
|
||||
feeService.getFeeLevels(function(err, levels) {
|
||||
feeService.getFeeLevels($scope.wallet.coin, function(err, levels) {
|
||||
if (err) return;
|
||||
walletService.getLowAmount($scope.wallet, levels, function(err, amount) {
|
||||
if (err) return;
|
||||
|
|
@ -168,10 +185,7 @@ angular.module('copayApp.controllers').controller('txDetailsController', functio
|
|||
|
||||
$scope.viewOnBlockchain = function() {
|
||||
var btx = $scope.btx;
|
||||
var url = 'https://blockchain.info/tx/' + btx.txid;
|
||||
if ($scope.getShortNetworkName() == 'test') {
|
||||
url = "https://test-insight.bitpay.com/tx/" + btx.txid;
|
||||
}
|
||||
var url = 'https://' + ($scope.getShortNetworkName() == 'test' ? 'test-' : '') + blockexplorerUrl + '/tx/' + btx.txid;
|
||||
var optIn = true;
|
||||
var title = null;
|
||||
var message = gettextCatalog.getString('View Transaction on Insight');
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
|
|||
var analyzeUtxos = function() {
|
||||
if (analyzeUtxosDone) return;
|
||||
|
||||
feeService.getFeeLevels(function(err, levels) {
|
||||
feeService.getFeeLevels($scope.wallet.coin, function(err, levels) {
|
||||
if (err) return;
|
||||
walletService.getLowUtxos($scope.wallet, levels, function(err, resp) {
|
||||
if (err || !resp) return;
|
||||
|
|
@ -156,9 +156,7 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
|
|||
|
||||
var updateTxHistory = function(cb) {
|
||||
if (!cb) cb = function() {};
|
||||
if ($scope.updatingTxHistory) return;
|
||||
|
||||
$scope.updatingTxHistory = true;
|
||||
$scope.updateTxHistoryError = false;
|
||||
$scope.updatingTxHistoryProgress = 0;
|
||||
|
||||
|
|
@ -171,7 +169,7 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
|
|||
});
|
||||
};
|
||||
|
||||
feeService.getFeeLevels(function(err, levels) {
|
||||
feeService.getFeeLevels($scope.wallet.coin, function(err, levels) {
|
||||
walletService.getTxHistory($scope.wallet, {
|
||||
progressFn: progressFn,
|
||||
feeLevels: levels,
|
||||
|
|
@ -184,7 +182,9 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
|
|||
}
|
||||
$scope.completeTxHistory = txHistory;
|
||||
$scope.showHistory();
|
||||
$scope.$apply();
|
||||
$timeout(function() {
|
||||
$scope.$apply();
|
||||
});
|
||||
return cb();
|
||||
});
|
||||
});
|
||||
|
|
@ -356,6 +356,8 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
|
|||
if (!$scope.wallet) return;
|
||||
$scope.requiresMultipleSignatures = $scope.wallet.credentials.m > 1;
|
||||
|
||||
$scope.updatingTxHistory = true;
|
||||
|
||||
addressbookService.list(function(err, ab) {
|
||||
if (err) $log.error(err);
|
||||
$scope.addressbook = ab || {};
|
||||
|
|
|
|||
|
|
@ -1,12 +1,18 @@
|
|||
'use strict';
|
||||
angular.module('copayApp.directives')
|
||||
.directive('validAddress', ['$rootScope', 'bitcore',
|
||||
function($rootScope, bitcore) {
|
||||
.directive('validAddress', ['$rootScope', 'bitcore', 'bitcoreCash',
|
||||
function($rootScope, bitcore, bitcoreCash) {
|
||||
return {
|
||||
require: 'ngModel',
|
||||
link: function(scope, elem, attrs, ctrl) {
|
||||
// Bitcoin address
|
||||
var URI = bitcore.URI;
|
||||
var Address = bitcore.Address
|
||||
|
||||
// Bitcoin Cash address
|
||||
var URICash = bitcoreCash.URI;
|
||||
var AddressCash = bitcoreCash.Address
|
||||
|
||||
var validator = function(value) {
|
||||
|
||||
// Regular url
|
||||
|
|
@ -16,8 +22,8 @@ angular.module('copayApp.directives')
|
|||
}
|
||||
|
||||
// Bip21 uri
|
||||
var uri, isAddressValidLivenet, isAddressValidTestnet;
|
||||
if (/^bitcoin:/.test(value)) {
|
||||
var uri, isAddressValidLivenet, isAddressValidTestnet;
|
||||
var isUriValid = URI.isValid(value);
|
||||
if (isUriValid) {
|
||||
uri = new URI(value);
|
||||
|
|
@ -26,6 +32,14 @@ angular.module('copayApp.directives')
|
|||
}
|
||||
ctrl.$setValidity('validAddress', isUriValid && (isAddressValidLivenet || isAddressValidTestnet));
|
||||
return value;
|
||||
} else if (/^bitcoincash:/.test(value)) {
|
||||
var isUriValid = URICash.isValid(value);
|
||||
if (isUriValid) {
|
||||
uri = new URICash(value);
|
||||
isAddressValidLivenet = AddressCash.isValid(uri.address.toString(), 'livenet')
|
||||
}
|
||||
ctrl.$setValidity('validAddress', isUriValid && (isAddressValidLivenet));
|
||||
return value;
|
||||
}
|
||||
|
||||
if (typeof value == 'undefined') {
|
||||
|
|
@ -33,10 +47,11 @@ angular.module('copayApp.directives')
|
|||
return;
|
||||
}
|
||||
|
||||
// Regular Address
|
||||
// Regular Address: try Bitcoin and Bitcoin Cash
|
||||
var regularAddressLivenet = Address.isValid(value, 'livenet');
|
||||
var regularAddressTestnet = Address.isValid(value, 'testnet');
|
||||
ctrl.$setValidity('validAddress', (regularAddressLivenet || regularAddressTestnet));
|
||||
var regularAddressCashLivenet = AddressCash.isValid(value, 'livenet');
|
||||
ctrl.$setValidity('validAddress', (regularAddressLivenet || regularAddressTestnet || regularAddressCashLivenet));
|
||||
return value;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -27,12 +27,10 @@ angular.module('copayApp.filters', [])
|
|||
}
|
||||
})
|
||||
.filter('formatFiatAmount', ['$filter', '$locale', 'configService',
|
||||
function(filter, locale, configService) {
|
||||
function(filter, locale) {
|
||||
var numberFilter = filter('number');
|
||||
var formats = locale.NUMBER_FORMATS;
|
||||
var config = configService.getSync().wallet.settings;
|
||||
return function(amount) {
|
||||
if (!config) return amount;
|
||||
|
||||
var fractionSize = 2;
|
||||
var value = numberFilter(amount, fractionSize);
|
||||
|
|
|
|||
107
src/js/routes.js
107
src/js/routes.js
|
|
@ -287,7 +287,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
*/
|
||||
|
||||
.state('tabs.send.amount', {
|
||||
url: '/amount/:recipientType/:toAddress/:toName/:toEmail/:toColor',
|
||||
url: '/amount/:recipientType/:toAddress/:toName/:toEmail/:toColor/:coin/:fixedUnit',
|
||||
views: {
|
||||
'tab-send@tabs': {
|
||||
controller: 'amountController',
|
||||
|
|
@ -296,7 +296,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
}
|
||||
})
|
||||
.state('tabs.send.confirm', {
|
||||
url: '/confirm/:recipientType/:toAddress/:toName/:toAmount/:toEmail/:toColor/:description/:useSendMax',
|
||||
url: '/confirm/:recipientType/:toAddress/:toName/:toAmount/:toEmail/:toColor/:description/:coin/:useSendMax',
|
||||
views: {
|
||||
'tab-send@tabs': {
|
||||
controller: 'confirmController',
|
||||
|
|
@ -329,6 +329,9 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
'tab-home@tabs': {
|
||||
templateUrl: 'views/add.html'
|
||||
}
|
||||
},
|
||||
params: {
|
||||
coin: 'btc'
|
||||
}
|
||||
})
|
||||
.state('tabs.add.join', {
|
||||
|
|
@ -374,6 +377,16 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
*
|
||||
*/
|
||||
|
||||
.state('tabs.preferencesCash', {
|
||||
url: '/preferencesCash',
|
||||
views: {
|
||||
'tab-settings@tabs': {
|
||||
controller: 'preferencesCashController',
|
||||
templateUrl: 'views/preferencesCash.html'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
.state('tabs.notifications', {
|
||||
url: '/notifications',
|
||||
views: {
|
||||
|
|
@ -392,15 +405,6 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
}
|
||||
}
|
||||
})
|
||||
.state('tabs.unit', {
|
||||
url: '/unit',
|
||||
views: {
|
||||
'tab-settings@tabs': {
|
||||
controller: 'preferencesUnitController',
|
||||
templateUrl: 'views/preferencesUnit.html'
|
||||
}
|
||||
}
|
||||
})
|
||||
.state('tabs.fee', {
|
||||
url: '/fee',
|
||||
views: {
|
||||
|
|
@ -474,6 +478,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
}
|
||||
})
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Wallet preferences
|
||||
|
|
@ -589,6 +594,16 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
}
|
||||
})
|
||||
|
||||
.state('tabs.preferencesCash.scan', {
|
||||
url: '/cashScan',
|
||||
views: {
|
||||
'tab-settings@tabs': {
|
||||
controller: 'cashScanController',
|
||||
templateUrl: 'views/cashScan.html'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
/*
|
||||
*
|
||||
* Addressbook
|
||||
|
|
@ -676,12 +691,12 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
abstract: true,
|
||||
params: {
|
||||
id: null,
|
||||
nextStep: 'tabs.paymentRequest.confirm'
|
||||
nextStep: 'tabs.paymentRequest.confirm',
|
||||
}
|
||||
})
|
||||
|
||||
.state('tabs.paymentRequest.amount', {
|
||||
url: '/amount',
|
||||
url: '/amount/:coin',
|
||||
views: {
|
||||
'tab-receive@tabs': {
|
||||
controller: 'amountController',
|
||||
|
|
@ -690,7 +705,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
}
|
||||
})
|
||||
.state('tabs.paymentRequest.confirm', {
|
||||
url: '/confirm/:amount/:currency',
|
||||
url: '/confirm/:amount/:currency/:coin',
|
||||
views: {
|
||||
'tab-receive@tabs': {
|
||||
controller: 'customAmountController',
|
||||
|
|
@ -923,6 +938,9 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
controllerAs: 'glidera',
|
||||
templateUrl: 'views/glidera.html'
|
||||
}
|
||||
},
|
||||
params: {
|
||||
coin: 'btc',
|
||||
}
|
||||
})
|
||||
.state('tabs.buyandsell.glidera.amount', {
|
||||
|
|
@ -976,6 +994,9 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
controllerAs: 'coinbase',
|
||||
templateUrl: 'views/coinbase.html'
|
||||
}
|
||||
},
|
||||
params: {
|
||||
coin: 'btc',
|
||||
}
|
||||
})
|
||||
.state('tabs.preferences.coinbase', {
|
||||
|
|
@ -1026,36 +1047,54 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
abstract: true
|
||||
})
|
||||
|
||||
/*
|
||||
*
|
||||
* Mercado Libre Gift Card
|
||||
*
|
||||
*/
|
||||
|
||||
/* Explore Bitcoin.com */
|
||||
.state('tabs.bitcoin-com', {
|
||||
url: '/bitcoincom',
|
||||
.state('tabs.giftcards.mercadoLibre', {
|
||||
url: '/mercadoLibre',
|
||||
views: {
|
||||
'tab-home@tabs': {
|
||||
controller: 'bitcoincomController',
|
||||
templateUrl: 'views/bitcoincom.html'
|
||||
controller: 'mercadoLibreController',
|
||||
templateUrl: 'views/mercadoLibre.html'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
/* buy.Bitcoin.com */
|
||||
.state('tabs.buyandsell.bitcoindotcom', {
|
||||
url: '/buyBitcoindotcom',
|
||||
.state('tabs.giftcards.mercadoLibre.cards', {
|
||||
url: '/cards',
|
||||
views: {
|
||||
'tab-home@tabs': {
|
||||
controller: 'buyBitcoindotcomController',
|
||||
templateUrl: 'views/buyBitcoindotcom.html'
|
||||
controller: 'mercadoLibreCardsController',
|
||||
templateUrl: 'views/mercadoLibreCards.html'
|
||||
}
|
||||
},
|
||||
params: {
|
||||
invoiceId: null
|
||||
}
|
||||
})
|
||||
|
||||
/* Price Chart */
|
||||
.state('tabs.pricechart', {
|
||||
url: '/pricechart',
|
||||
.state('tabs.giftcards.mercadoLibre.amount', {
|
||||
url: '/amount',
|
||||
views: {
|
||||
'tab-home@tabs': {
|
||||
controller: 'pricechartController',
|
||||
templateUrl: 'views/pricechart.html'
|
||||
controller: 'amountController',
|
||||
templateUrl: 'views/amount.html'
|
||||
}
|
||||
},
|
||||
params: {
|
||||
nextStep: 'tabs.giftcards.mercadoLibre.buy',
|
||||
currency: 'BRL',
|
||||
coin: 'btc',
|
||||
fixedUnit: 1,
|
||||
}
|
||||
})
|
||||
.state('tabs.giftcards.mercadoLibre.buy', {
|
||||
url: '/buy/:amount/:currency',
|
||||
views: {
|
||||
'tab-home@tabs': {
|
||||
controller: 'buyMercadoLibreController',
|
||||
templateUrl: 'views/buyMercadoLibre.html'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
@ -1098,7 +1137,8 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
params: {
|
||||
nextStep: 'tabs.giftcards.amazon.buy',
|
||||
currency: 'USD',
|
||||
forceCurrency: true
|
||||
coin: 'btc',
|
||||
fixedUnit: true,
|
||||
}
|
||||
})
|
||||
.state('tabs.giftcards.amazon.buy', {
|
||||
|
|
@ -1138,6 +1178,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
params: {
|
||||
id: null,
|
||||
currency: 'USD',
|
||||
coin: 'btc',
|
||||
useSendMax: null
|
||||
}
|
||||
})
|
||||
|
|
@ -1169,7 +1210,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
}
|
||||
});
|
||||
})
|
||||
.run(function($rootScope, $state, $location, $log, $timeout, startupService, fingerprintService, $ionicHistory, $ionicPlatform, $window, appConfigService, lodash, platformInfo, profileService, uxLanguage, gettextCatalog, openURLService, storageService, scannerService, configService, emailService, /* plugins START HERE => */ glideraService, buydotbitcoindotcomService, amazonService, bitpayCardService, applicationService) {
|
||||
.run(function($rootScope, $state, $location, $log, $timeout, startupService, ionicToast, fingerprintService, $ionicHistory, $ionicPlatform, $window, appConfigService, lodash, platformInfo, profileService, uxLanguage, gettextCatalog, openURLService, storageService, scannerService, configService, emailService, /* plugins START HERE => */ coinbaseService, glideraService, amazonService, bitpayCardService, applicationService, mercadoLibreService) {
|
||||
|
||||
uxLanguage.init();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,19 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.services').factory('addressbookService', function(bitcore, storageService, lodash) {
|
||||
angular.module('copayApp.services').factory('addressbookService', function($log, bitcore, bitcoreCash, storageService, lodash) {
|
||||
var root = {};
|
||||
|
||||
var getNetwork = function(address) {
|
||||
var network;
|
||||
try {
|
||||
network = (new bitcore.Address(address)).network.name;
|
||||
} catch(e) {
|
||||
$log.warn('No valid bitcoin address. Trying bitcoin cash...');
|
||||
network = (new bitcoreCash.Address(address)).network.name;
|
||||
}
|
||||
return network;
|
||||
};
|
||||
|
||||
root.get = function(addr, cb) {
|
||||
storageService.getAddressbook('testnet', function(err, ab) {
|
||||
if (err) return cb(err);
|
||||
|
|
@ -35,7 +46,8 @@ angular.module('copayApp.services').factory('addressbookService', function(bitco
|
|||
};
|
||||
|
||||
root.add = function(entry, cb) {
|
||||
var network = (new bitcore.Address(entry.address)).network.name;
|
||||
var network = getNetwork(entry.address);
|
||||
if (lodash.isEmpty(network)) return cb('Not valid bitcoin address');
|
||||
storageService.getAddressbook(network, function(err, ab) {
|
||||
if (err) return cb(err);
|
||||
if (ab) ab = JSON.parse(ab);
|
||||
|
|
@ -53,7 +65,8 @@ angular.module('copayApp.services').factory('addressbookService', function(bitco
|
|||
};
|
||||
|
||||
root.remove = function(addr, cb) {
|
||||
var network = (new bitcore.Address(addr)).network.name;
|
||||
var network = getNetwork(addr);
|
||||
if (lodash.isEmpty(network)) return cb('Not valid bitcoin address');
|
||||
storageService.getAddressbook(network, function(err, ab) {
|
||||
if (err) return cb(err);
|
||||
if (ab) ab = JSON.parse(ab);
|
||||
|
|
|
|||
6
src/js/services/bitcoreCash.js
Normal file
6
src/js/services/bitcoreCash.js
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
'use strict';
|
||||
angular.module('copayApp.services')
|
||||
.factory('bitcoreCash', function bitcoreFactory(bwcService) {
|
||||
var bitcoreCash = bwcService.getBitcoreCash();
|
||||
return bitcoreCash;
|
||||
});
|
||||
|
|
@ -53,6 +53,7 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $
|
|||
'wallet:sells:create,' +
|
||||
'wallet:transactions:read,' +
|
||||
'wallet:transactions:send,' +
|
||||
'wallet:transactions:send:bypass-2fa,' +
|
||||
'wallet:payment-methods:read';
|
||||
|
||||
// NW has a bug with Window Object
|
||||
|
|
@ -169,9 +170,9 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $
|
|||
var _getNetAmount = function(amount, cb) {
|
||||
// Fee Normal for a single transaction (450 bytes)
|
||||
var txNormalFeeKB = 450 / 1000;
|
||||
feeService.getFeeRate(null, 'normal', function(err, feePerKB) {
|
||||
feeService.getFeeRate('btc', 'livenet', 'normal', function(err, feePerKb) {
|
||||
if (err) return cb(err);
|
||||
var feeBTC = (feePerKB * txNormalFeeKB / 100000000).toFixed(8);
|
||||
var feeBTC = (feePerKb * txNormalFeeKB / 100000000).toFixed(8);
|
||||
|
||||
return cb(null, amount - feeBTC, feeBTC);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -69,7 +69,8 @@ angular.module('copayApp.services').factory('configService', function(storageSer
|
|||
bannedUntil: null,
|
||||
},
|
||||
|
||||
// External services
|
||||
cashSupport: false,
|
||||
|
||||
recentTransactions: {
|
||||
enabled: true,
|
||||
},
|
||||
|
|
@ -141,6 +142,11 @@ angular.module('copayApp.services').factory('configService', function(storageSer
|
|||
configCache.hideNextSteps = defaultConfig.hideNextSteps;
|
||||
}
|
||||
|
||||
|
||||
if (!configCache.cashSupport) {
|
||||
configCache.cashSupport = defaultConfig.cashSupport;
|
||||
}
|
||||
|
||||
if (!configCache.recentTransactions) {
|
||||
configCache.recentTransactions = defaultConfig.recentTransactions;
|
||||
}
|
||||
|
|
@ -151,6 +157,14 @@ angular.module('copayApp.services').factory('configService', function(storageSer
|
|||
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 {
|
||||
configCache = lodash.clone(defaultConfig);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ angular.module('copayApp.services').factory('feeService', function($log, $timeou
|
|||
|
||||
var cache = {
|
||||
updateTs: 0,
|
||||
coin: ''
|
||||
};
|
||||
|
||||
root.getCurrentFeeLevel = function() {
|
||||
|
|
@ -24,20 +25,20 @@ angular.module('copayApp.services').factory('feeService', function($log, $timeou
|
|||
};
|
||||
|
||||
|
||||
root.getFeeRate = function(network, feeLevel, cb) {
|
||||
root.getFeeRate = function(coin, network, feeLevel, cb) {
|
||||
|
||||
if (feeLevel == 'custom') return cb();
|
||||
|
||||
network = network || 'livenet';
|
||||
|
||||
root.getFeeLevels(function(err, levels, fromCache) {
|
||||
root.getFeeLevels(coin, function(err, levels, fromCache) {
|
||||
if (err) return cb(err);
|
||||
|
||||
var feeLevelRate = lodash.find(levels[network], {
|
||||
level: feeLevel
|
||||
});
|
||||
|
||||
if (!feeLevelRate || !feeLevelRate.feePerKB) {
|
||||
if (!feeLevelRate || !feeLevelRate.feePerKb) {
|
||||
return cb({
|
||||
message: gettextCatalog.getString("Could not get dynamic fee for level: {{feeLevel}}", {
|
||||
feeLevel: feeLevel
|
||||
|
|
@ -45,34 +46,35 @@ angular.module('copayApp.services').factory('feeService', function($log, $timeou
|
|||
});
|
||||
}
|
||||
|
||||
var feeRate = feeLevelRate.feePerKB;
|
||||
var feeRate = feeLevelRate.feePerKb;
|
||||
|
||||
if (!fromCache) $log.debug('Dynamic fee: ' + feeLevel + '/' + network + ' ' + (feeLevelRate.feePerKB / 1000).toFixed() + ' SAT/B');
|
||||
if (!fromCache) $log.debug('Dynamic fee: ' + feeLevel + '/' + network + ' ' + (feeLevelRate.feePerKb / 1000).toFixed() + ' SAT/B');
|
||||
|
||||
return cb(null, feeRate);
|
||||
});
|
||||
};
|
||||
|
||||
root.getCurrentFeeRate = function(network, cb) {
|
||||
return root.getFeeRate(network, root.getCurrentFeeLevel(), cb);
|
||||
root.getCurrentFeeRate = function(coin, network, cb) {
|
||||
return root.getFeeRate(coin, network, root.getCurrentFeeLevel(), cb);
|
||||
};
|
||||
|
||||
root.getFeeLevels = function(cb) {
|
||||
root.getFeeLevels = function(coin, cb) {
|
||||
coin = coin || 'btc';
|
||||
|
||||
if (cache.updateTs > Date.now() - CACHE_TIME_TS * 1000) {
|
||||
if (cache.coin == coin && cache.updateTs > Date.now() - CACHE_TIME_TS * 1000) {
|
||||
return cb(null, cache.data, true);
|
||||
}
|
||||
|
||||
var walletClient = bwcService.getClient();
|
||||
var unitName = configService.getSync().wallet.settings.unitName;
|
||||
|
||||
walletClient.getFeeLevels('livenet', function(errLivenet, levelsLivenet) {
|
||||
walletClient.getFeeLevels('testnet', function(errTestnet, levelsTestnet) {
|
||||
walletClient.getFeeLevels(coin, 'livenet', function(errLivenet, levelsLivenet) {
|
||||
walletClient.getFeeLevels('btc', 'testnet', function(errTestnet, levelsTestnet) {
|
||||
if (errLivenet || errTestnet) {
|
||||
return cb(gettextCatalog.getString('Could not get dynamic fee'));
|
||||
}
|
||||
|
||||
cache.updateTs = Date.now();
|
||||
cache.coin = coin;
|
||||
cache.data = {
|
||||
'livenet': levelsLivenet,
|
||||
'testnet': levelsTestnet
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ angular.module('copayApp.services')
|
|||
};
|
||||
|
||||
root.add = function(level, msg) {
|
||||
msg = msg.replace('/xpriv.*/', 'xpriv[Hidden]');
|
||||
logs.push({
|
||||
timestamp: new Date().toISOString(),
|
||||
level: level,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.services').factory('incomingData', function($log, $state, $timeout, $ionicHistory, bitcore, $rootScope, payproService, scannerService, appConfigService, popupService, gettextCatalog) {
|
||||
angular.module('copayApp.services').factory('incomingData', function($log, $state, $timeout, $ionicHistory, bitcore, bitcoreCash, $rootScope, payproService, scannerService, appConfigService, popupService, gettextCatalog) {
|
||||
|
||||
var root = {};
|
||||
|
||||
|
|
@ -46,7 +46,7 @@ angular.module('copayApp.services').factory('incomingData', function($log, $stat
|
|||
return true;
|
||||
}
|
||||
|
||||
function goSend(addr, amount, message) {
|
||||
function goSend(addr, amount, message, coin) {
|
||||
$state.go('tabs.send', {}, {
|
||||
'reload': true,
|
||||
'notify': $state.current.name == 'tabs.send' ? false : true
|
||||
|
|
@ -57,18 +57,20 @@ angular.module('copayApp.services').factory('incomingData', function($log, $stat
|
|||
$state.transitionTo('tabs.send.confirm', {
|
||||
toAmount: amount,
|
||||
toAddress: addr,
|
||||
description: message
|
||||
description: message,
|
||||
coin: coin
|
||||
});
|
||||
} else {
|
||||
$state.transitionTo('tabs.send.amount', {
|
||||
toAddress: addr
|
||||
toAddress: addr,
|
||||
coin: coin
|
||||
});
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
// data extensions for Payment Protocol with non-backwards-compatible request
|
||||
if ((/^bitcoin:\?r=[\w+]/).exec(data)) {
|
||||
data = decodeURIComponent(data.replace('bitcoin:?r=', ''));
|
||||
if ((/^bitcoin(cash)?:\?r=[\w+]/).exec(data)) {
|
||||
data = decodeURIComponent(data.replace(/bitcoin(cash)?:\?r=/, ''));
|
||||
$state.go('tabs.send', {}, {
|
||||
'reload': true,
|
||||
'notify': $state.current.name == 'tabs.send' ? false : true
|
||||
|
|
@ -82,27 +84,97 @@ angular.module('copayApp.services').factory('incomingData', function($log, $stat
|
|||
|
||||
data = sanitizeUri(data);
|
||||
|
||||
// BIP21
|
||||
// Bitcoin URL
|
||||
if (bitcore.URI.isValid(data)) {
|
||||
var parsed = new bitcore.URI(data);
|
||||
var coin = 'btc';
|
||||
var parsed = new bitcore.URI(data);
|
||||
|
||||
var addr = parsed.address ? parsed.address.toString() : '';
|
||||
var message = parsed.message;
|
||||
var addr = parsed.address ? parsed.address.toString() : '';
|
||||
var message = parsed.message;
|
||||
|
||||
var amount = parsed.amount ? parsed.amount : '';
|
||||
var amount = parsed.amount ? parsed.amount : '';
|
||||
|
||||
if (parsed.r) {
|
||||
payproService.getPayProDetails(parsed.r, function(err, details) {
|
||||
if (err) {
|
||||
if (addr && amount) goSend(addr, amount, message);
|
||||
else popupService.showAlert(gettextCatalog.getString('Error'), err);
|
||||
} else handlePayPro(details);
|
||||
});
|
||||
} else {
|
||||
goSend(addr, amount, message);
|
||||
}
|
||||
if (parsed.r) {
|
||||
payproService.getPayProDetails(parsed.r, function(err, details) {
|
||||
if (err) {
|
||||
if (addr && amount) goSend(addr, amount, message, coin);
|
||||
else popupService.showAlert(gettextCatalog.getString('Error'), err);
|
||||
} else handlePayPro(details);
|
||||
});
|
||||
} else {
|
||||
goSend(addr, amount, message, coin);
|
||||
}
|
||||
return true;
|
||||
// Cash URI
|
||||
} else if (bitcoreCash.URI.isValid(data)) {
|
||||
var coin = 'bch';
|
||||
var parsed = new bitcoreCash.URI(data);
|
||||
|
||||
var addr = parsed.address ? parsed.address.toString() : '';
|
||||
var message = parsed.message;
|
||||
|
||||
var amount = parsed.amount ? parsed.amount : '';
|
||||
|
||||
// paypro not yet supported on cash
|
||||
if (parsed.r) {
|
||||
payproService.getPayProDetails(parsed.r, function(err, details) {
|
||||
if (err) {
|
||||
if (addr && amount)
|
||||
goSend(addr, amount, message, coin);
|
||||
else
|
||||
popupService.showAlert(gettextCatalog.getString('Error'), err);
|
||||
}
|
||||
handlePayPro(details, coin);
|
||||
});
|
||||
} else {
|
||||
goSend(addr, amount, message, coin);
|
||||
}
|
||||
return true;
|
||||
|
||||
// Cash URI with bitcoin core address version number?
|
||||
} else if (bitcore.URI.isValid(data.replace(/^bitcoincash:/,'bitcoin:'))) {
|
||||
$log.debug('Handling bitcoincash URI with legacy address');
|
||||
var coin = 'bch';
|
||||
var parsed = new bitcore.URI(data.replace(/^bitcoincash:/,'bitcoin:'));
|
||||
|
||||
var oldAddr = parsed.address ? parsed.address.toString() : '';
|
||||
if (!oldAddr) return false;
|
||||
|
||||
var addr = '';
|
||||
|
||||
var a = bitcore.Address(oldAddr).toObject();
|
||||
addr = bitcoreCash.Address.fromObject(a).toString();
|
||||
|
||||
// Translate address
|
||||
$log.debug('address transalated to:' + addr);
|
||||
popupService.showConfirm(
|
||||
gettextCatalog.getString('Bitcoin cash Payment'),
|
||||
gettextCatalog.getString('Payment address was translated to new Bitcoin Cash address format: ' + addr),
|
||||
gettextCatalog.getString('OK'),
|
||||
gettextCatalog.getString('Cancel'),
|
||||
function(ret) {
|
||||
if (!ret) return false;
|
||||
|
||||
var message = parsed.message;
|
||||
var amount = parsed.amount ? parsed.amount : '';
|
||||
|
||||
// paypro not yet supported on cash
|
||||
if (parsed.r) {
|
||||
payproService.getPayProDetails(parsed.r, function(err, details) {
|
||||
if (err) {
|
||||
if (addr && amount)
|
||||
goSend(addr, amount, message, coin);
|
||||
else
|
||||
popupService.showAlert(gettextCatalog.getString('Error'), err);
|
||||
}
|
||||
handlePayPro(details, coin);
|
||||
});
|
||||
} else {
|
||||
goSend(addr, amount, message, coin);
|
||||
}
|
||||
}
|
||||
);
|
||||
return true;
|
||||
|
||||
// Plain URL
|
||||
} else if (/^https?:\/\//.test(data)) {
|
||||
|
||||
|
|
@ -127,6 +199,16 @@ angular.module('copayApp.services').factory('incomingData', function($log, $stat
|
|||
} else {
|
||||
goToAmountPage(data);
|
||||
}
|
||||
} else if (bitcoreCash.Address.isValid(data, 'livenet')) {
|
||||
if ($state.includes('tabs.scan')) {
|
||||
root.showMenu({
|
||||
data: data,
|
||||
type: 'bitcoinAddress',
|
||||
coin: 'bch',
|
||||
});
|
||||
} else {
|
||||
goToAmountPage(data, 'bch');
|
||||
}
|
||||
} else if (data && data.indexOf(appConfigService.name + '://glidera') === 0) {
|
||||
var code = getParameterByName('code', data);
|
||||
$ionicHistory.nextViewOptions({
|
||||
|
|
@ -236,29 +318,29 @@ angular.module('copayApp.services').factory('incomingData', function($log, $stat
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
};
|
||||
|
||||
function goToAmountPage(toAddress) {
|
||||
function goToAmountPage(toAddress, coin) {
|
||||
$state.go('tabs.send', {}, {
|
||||
'reload': true,
|
||||
'notify': $state.current.name == 'tabs.send' ? false : true
|
||||
});
|
||||
$timeout(function() {
|
||||
$state.transitionTo('tabs.send.amount', {
|
||||
toAddress: toAddress
|
||||
toAddress: toAddress,
|
||||
coin: coin,
|
||||
});
|
||||
}, 100);
|
||||
}
|
||||
|
||||
function handlePayPro(payProDetails) {
|
||||
function handlePayPro(payProDetails, coin) {
|
||||
var stateParams = {
|
||||
toAmount: payProDetails.amount,
|
||||
toAddress: payProDetails.toAddress,
|
||||
description: payProDetails.memo,
|
||||
paypro: payProDetails
|
||||
paypro: payProDetails,
|
||||
coin: coin,
|
||||
};
|
||||
scannerService.pausePreview();
|
||||
$state.go('tabs.send', {}, {
|
||||
|
|
|
|||
183
src/js/services/mercadoLibreService.js
Normal file
183
src/js/services/mercadoLibreService.js
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
'use strict';
|
||||
angular.module('copayApp.services').factory('mercadoLibreService', function($http, $log, lodash, moment, storageService, configService, platformInfo, nextStepsService, homeIntegrationsService) {
|
||||
var root = {};
|
||||
var credentials = {};
|
||||
|
||||
// Not used yet
|
||||
var availableCountries = [{
|
||||
'country': 'Brazil',
|
||||
'currency': 'BRL',
|
||||
'name': 'Mercado Livre',
|
||||
'url': 'https://www.mercadolivre.com.br'
|
||||
}];
|
||||
|
||||
/*
|
||||
* Development: 'testnet'
|
||||
* Production: 'livenet'
|
||||
*/
|
||||
credentials.NETWORK = 'livenet';
|
||||
//credentials.NETWORK = 'testnet';
|
||||
|
||||
if (credentials.NETWORK == 'testnet') {
|
||||
credentials.BITPAY_API_URL = "https://test.bitpay.com";
|
||||
} else {
|
||||
credentials.BITPAY_API_URL = "https://bitpay.com";
|
||||
};
|
||||
|
||||
var homeItem = {
|
||||
name: 'mercadoLibre',
|
||||
title: 'Vales-Presente do Mercado Livre Brasil',
|
||||
icon: 'icon-ml',
|
||||
sref: 'tabs.giftcards.mercadoLibre',
|
||||
};
|
||||
|
||||
var nextStepItem = {
|
||||
name: 'mercadoLibre',
|
||||
title: 'Comprar um Vale-Presente Mercado Livre',
|
||||
icon: 'icon-ml',
|
||||
sref: 'tabs.giftcards.mercadoLibre',
|
||||
};
|
||||
|
||||
var _getBitPay = function(endpoint) {
|
||||
return {
|
||||
method: 'GET',
|
||||
url: credentials.BITPAY_API_URL + endpoint,
|
||||
headers: {
|
||||
'content-type': 'application/json'
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
var _postBitPay = function(endpoint, data) {
|
||||
return {
|
||||
method: 'POST',
|
||||
url: credentials.BITPAY_API_URL + endpoint,
|
||||
headers: {
|
||||
'content-type': 'application/json'
|
||||
},
|
||||
data: data
|
||||
};
|
||||
};
|
||||
|
||||
root.getNetwork = function() {
|
||||
return credentials.NETWORK;
|
||||
};
|
||||
|
||||
root.savePendingGiftCard = function(gc, opts, cb) {
|
||||
var network = root.getNetwork();
|
||||
storageService.getMercadoLibreGiftCards(network, function(err, oldGiftCards) {
|
||||
if (lodash.isString(oldGiftCards)) {
|
||||
oldGiftCards = JSON.parse(oldGiftCards);
|
||||
}
|
||||
if (lodash.isString(gc)) {
|
||||
gc = JSON.parse(gc);
|
||||
}
|
||||
var inv = oldGiftCards || {};
|
||||
inv[gc.invoiceId] = gc;
|
||||
if (opts && (opts.error || opts.status)) {
|
||||
inv[gc.invoiceId] = lodash.assign(inv[gc.invoiceId], opts);
|
||||
}
|
||||
if (opts && opts.remove) {
|
||||
delete(inv[gc.invoiceId]);
|
||||
}
|
||||
|
||||
inv = JSON.stringify(inv);
|
||||
|
||||
|
||||
storageService.setMercadoLibreGiftCards(network, inv, function(err) {
|
||||
|
||||
homeIntegrationsService.register(homeItem);
|
||||
nextStepsService.unregister(nextStepItem.name);
|
||||
return cb(err);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
root.getPendingGiftCards = function(cb) {
|
||||
var network = root.getNetwork();
|
||||
storageService.getMercadoLibreGiftCards(network, function(err, giftCards) {
|
||||
var _gcds = giftCards ? JSON.parse(giftCards) : null;
|
||||
return cb(err, _gcds);
|
||||
});
|
||||
};
|
||||
|
||||
root.createBitPayInvoice = function(data, cb) {
|
||||
var dataSrc = {
|
||||
currency: data.currency,
|
||||
amount: data.amount,
|
||||
clientId: data.uuid
|
||||
};
|
||||
|
||||
$http(_postBitPay('/mercado-libre-gift/pay', dataSrc)).then(function(data) {
|
||||
$log.info('BitPay Create Invoice: SUCCESS');
|
||||
return cb(null, data.data);
|
||||
}, function(data) {
|
||||
$log.error('BitPay Create Invoice: ERROR', JSON.stringify(data.data));
|
||||
return cb(data.data);
|
||||
});
|
||||
};
|
||||
|
||||
root.getBitPayInvoice = function(id, cb) {
|
||||
$http(_getBitPay('/invoices/' + id)).then(function(data) {
|
||||
$log.info('BitPay Get Invoice: SUCCESS');
|
||||
return cb(null, data.data.data);
|
||||
}, function(data) {
|
||||
$log.error('BitPay Get Invoice: ERROR', JSON.stringify(data.data));
|
||||
return cb(data.data);
|
||||
});
|
||||
};
|
||||
|
||||
root.createGiftCard = function(data, cb) {
|
||||
var dataSrc = {
|
||||
"clientId": data.uuid,
|
||||
"invoiceId": data.invoiceId,
|
||||
"accessKey": data.accessKey
|
||||
};
|
||||
|
||||
$http(_postBitPay('/mercado-libre-gift/redeem', dataSrc)).then(function(data) {
|
||||
var status = data.data.status == 'new' ? 'PENDING' : (data.data.status == 'paid') ? 'PENDING' : data.data.status;
|
||||
data.data.status = status;
|
||||
$log.info('Mercado Libre Gift Card Create/Update: ' + status);
|
||||
return cb(null, data.data);
|
||||
}, function(data) {
|
||||
$log.error('Mercado Libre Gift Card Create/Update: ERROR', JSON.stringify(data.data));
|
||||
return cb(data.data);
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
* Disabled for now *
|
||||
*/
|
||||
/*
|
||||
root.cancelGiftCard = function(data, cb) {
|
||||
|
||||
var dataSrc = {
|
||||
"clientId": data.uuid,
|
||||
"invoiceId": data.invoiceId,
|
||||
"accessKey": data.accessKey
|
||||
};
|
||||
|
||||
$http(_postBitPay('/mercado-libre-gift/cancel', dataSrc)).then(function(data) {
|
||||
$log.info('Mercado Libre Gift Card Cancel: SUCCESS');
|
||||
return cb(null, data.data);
|
||||
}, function(data) {
|
||||
$log.error('Mercado Libre Gift Card Cancel: ' + data.data.message);
|
||||
return cb(data.data);
|
||||
});
|
||||
};
|
||||
*/
|
||||
|
||||
var register = function() {
|
||||
storageService.getMercadoLibreGiftCards(root.getNetwork(), function(err, giftCards) {
|
||||
if (giftCards) {
|
||||
homeIntegrationsService.register(homeItem);
|
||||
} else {
|
||||
nextStepsService.register(nextStepItem);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Hide Mercado Libre
|
||||
// register();
|
||||
return root;
|
||||
});
|
||||
|
|
@ -45,7 +45,8 @@ angular.module('copayApp.services').factory('ongoingProcess', function($log, $ti
|
|||
'cancelingGiftCard': 'Canceling Gift Card...',
|
||||
'creatingGiftCard': 'Creating Gift Card...',
|
||||
'buyingGiftCard': 'Buying Gift Card...',
|
||||
'topup': gettext('Top up in progress...')
|
||||
'topup': gettext('Top up in progress...'),
|
||||
'duplicatingWallet': gettext('Duplicating wallet...'),
|
||||
};
|
||||
|
||||
root.clear = function() {
|
||||
|
|
|
|||
|
|
@ -57,10 +57,10 @@ angular.module('copayApp.services').factory('openURLService', function($rootScop
|
|||
|
||||
// This event is sent to an existent instance of Copay (only for standalone apps)
|
||||
gui.App.on('open', function(pathData) {
|
||||
if (pathData.indexOf('bitcoin:') != -1) {
|
||||
if (pathData.indexOf(/^bitcoin(cash)?:/) != -1) {
|
||||
$log.debug('Bitcoin URL found');
|
||||
handleOpenURL({
|
||||
url: pathData.substring(pathData.indexOf('bitcoin:'))
|
||||
url: pathData.substring(pathData.indexOf(/^bitcoin(cash)?:/))
|
||||
});
|
||||
} else if (pathData.indexOf(appConfigService.name + '://') != -1) {
|
||||
$log.debug(appConfigService.name + ' URL found');
|
||||
|
|
@ -84,6 +84,7 @@ angular.module('copayApp.services').factory('openURLService', function($rootScop
|
|||
if (navigator.registerProtocolHandler) {
|
||||
$log.debug('Registering Browser handlers base:' + base);
|
||||
navigator.registerProtocolHandler('bitcoin', url, 'Copay Bitcoin Handler');
|
||||
navigator.registerProtocolHandler('web+bitcoincash', url, 'Copay Bitcoin Cash Handler');
|
||||
navigator.registerProtocolHandler('web+copay', url, 'Copay Wallet Handler');
|
||||
navigator.registerProtocolHandler('web+bitpay', url, 'BitPay Wallet Handler');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
'use strict';
|
||||
angular.module('copayApp.services')
|
||||
.factory('profileService', function profileServiceFactory($rootScope, $timeout, $filter, $log, sjcl, lodash, storageService, bwcService, configService, gettextCatalog, bwcError, uxLanguage, platformInfo, txFormatService, $state) {
|
||||
.factory('profileService', function profileServiceFactory($rootScope, $timeout, $filter, $log, $state, sjcl, lodash, storageService, bwcService, configService, gettextCatalog, bwcError, uxLanguage, platformInfo, txFormatService, appConfigService) {
|
||||
|
||||
|
||||
var isChromeApp = platformInfo.isChromeApp;
|
||||
|
|
@ -89,6 +89,7 @@ angular.module('copayApp.services')
|
|||
wallet.copayerId = wallet.credentials.copayerId;
|
||||
wallet.m = wallet.credentials.m;
|
||||
wallet.n = wallet.credentials.n;
|
||||
wallet.coin = wallet.credentials.coin;
|
||||
|
||||
root.updateWalletSettings(wallet);
|
||||
root.wallet[walletId] = wallet;
|
||||
|
|
@ -222,11 +223,12 @@ angular.module('copayApp.services')
|
|||
return ((config.bwsFor && config.bwsFor[walletId]) || defaults.bws.url);
|
||||
};
|
||||
|
||||
|
||||
var client = bwcService.getClient(JSON.stringify(credentials), {
|
||||
bwsurl: getBWSURL(credentials.walletId),
|
||||
});
|
||||
|
||||
|
||||
|
||||
var skipKeyValidation = shouldSkipValidation(credentials.walletId);
|
||||
if (!skipKeyValidation)
|
||||
root.runValidation(client, 500);
|
||||
|
|
@ -328,6 +330,7 @@ angular.module('copayApp.services')
|
|||
passphrase: opts.passphrase,
|
||||
account: opts.account || 0,
|
||||
derivationStrategy: opts.derivationStrategy || 'BIP44',
|
||||
coin: opts.coin
|
||||
});
|
||||
|
||||
} catch (ex) {
|
||||
|
|
@ -336,7 +339,12 @@ angular.module('copayApp.services')
|
|||
}
|
||||
} else if (opts.extendedPrivateKey) {
|
||||
try {
|
||||
walletClient.seedFromExtendedPrivateKey(opts.extendedPrivateKey);
|
||||
walletClient.seedFromExtendedPrivateKey(opts.extendedPrivateKey, {
|
||||
network: network,
|
||||
account: opts.account || 0,
|
||||
derivationStrategy: opts.derivationStrategy || 'BIP44',
|
||||
coin: opts.coin,
|
||||
});
|
||||
} catch (ex) {
|
||||
$log.warn(ex);
|
||||
return cb(gettextCatalog.getString('Could not create using the specified extended private key'));
|
||||
|
|
@ -346,6 +354,7 @@ angular.module('copayApp.services')
|
|||
walletClient.seedFromExtendedPublicKey(opts.extendedPublicKey, opts.externalSource, opts.entropySource, {
|
||||
account: opts.account || 0,
|
||||
derivationStrategy: opts.derivationStrategy || 'BIP44',
|
||||
coin: opts.coin
|
||||
});
|
||||
walletClient.credentials.hwInfo = opts.hwInfo;
|
||||
} catch (ex) {
|
||||
|
|
@ -360,6 +369,7 @@ angular.module('copayApp.services')
|
|||
passphrase: opts.passphrase,
|
||||
language: lang,
|
||||
account: 0,
|
||||
coin: opts.coin
|
||||
});
|
||||
} catch (e) {
|
||||
$log.info('Error creating recovery phrase: ' + e.message);
|
||||
|
|
@ -369,6 +379,7 @@ angular.module('copayApp.services')
|
|||
network: network,
|
||||
passphrase: opts.passphrase,
|
||||
account: 0,
|
||||
coin: opts.coin
|
||||
});
|
||||
} else {
|
||||
return cb(e);
|
||||
|
|
@ -380,7 +391,11 @@ angular.module('copayApp.services')
|
|||
|
||||
// Creates a wallet on BWC/BWS
|
||||
var doCreateWallet = function(opts, cb) {
|
||||
$log.debug('Creating Wallet:', opts);
|
||||
var showOpts = lodash.clone(opts);
|
||||
if (showOpts.extendedPrivateKey) showOpts.extendedPrivateKey='[hidden]';
|
||||
if (showOpts.mnemonic) showOpts.mnemonic='[hidden]';
|
||||
|
||||
$log.debug('Creating Wallet:', showOpts);
|
||||
$timeout(function() {
|
||||
seedWallet(opts, function(err, walletClient) {
|
||||
if (err) return cb(err);
|
||||
|
|
@ -392,6 +407,7 @@ angular.module('copayApp.services')
|
|||
network: opts.networkName,
|
||||
singleAddress: opts.singleAddress,
|
||||
walletPrivKey: opts.walletPrivKey,
|
||||
coin: opts.coin
|
||||
}, function(err, secret) {
|
||||
if (err) return bwcError.cb(err, gettextCatalog.getString('Error creating wallet'), cb);
|
||||
return cb(null, walletClient, secret);
|
||||
|
|
@ -435,7 +451,9 @@ angular.module('copayApp.services')
|
|||
seedWallet(opts, function(err, walletClient) {
|
||||
if (err) return cb(err);
|
||||
|
||||
walletClient.joinWallet(opts.secret, opts.myName || 'me', {}, function(err) {
|
||||
walletClient.joinWallet(opts.secret, opts.myName || 'me', {
|
||||
coin: opts.coin
|
||||
}, function(err) {
|
||||
if (err) return bwcError.cb(err, gettextCatalog.getString('Could not join wallet'), cb);
|
||||
addAndBindWalletClient(walletClient, {
|
||||
bwsurl: opts.bwsurl
|
||||
|
|
@ -495,7 +513,9 @@ angular.module('copayApp.services')
|
|||
var walletId = client.credentials.walletId
|
||||
|
||||
if (!root.profile.addWallet(JSON.parse(client.export())))
|
||||
return cb(gettextCatalog.getString('Wallet already in Copay'));
|
||||
return cb(gettextCatalog.getString("Wallet already in {{appName}}", {
|
||||
appName: appConfigService.nameCase
|
||||
}));
|
||||
|
||||
|
||||
var skipKeyValidation = shouldSkipValidation(walletId);
|
||||
|
|
@ -621,6 +641,7 @@ angular.module('copayApp.services')
|
|||
entropySourcePath: opts.entropySourcePath,
|
||||
derivationStrategy: opts.derivationStrategy || 'BIP44',
|
||||
account: opts.account || 0,
|
||||
coin: opts.coin
|
||||
}, function(err) {
|
||||
if (err) {
|
||||
if (err instanceof errors.NOT_AUTHORIZED)
|
||||
|
|
@ -642,6 +663,7 @@ angular.module('copayApp.services')
|
|||
walletClient.importFromExtendedPublicKey(opts.extendedPublicKey, opts.externalSource, opts.entropySource, {
|
||||
account: opts.account || 0,
|
||||
derivationStrategy: opts.derivationStrategy || 'BIP44',
|
||||
coin: opts.coin
|
||||
}, function(err) {
|
||||
if (err) {
|
||||
|
||||
|
|
@ -682,6 +704,7 @@ angular.module('copayApp.services')
|
|||
opts.m = 1;
|
||||
opts.n = 1;
|
||||
opts.networkName = 'livenet';
|
||||
opts.coin = 'btc';
|
||||
root.createWallet(opts, cb);
|
||||
};
|
||||
|
||||
|
|
@ -747,6 +770,12 @@ angular.module('copayApp.services')
|
|||
|
||||
var ret = lodash.values(root.wallet);
|
||||
|
||||
if (opts.coin) {
|
||||
ret = lodash.filter(ret, function(x) {
|
||||
return (x.credentials.coin == opts.coin);
|
||||
});
|
||||
}
|
||||
|
||||
if (opts.network) {
|
||||
ret = lodash.filter(ret, function(x) {
|
||||
return (x.credentials.network == opts.network);
|
||||
|
|
@ -767,12 +796,14 @@ angular.module('copayApp.services')
|
|||
|
||||
if (opts.hasFunds) {
|
||||
ret = lodash.filter(ret, function(w) {
|
||||
if (!w.status) return;
|
||||
return (w.status.availableBalanceSat > 0);
|
||||
});
|
||||
}
|
||||
|
||||
if (opts.minAmount) {
|
||||
ret = lodash.filter(ret, function(w) {
|
||||
if (!w.status) return;
|
||||
return (w.status.availableBalanceSat > opts.minAmount);
|
||||
});
|
||||
}
|
||||
|
|
@ -857,7 +888,7 @@ angular.module('copayApp.services')
|
|||
x.types = [x.type];
|
||||
|
||||
if (x.data && x.data.amount)
|
||||
x.amountStr = txFormatService.formatAmountStr(x.data.amount);
|
||||
x.amountStr = txFormatService.formatAmountStr(x.wallet.coin, x.data.amount);
|
||||
|
||||
x.action = function() {
|
||||
// TODO?
|
||||
|
|
|
|||
|
|
@ -25,9 +25,10 @@ var RateService = function(opts) {
|
|||
self._isAvailable = false;
|
||||
self._rates = {};
|
||||
self._alternatives = [];
|
||||
self._ratesBCH = {};
|
||||
self._queued = [];
|
||||
|
||||
self._fetchCurrencies();
|
||||
self.updateRates();
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -39,14 +40,20 @@ RateService.singleton = function(opts) {
|
|||
return _instance;
|
||||
};
|
||||
|
||||
RateService.prototype._fetchCurrencies = function() {
|
||||
RateService.prototype.updateRates = function() {
|
||||
var self = this;
|
||||
|
||||
var backoffSeconds = 5;
|
||||
var updateFrequencySeconds = 5 * 60;
|
||||
var rateServiceUrl = 'https://bitpay.com/api/rates';
|
||||
var bchRateServiceUrl = 'https://api.kraken.com/0/public/Ticker?pair=BCHUSD,BCHEUR';
|
||||
|
||||
|
||||
function getBTC(cb, tries) {
|
||||
tries = tries || 0;
|
||||
if (!self.httprequest) return;
|
||||
if (tries > 5) return cb('could not get BTC rates');
|
||||
|
||||
var retrieve = function() {
|
||||
//log.info('Fetching exchange rates');
|
||||
self.httprequest.get(rateServiceUrl).success(function(res) {
|
||||
self.lodash.each(res, function(currency) {
|
||||
|
|
@ -57,27 +64,64 @@ RateService.prototype._fetchCurrencies = function() {
|
|||
rate: currency.rate
|
||||
});
|
||||
});
|
||||
|
||||
return cb();
|
||||
}).error(function() {
|
||||
//log.debug('Error fetching exchange rates', err);
|
||||
setTimeout(function() {
|
||||
backoffSeconds *= 1.5;
|
||||
getBTC(cb, tries++);
|
||||
}, backoffSeconds * 1000);
|
||||
return;
|
||||
})
|
||||
}
|
||||
|
||||
function getBCH(cb, tries) {
|
||||
tries = tries || 0;
|
||||
if (!self.httprequest) return;
|
||||
if (tries > 5) return cb('could not get BCH rates');
|
||||
|
||||
function retry(tries) {
|
||||
//log.debug('Error fetching exchange rates', err);
|
||||
setTimeout(function() {
|
||||
backoffSeconds *= 1.5;
|
||||
getBTC(cb, tries++);
|
||||
}, backoffSeconds * 1000);
|
||||
return;
|
||||
}
|
||||
|
||||
self.httprequest.get(bchRateServiceUrl).success(function(res) {
|
||||
self.lodash.each(res.result, function(data, paircode) {
|
||||
var code = paircode.substr(3,3);
|
||||
var rate =data.c[0];
|
||||
self._ratesBCH[code] = rate;
|
||||
})
|
||||
return cb();
|
||||
}).error(function() {
|
||||
return retry(tries);
|
||||
})
|
||||
}
|
||||
|
||||
getBTC(function(err) {
|
||||
if (err) return;
|
||||
getBCH(function(err) {
|
||||
if (err) return;
|
||||
|
||||
self._isAvailable = true;
|
||||
self.lodash.each(self._queued, function(callback) {
|
||||
setTimeout(callback, 1);
|
||||
});
|
||||
setTimeout(retrieve, updateFrequencySeconds * 1000);
|
||||
}).error(function(err) {
|
||||
//log.debug('Error fetching exchange rates', err);
|
||||
setTimeout(function() {
|
||||
backoffSeconds *= 1.5;
|
||||
retrieve();
|
||||
}, backoffSeconds * 1000);
|
||||
return;
|
||||
});
|
||||
setTimeout( self.updateRates , updateFrequencySeconds * 1000);
|
||||
})
|
||||
})
|
||||
|
||||
};
|
||||
|
||||
retrieve();
|
||||
};
|
||||
|
||||
RateService.prototype.getRate = function(code) {
|
||||
return this._rates[code];
|
||||
RateService.prototype.getRate = function(code, chain) {
|
||||
if (chain == 'bch')
|
||||
return this._ratesBCH[code];
|
||||
else
|
||||
return this._rates[code];
|
||||
};
|
||||
|
||||
RateService.prototype.getAlternatives = function() {
|
||||
|
|
@ -90,25 +134,25 @@ RateService.prototype.isAvailable = function() {
|
|||
|
||||
RateService.prototype.whenAvailable = function(callback) {
|
||||
if (this.isAvailable()) {
|
||||
setTimeout(callback, 1);
|
||||
setTimeout(callback, 10);
|
||||
} else {
|
||||
this._queued.push(callback);
|
||||
}
|
||||
};
|
||||
|
||||
RateService.prototype.toFiat = function(satoshis, code) {
|
||||
RateService.prototype.toFiat = function(satoshis, code, chain) {
|
||||
if (!this.isAvailable()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return satoshis * this.SAT_TO_BTC * this.getRate(code);
|
||||
return satoshis * this.SAT_TO_BTC * this.getRate(code, chain);
|
||||
};
|
||||
|
||||
RateService.prototype.fromFiat = function(amount, code) {
|
||||
RateService.prototype.fromFiat = function(amount, code, chain) {
|
||||
if (!this.isAvailable()) {
|
||||
return null;
|
||||
}
|
||||
return amount / this.getRate(code) * this.BTC_TO_SAT;
|
||||
return amount / this.getRate(code, chain) * this.BTC_TO_SAT;
|
||||
};
|
||||
|
||||
RateService.prototype.listAlternatives = function(sort) {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ angular.module('copayApp.services').service('sendMaxService', function(feeServic
|
|||
*
|
||||
*/
|
||||
this.getInfo = function(wallet, cb) {
|
||||
feeService.getCurrentFeeRate(wallet.credentials.network, function(err, feePerKb) {
|
||||
feeService.getCurrentFeeRate(wallet.coin, wallet.credentials.network, function(err, feePerKb) {
|
||||
if (err) return cb(err);
|
||||
|
||||
var config = configService.getSync().wallet;
|
||||
|
|
|
|||
|
|
@ -610,5 +610,17 @@ angular.module('copayApp.services')
|
|||
storage.remove('txConfirmNotif-' + txid, cb);
|
||||
};
|
||||
|
||||
root.setMercadoLibreGiftCards = function(network, gcs, cb) {
|
||||
storage.set('mercadoLibreGiftCards-' + network, gcs, cb);
|
||||
};
|
||||
|
||||
root.getMercadoLibreGiftCards = function(network, cb) {
|
||||
storage.get('mercadoLibreGiftCards-' + network, cb);
|
||||
};
|
||||
|
||||
root.removeMercadoLibreGiftCards = function(network, cb) {
|
||||
storage.remove('MercadoLibreGiftCards-' + network, cb);
|
||||
};
|
||||
|
||||
return root;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ angular.module('copayApp.services').factory('txFormatService', function($filter,
|
|||
|
||||
|
||||
root.formatAmount = function(satoshis, fullPrecision) {
|
||||
var config = configService.getSync().wallet.settings;
|
||||
var config = configService.getDefaults().wallet.settings;
|
||||
if (config.unitCode == 'sat') return satoshis;
|
||||
|
||||
//TODO : now only works for english, specify opts to change thousand separator and decimal separator
|
||||
|
|
@ -17,16 +17,15 @@ angular.module('copayApp.services').factory('txFormatService', function($filter,
|
|||
return this.Utils.formatAmount(satoshis, config.unitCode, opts);
|
||||
};
|
||||
|
||||
root.formatAmountStr = function(satoshis) {
|
||||
root.formatAmountStr = function(coin, satoshis) {
|
||||
if (isNaN(satoshis)) return;
|
||||
var config = configService.getSync().wallet.settings;
|
||||
return root.formatAmount(satoshis) + ' ' + config.unitName;
|
||||
return root.formatAmount(satoshis) + ' ' + (coin).toUpperCase();
|
||||
};
|
||||
|
||||
root.toFiat = function(satoshis, code, cb) {
|
||||
root.toFiat = function(coin, satoshis, code, cb) {
|
||||
if (isNaN(satoshis)) return;
|
||||
var val = function() {
|
||||
var v1 = rateService.toFiat(satoshis, code);
|
||||
var v1 = rateService.toFiat(satoshis, code, coin);
|
||||
if (!v1) return null;
|
||||
|
||||
return v1.toFixed(2);
|
||||
|
|
@ -43,10 +42,10 @@ angular.module('copayApp.services').factory('txFormatService', function($filter,
|
|||
};
|
||||
};
|
||||
|
||||
root.formatToUSD = function(satoshis, cb) {
|
||||
root.formatToUSD = function(coin, satoshis, cb) {
|
||||
if (isNaN(satoshis)) return;
|
||||
var val = function() {
|
||||
var v1 = rateService.toFiat(satoshis, 'USD');
|
||||
var v1 = rateService.toFiat(satoshis, 'USD', coin);
|
||||
if (!v1) return null;
|
||||
|
||||
return v1.toFixed(2);
|
||||
|
|
@ -63,12 +62,12 @@ angular.module('copayApp.services').factory('txFormatService', function($filter,
|
|||
};
|
||||
};
|
||||
|
||||
root.formatAlternativeStr = function(satoshis, cb) {
|
||||
root.formatAlternativeStr = function(coin, satoshis, cb) {
|
||||
if (isNaN(satoshis)) return;
|
||||
var config = configService.getSync().wallet.settings;
|
||||
|
||||
var val = function() {
|
||||
var v1 = parseFloat((rateService.toFiat(satoshis, config.alternativeIsoCode)).toFixed(2));
|
||||
var v1 = parseFloat((rateService.toFiat(satoshis, config.alternativeIsoCode, coin)).toFixed(2));
|
||||
v1 = $filter('formatFiatAmount')(v1);
|
||||
if (!v1) return null;
|
||||
|
||||
|
|
@ -86,7 +85,7 @@ angular.module('copayApp.services').factory('txFormatService', function($filter,
|
|||
};
|
||||
};
|
||||
|
||||
root.processTx = function(tx) {
|
||||
root.processTx = function(coin, tx) {
|
||||
if (!tx || tx.action == 'invalid')
|
||||
return tx;
|
||||
|
||||
|
|
@ -101,17 +100,17 @@ angular.module('copayApp.services').factory('txFormatService', function($filter,
|
|||
tx.hasMultiplesOutputs = true;
|
||||
}
|
||||
tx.amount = lodash.reduce(tx.outputs, function(total, o) {
|
||||
o.amountStr = root.formatAmountStr(o.amount);
|
||||
o.alternativeAmountStr = root.formatAlternativeStr(o.amount);
|
||||
o.amountStr = root.formatAmountStr(coin, o.amount);
|
||||
o.alternativeAmountStr = root.formatAlternativeStr(coin, o.amount);
|
||||
return total + o.amount;
|
||||
}, 0);
|
||||
}
|
||||
tx.toAddress = tx.outputs[0].toAddress;
|
||||
}
|
||||
|
||||
tx.amountStr = root.formatAmountStr(tx.amount);
|
||||
tx.alternativeAmountStr = root.formatAlternativeStr(tx.amount);
|
||||
tx.feeStr = root.formatAmountStr(tx.fee || tx.fees);
|
||||
tx.amountStr = root.formatAmountStr(coin, tx.amount);
|
||||
tx.alternativeAmountStr = root.formatAlternativeStr(coin, tx.amount);
|
||||
tx.feeStr = root.formatAmountStr(coin, tx.fee || tx.fees);
|
||||
|
||||
if (tx.amountStr) {
|
||||
tx.amountValueStr = tx.amountStr.split(' ')[0];
|
||||
|
|
@ -145,8 +144,6 @@ angular.module('copayApp.services').factory('txFormatService', function($filter,
|
|||
|
||||
lodash.each(txps, function(tx) {
|
||||
|
||||
tx = txFormatService.processTx(tx);
|
||||
|
||||
// no future transactions...
|
||||
if (tx.createdOn > now)
|
||||
tx.createdOn = now;
|
||||
|
|
@ -157,6 +154,8 @@ angular.module('copayApp.services').factory('txFormatService', function($filter,
|
|||
return;
|
||||
}
|
||||
|
||||
tx = txFormatService.processTx(tx.wallet.coin, tx);
|
||||
|
||||
var action = lodash.find(tx.actions, {
|
||||
copayerId: tx.wallet.copayerId
|
||||
});
|
||||
|
|
@ -180,7 +179,7 @@ angular.module('copayApp.services').factory('txFormatService', function($filter,
|
|||
return txps;
|
||||
};
|
||||
|
||||
root.parseAmount = function(amount, currency) {
|
||||
root.parseAmount = function(coin, amount, currency) {
|
||||
var config = configService.getSync().wallet.settings;
|
||||
var satToBtc = 1 / 100000000;
|
||||
var unitToSatoshi = config.unitToSatoshi;
|
||||
|
|
@ -189,21 +188,21 @@ angular.module('copayApp.services').factory('txFormatService', function($filter,
|
|||
var alternativeIsoCode = config.alternativeIsoCode;
|
||||
|
||||
// If fiat currency
|
||||
if (currency != 'bits' && currency != 'BTC' && currency != 'sat') {
|
||||
if (currency != 'BCH' && currency != 'BTC' && currency != 'sat') {
|
||||
amountUnitStr = $filter('formatFiatAmount')(amount) + ' ' + currency;
|
||||
amountSat = rateService.fromFiat(amount, currency).toFixed(0);
|
||||
amountSat = rateService.fromFiat(amount, currency, coin).toFixed(0);
|
||||
} else if (currency == 'sat') {
|
||||
amountSat = amount;
|
||||
amountUnitStr = root.formatAmountStr(amountSat);
|
||||
// convert sat to BTC
|
||||
amountUnitStr = root.formatAmountStr(coin, amountSat);
|
||||
// convert sat to BTC or BCH
|
||||
amount = (amountSat * satToBtc).toFixed(8);
|
||||
currency = 'BTC';
|
||||
currency = (coin).toUpperCase();
|
||||
} else {
|
||||
amountSat = parseInt((amount * unitToSatoshi).toFixed(0));
|
||||
amountUnitStr = root.formatAmountStr(amountSat);
|
||||
// convert unit to BTC
|
||||
amountUnitStr = root.formatAmountStr(coin, amountSat);
|
||||
// convert unit to BTC or BCH
|
||||
amount = (amountSat * satToBtc).toFixed(8);
|
||||
currency = 'BTC';
|
||||
currency = (coin).toUpperCase();
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -17,6 +17,9 @@ angular.module('copayApp.services')
|
|||
}, {
|
||||
name: 'Italiano',
|
||||
isoCode: 'it',
|
||||
}, {
|
||||
name: 'Nederlands',
|
||||
isoCode: 'nl',
|
||||
}, {
|
||||
name: 'Polski',
|
||||
isoCode: 'pl',
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
||||
// Ratio low amount warning (fee/amount) in incoming TX
|
||||
var LOW_AMOUNT_RATIO = 0.15;
|
||||
// Ratio low amount warning (fee/amount) in incoming TX
|
||||
var LOW_AMOUNT_RATIO = 0.15;
|
||||
|
||||
// Ratio of "many utxos" warning in total balance (fee/amount)
|
||||
var TOTAL_LOW_WARNING_RATIO = .3;
|
||||
|
|
@ -104,7 +104,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
|
|||
|
||||
root.getStatus = function(wallet, opts, cb) {
|
||||
opts = opts || {};
|
||||
|
||||
var walletId = wallet.id;
|
||||
|
||||
function processPendingTxps(status) {
|
||||
var txps = status.pendingTxps;
|
||||
|
|
@ -130,7 +130,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
|
|||
|
||||
lodash.each(txps, function(tx) {
|
||||
|
||||
tx = txFormatService.processTx(tx);
|
||||
tx = txFormatService.processTx(wallet.coin, tx);
|
||||
|
||||
// no future transactions...
|
||||
if (tx.createdOn > now)
|
||||
|
|
@ -213,14 +213,13 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
|
|||
// Selected unit
|
||||
cache.unitToSatoshi = config.settings.unitToSatoshi;
|
||||
cache.satToUnit = 1 / cache.unitToSatoshi;
|
||||
cache.unitName = config.settings.unitName;
|
||||
|
||||
//STR
|
||||
cache.totalBalanceStr = txFormatService.formatAmount(cache.totalBalanceSat) + ' ' + cache.unitName;
|
||||
cache.lockedBalanceStr = txFormatService.formatAmount(cache.lockedBalanceSat) + ' ' + cache.unitName;
|
||||
cache.availableBalanceStr = txFormatService.formatAmount(cache.availableBalanceSat) + ' ' + cache.unitName;
|
||||
cache.spendableBalanceStr = txFormatService.formatAmount(cache.spendableAmount) + ' ' + cache.unitName;
|
||||
cache.pendingBalanceStr = txFormatService.formatAmount(cache.pendingAmount) + ' ' + cache.unitName;
|
||||
cache.totalBalanceStr = txFormatService.formatAmountStr(wallet.coin, cache.totalBalanceSat);
|
||||
cache.lockedBalanceStr = txFormatService.formatAmountStr(wallet.coin, cache.lockedBalanceSat);
|
||||
cache.availableBalanceStr = txFormatService.formatAmountStr(wallet.coin, cache.availableBalanceSat);
|
||||
cache.spendableBalanceStr = txFormatService.formatAmountStr(wallet.coin, cache.spendableAmount);
|
||||
cache.pendingBalanceStr = txFormatService.formatAmountStr(wallet.coin, cache.pendingAmount);
|
||||
|
||||
cache.alternativeName = config.settings.alternativeName;
|
||||
cache.alternativeIsoCode = config.settings.alternativeIsoCode;
|
||||
|
|
@ -238,11 +237,11 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
|
|||
|
||||
rateService.whenAvailable(function() {
|
||||
|
||||
var totalBalanceAlternative = rateService.toFiat(cache.totalBalanceSat, cache.alternativeIsoCode);
|
||||
var pendingBalanceAlternative = rateService.toFiat(cache.pendingAmount, cache.alternativeIsoCode);
|
||||
var lockedBalanceAlternative = rateService.toFiat(cache.lockedBalanceSat, cache.alternativeIsoCode);
|
||||
var spendableBalanceAlternative = rateService.toFiat(cache.spendableAmount, cache.alternativeIsoCode);
|
||||
var alternativeConversionRate = rateService.toFiat(100000000, cache.alternativeIsoCode);
|
||||
var totalBalanceAlternative = rateService.toFiat(cache.totalBalanceSat, cache.alternativeIsoCode, wallet.coin);
|
||||
var pendingBalanceAlternative = rateService.toFiat(cache.pendingAmount, cache.alternativeIsoCode, wallet.coin);
|
||||
var lockedBalanceAlternative = rateService.toFiat(cache.lockedBalanceSat, cache.alternativeIsoCode, wallet.coin);
|
||||
var spendableBalanceAlternative = rateService.toFiat(cache.spendableAmount, cache.alternativeIsoCode, wallet.coin);
|
||||
var alternativeConversionRate = rateService.toFiat(100000000, cache.alternativeIsoCode, wallet.coin);
|
||||
|
||||
cache.totalBalanceAlternative = $filter('formatFiatAmount')(totalBalanceAlternative);
|
||||
cache.pendingBalanceAlternative = $filter('formatFiatAmount')(pendingBalanceAlternative);
|
||||
|
|
@ -260,6 +259,8 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
|
|||
};
|
||||
|
||||
function cacheStatus(status) {
|
||||
if (status.wallet && status.wallet.scanStatus == 'running') return;
|
||||
|
||||
wallet.cachedStatus = status || {};
|
||||
var cache = wallet.cachedStatus;
|
||||
cache.statusUpdatedOn = Date.now();
|
||||
|
|
@ -304,6 +305,8 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
|
|||
|
||||
cacheStatus(status);
|
||||
|
||||
wallet.scanning = status.wallet && status.wallet.scanStatus == 'running';
|
||||
|
||||
return cb(null, status);
|
||||
});
|
||||
};
|
||||
|
|
@ -366,7 +369,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
|
|||
wallet.hasUnsafeConfirmed = false;
|
||||
|
||||
lodash.each(txs, function(tx) {
|
||||
tx = txFormatService.processTx(tx);
|
||||
tx = txFormatService.processTx(wallet.coin, tx);
|
||||
|
||||
// no future transactions...
|
||||
if (tx.time > now)
|
||||
|
|
@ -400,7 +403,6 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
|
|||
var LIMIT = 50;
|
||||
var requestLimit = FIRST_LIMIT;
|
||||
var walletId = wallet.credentials.walletId;
|
||||
var config = configService.getSync().wallet.settings;
|
||||
|
||||
var opts = opts || {};
|
||||
var progressFn = opts.progressFn || function() {};
|
||||
|
|
@ -414,18 +416,16 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
|
|||
var fixTxsUnit = function(txs) {
|
||||
if (!txs || !txs[0] || !txs[0].amountStr) return;
|
||||
|
||||
var cacheUnit = txs[0].amountStr.split(' ')[1];
|
||||
var cacheCoin = txs[0].amountStr.split(' ')[1];
|
||||
|
||||
if (cacheUnit == config.unitName)
|
||||
return;
|
||||
if (cacheCoin == 'bits') {
|
||||
|
||||
var name = ' ' + config.unitName;
|
||||
|
||||
$log.debug('Fixing Tx Cache Unit to:' + name)
|
||||
lodash.each(txs, function(tx) {
|
||||
tx.amountStr = txFormatService.formatAmount(tx.amount) + name;
|
||||
tx.feeStr = txFormatService.formatAmount(tx.fees) + name;
|
||||
});
|
||||
$log.debug('Fixing Tx Cache Unit to: ' + wallet.coin)
|
||||
lodash.each(txs, function(tx) {
|
||||
tx.amountStr = txFormatService.formatAmountStr(wallet.coin, tx.amount);
|
||||
tx.feeStr = txFormatService.formatAmountStr(wallet.coin, tx.fees);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
getSavedTxs(walletId, function(err, txsFromLocal) {
|
||||
|
|
@ -788,7 +788,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
|
|||
//prefs.email (may come from arguments)
|
||||
prefs.email = config.emailNotifications.email;
|
||||
prefs.language = uxLanguage.getCurrentLanguage();
|
||||
prefs.unit = walletSettings.unitCode;
|
||||
// prefs.unit = walletSettings.unitCode; // TODO: remove, not used
|
||||
|
||||
updateRemotePreferencesFor(lodash.clone(clients), prefs, function(err) {
|
||||
if (err) return cb(err);
|
||||
|
|
@ -820,13 +820,10 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
|
|||
$log.debug('Scanning wallet ' + wallet.id);
|
||||
if (!wallet.isComplete()) return;
|
||||
|
||||
wallet.updating = true;
|
||||
ongoingProcess.set('scanning', true);
|
||||
wallet.scanning = true;
|
||||
wallet.startScan({
|
||||
includeCopayerBranches: true,
|
||||
}, function(err) {
|
||||
wallet.updating = false;
|
||||
ongoingProcess.set('scanning', false);
|
||||
return cb(err);
|
||||
});
|
||||
};
|
||||
|
|
@ -922,28 +919,30 @@ 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) {
|
||||
var lowLevelRate = (lodash.find(feeLevels[wallet.network], {
|
||||
level: 'normal',
|
||||
}).feePerKB / 1000).toFixed(0);
|
||||
}).feePerKb / 1000).toFixed(0);
|
||||
|
||||
var size = root.getEstimatedTxSize(wallet, nbOutputs);
|
||||
return size * lowLevelRate;
|
||||
};
|
||||
|
||||
|
||||
// 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) {
|
||||
var minFee = root.getMinFee(wallet,feeLevels, nbOutputs);
|
||||
return parseInt( minFee / LOW_AMOUNT_RATIO);
|
||||
var minFee = root.getMinFee(wallet, feeLevels, nbOutputs);
|
||||
return parseInt(minFee / LOW_AMOUNT_RATIO);
|
||||
};
|
||||
|
||||
|
||||
|
||||
root.getLowUtxos = function(wallet, levels, cb) {
|
||||
|
||||
wallet.getUtxos({}, function(err, resp) {
|
||||
wallet.getUtxos({
|
||||
coin: wallet.coin
|
||||
}, function(err, resp) {
|
||||
if (err || !resp || !resp.length) return cb();
|
||||
|
||||
var minFee = root.getMinFee(wallet, levels, resp.length);
|
||||
|
|
@ -959,7 +958,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
|
|||
var totalLow = lodash.sum(lowUtxos, 'satoshis');
|
||||
|
||||
return cb(err, {
|
||||
allUtxos: resp || [],
|
||||
allUtxos: resp || [],
|
||||
lowUtxos: lowUtxos || [],
|
||||
warning: minFee / balance > TOTAL_LOW_WARNING_RATIO,
|
||||
minFee: minFee,
|
||||
|
|
@ -1236,5 +1235,38 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
|
|||
});
|
||||
};
|
||||
|
||||
root.getProtocolHandler = function(wallet) {
|
||||
if (wallet.coin== 'bch') return 'bitcoincash';
|
||||
else return 'bitcoin';
|
||||
}
|
||||
|
||||
|
||||
root.copyCopayers = function(wallet, newWallet, cb) {
|
||||
var c = wallet.credentials;
|
||||
|
||||
var walletPrivKey = bitcore.PrivateKey.fromString(c.walletPrivKey);
|
||||
|
||||
var copayer = 1,
|
||||
i = 0,
|
||||
l = c.publicKeyRing.length;
|
||||
var mainErr = null;
|
||||
|
||||
lodash.each(c.publicKeyRing, function(item) {
|
||||
var name = item.copayerName || ('copayer ' + copayer++);
|
||||
newWallet._doJoinWallet(newWallet.credentials.walletId, walletPrivKey, item.xPubKey, item.requestPubKey, name, {
|
||||
coin: newWallet.credentials.coin,
|
||||
}, function(err) {
|
||||
//Ignore error is copayer already in wallet
|
||||
if (err && !(err instanceof errors.COPAYER_IN_WALLET)) {
|
||||
mainErr = err;
|
||||
}
|
||||
|
||||
if (++i == l) {
|
||||
return cb(mainErr);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return root;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -139,6 +139,19 @@
|
|||
}
|
||||
}
|
||||
.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 {
|
||||
&--minimize {
|
||||
font-size: 22px;
|
||||
|
|
@ -187,7 +200,7 @@
|
|||
&__result {
|
||||
color: $v-light-gray;
|
||||
font-size: .9em;
|
||||
margin-bottom: -.9em;
|
||||
//margin-bottom: -.9em; TODO matias
|
||||
line-height: 1;
|
||||
@media(max-height: 480px) {
|
||||
margin-bottom: 0;
|
||||
|
|
@ -196,7 +209,6 @@
|
|||
&__result-equiv {
|
||||
color: $v-mid-gray;
|
||||
font-size: 1.2em;
|
||||
margin-top: 2rem;
|
||||
@media(max-height: 480px) {
|
||||
margin-top: 0;
|
||||
font-size: 16px;
|
||||
|
|
|
|||
43
src/sass/views/cashScan.scss
Normal file
43
src/sass/views/cashScan.scss
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
#cash-scan {
|
||||
.comment {
|
||||
color: #667;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.item {
|
||||
color: $v-dark-gray;
|
||||
padding-top: 1.3rem;
|
||||
padding-bottom: 1.3rem;
|
||||
}
|
||||
|
||||
.heading {
|
||||
font-size: 17px;
|
||||
color: $v-dark-gray;
|
||||
margin: 1rem 0;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.text-disabled {
|
||||
color: $v-light-gray;
|
||||
}
|
||||
|
||||
.supported {
|
||||
display: flex;
|
||||
|
||||
.wallet-content {
|
||||
padding-left: 7px;
|
||||
}
|
||||
}
|
||||
|
||||
.duplicate-button {
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
padding-top: .5rem;
|
||||
}
|
||||
|
||||
a {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
|
@ -99,6 +99,9 @@
|
|||
i {
|
||||
padding-right: 20px;
|
||||
}
|
||||
span {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
}
|
||||
.toggle-unconfirmed {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,17 @@ wallet-selector {
|
|||
padding-right: .75rem;
|
||||
}
|
||||
|
||||
.subheader {
|
||||
margin: 20px 0 10px 0;
|
||||
font-weight: bold;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #EFEFEF;
|
||||
.wallet-coin-logo {
|
||||
vertical-align: middle;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.wallet-selector {
|
||||
.wallet {
|
||||
border: 0;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
@import "coinbase";
|
||||
@import "glidera";
|
||||
@import "amazon";
|
||||
@import "mercadolibre";
|
||||
|
||||
#coinbase, #glidera {
|
||||
.button-small {
|
||||
|
|
|
|||
202
src/sass/views/integrations/mercadolibre.scss
Normal file
202
src/sass/views/integrations/mercadolibre.scss
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
#mercadolibre {
|
||||
$item-lateral-padding: 20px;
|
||||
$item-vertical-padding: 10px;
|
||||
$item-border-color: #EFEFEF;
|
||||
$item-label-color: #6C6C6E;
|
||||
@extend .deflash-blue;
|
||||
.icon-amazon {
|
||||
background-image: url("../img/mercado-libre/icon-ml.svg");
|
||||
}
|
||||
.spinner svg {
|
||||
stroke: black;
|
||||
fill: black;
|
||||
}
|
||||
|
||||
.add-bottom-for-cta {
|
||||
bottom: 92px;
|
||||
}
|
||||
.head {
|
||||
padding: 30px $item-lateral-padding 4rem;
|
||||
border-top: 0;
|
||||
|
||||
.sending-label {
|
||||
display: flex;
|
||||
font-size: 18px;
|
||||
align-items: center;
|
||||
margin-bottom: 1.8rem;
|
||||
|
||||
img {
|
||||
margin-right: 1rem;
|
||||
height: 35px;
|
||||
width: 35px;
|
||||
}
|
||||
|
||||
span {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.big-icon-svg {
|
||||
padding: 0 7px 0 0;
|
||||
margin-right: 0.6rem;
|
||||
}
|
||||
|
||||
.big-icon-svg > .bg {
|
||||
height: 28px;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
}
|
||||
.amount-label{
|
||||
line-height: 30px;
|
||||
.amount{
|
||||
font-size: 38px;
|
||||
margin-bottom: .5rem;
|
||||
|
||||
> .unit {
|
||||
font-family: "Roboto-Light";
|
||||
}
|
||||
}
|
||||
.alternative {
|
||||
font-size: 12px;
|
||||
font-family: "Roboto-Light";
|
||||
color: #9B9B9B;
|
||||
}
|
||||
}
|
||||
}
|
||||
.item {
|
||||
border-color: $item-border-color;
|
||||
}
|
||||
.info {
|
||||
.badge {
|
||||
border-radius: 0;
|
||||
padding: .5rem;
|
||||
}
|
||||
.item {
|
||||
color: #4A4A4A;
|
||||
padding-top: $item-vertical-padding;
|
||||
padding-bottom: $item-vertical-padding;
|
||||
padding-left: $item-lateral-padding;
|
||||
|
||||
&:not(.item-icon-right) {
|
||||
padding-right: $item-lateral-padding;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 14px;
|
||||
color: $item-label-color;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.capitalized {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.wallet .big-icon-svg > .bg {
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
padding: 2px;
|
||||
box-shadow: none;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.total-amount {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
&.single-line {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-top: 17px;
|
||||
padding-bottom: 17px;
|
||||
|
||||
.label {
|
||||
margin: 0;
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
.item-divider {
|
||||
padding-top: 1.2rem;
|
||||
color: $item-label-color;
|
||||
font-size: 15px;
|
||||
}
|
||||
.wallet {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: .2rem 0;
|
||||
margin-bottom: 5px;
|
||||
|
||||
~ .bp-arrow-right {
|
||||
top: 14px;
|
||||
}
|
||||
|
||||
> i {
|
||||
padding: 0;
|
||||
position: static;
|
||||
|
||||
> img {
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
padding: 2px;
|
||||
margin-right: .7rem;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#meli-list-cards {
|
||||
img.item-logo {
|
||||
width: auto;
|
||||
height: auto;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
#meli-card {
|
||||
.card-head {
|
||||
margin: 20px 0;
|
||||
text-align: center;
|
||||
.date {
|
||||
font-size: 12px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
.amount {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
.card-status {
|
||||
text-align: center;
|
||||
margin-bottom: 25px;
|
||||
.card-status-desc {
|
||||
margin-top: 5px;
|
||||
font-size: 12px;
|
||||
color: $v-text-secondary-color;
|
||||
}
|
||||
.redeem-pin {
|
||||
font-weight: bold;
|
||||
font-size: 22px;
|
||||
}
|
||||
.button-redeem {
|
||||
margin-top: 10px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
font-size: 12px;
|
||||
color: $v-text-accent-color;
|
||||
}
|
||||
}
|
||||
.card-remove {
|
||||
text-align: center;
|
||||
margin-top: 30px;
|
||||
.button-remove {
|
||||
margin-top: 10px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
font-size: 12px;
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -17,6 +17,11 @@
|
|||
.icon-amazon {
|
||||
background-image: url("../img/icon-amazon.svg");
|
||||
}
|
||||
.icon-ml {
|
||||
background-image: url("../img/mercado-libre/icon-ml.svg");
|
||||
background-position: center;
|
||||
background-size: 85%;
|
||||
}
|
||||
.bg {
|
||||
&.wallet {
|
||||
padding: .25rem
|
||||
|
|
@ -54,6 +59,10 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
.wallet-coin-logo {
|
||||
vertical-align: middle;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.wallet-details__item.item {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
|
|
|
|||
|
|
@ -20,6 +20,12 @@
|
|||
.has-comment {
|
||||
border-bottom: 0 none;
|
||||
}
|
||||
.scan-label {
|
||||
cursor: pointer;
|
||||
cursor: hand;
|
||||
color: $link-color;
|
||||
font-weight: bold;
|
||||
}
|
||||
.comment {
|
||||
padding: 15px;
|
||||
background-color: #fff;
|
||||
|
|
@ -34,6 +40,9 @@
|
|||
width: 20px;
|
||||
}
|
||||
}
|
||||
a {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
&-explanation, &-button-group {
|
||||
padding: 0 1rem;
|
||||
|
|
@ -137,6 +146,14 @@
|
|||
.log-level {
|
||||
font-weight: bold;
|
||||
}
|
||||
.alt-currency-radio {
|
||||
.item-content {
|
||||
padding-right: 16px;
|
||||
}
|
||||
.radio-icon {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#tab-settings {
|
||||
|
|
@ -149,6 +166,13 @@
|
|||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
& > .bch {
|
||||
background-color: #9b9bab;
|
||||
border-radius: 1rem;
|
||||
}
|
||||
& > .bch-enabled {
|
||||
background-color: #ff9900 !important;
|
||||
}
|
||||
&.circle{
|
||||
left:8px;
|
||||
.bg {
|
||||
|
|
|
|||
|
|
@ -50,3 +50,4 @@
|
|||
@import "includes/pin";
|
||||
@import "includes/logOptions";
|
||||
@import "includes/checkBar";
|
||||
@import "cashScan";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,22 @@
|
|||
#wallet-backup-phrase {
|
||||
.comment {
|
||||
color: #667;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
.item {
|
||||
color: $v-dark-gray;
|
||||
padding-top: 1.3rem;
|
||||
padding-bottom: 1.3rem;
|
||||
border: none;
|
||||
}
|
||||
.heading {
|
||||
font-size: 17px;
|
||||
color: $v-dark-gray;
|
||||
margin: 1rem 0;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
border: none;
|
||||
}
|
||||
h3 {
|
||||
padding: 15px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,6 +88,27 @@
|
|||
padding: 1rem;
|
||||
background: #f8f8f9;
|
||||
}
|
||||
|
||||
&__no-transaction {
|
||||
color: $v-mid-gray;
|
||||
font-size: 12.5px;
|
||||
text-align: center;
|
||||
padding-top: 2rem;
|
||||
}
|
||||
|
||||
&__no-update-history {
|
||||
color: $v-error-color;
|
||||
font-size: 12.5px;
|
||||
text-align: center;
|
||||
padding-top: 2rem;
|
||||
}
|
||||
|
||||
&__updating-history {
|
||||
color: $v-mid-gray;
|
||||
font-size: 12.5px;
|
||||
text-align: center;
|
||||
padding-top: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
#walletDetails {
|
||||
|
|
@ -177,10 +198,6 @@
|
|||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&.collapsible {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
&__balance {
|
||||
-webkit-transform: scale3d(1, 1, 1) translateY(45px);
|
||||
transform: scale3d(1, 1, 1) translateY(45px);
|
||||
|
|
@ -198,8 +215,21 @@
|
|||
&__button-balance {
|
||||
background-color: transparent;
|
||||
border: 1px solid rgba(255,255,255,0.25);
|
||||
margin-top: 10px;
|
||||
i.icon {
|
||||
margin-right: 7px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
&__error {
|
||||
font-size: 14px;
|
||||
padding: 35px 20px;
|
||||
}
|
||||
|
||||
}
|
||||
.no-alternative {
|
||||
padding-top: 45px;
|
||||
}
|
||||
.item.item-footer {
|
||||
font-weight: lighter;
|
||||
|
|
@ -237,6 +267,17 @@
|
|||
font-size: 20px;
|
||||
color: #fff;
|
||||
width:95%;
|
||||
|
||||
.actions{
|
||||
float: right;
|
||||
a {
|
||||
color: white;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
padding: 5px;
|
||||
line-height: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.wallet-not-backed-up-warning {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue