Merge with origin.

This commit is contained in:
Brendon Duncan 2018-09-26 16:33:01 +12:00
commit eacf207b2c
21 changed files with 499 additions and 741 deletions

View file

@ -21,28 +21,14 @@ angular.module('copayApp.controllers').controller('addressbookViewController', f
}); });
$scope.sendTo = function() { $scope.sendTo = function() {
$ionicHistory.removeBackView();
sendFlowService.clear();
$state.go('tabs.send');
$timeout(function() {
var to = '';
if ($scope.addressbookEntry.coin == 'bch') {
var a = 'bitcoincash:' + $scope.addressbookEntry.address;
to = bitcoinCashJsService.readAddress(a).legacy;
} else {
to = $scope.addressbookEntry.address;
}
var stateParams = { var stateParams = {
toAddress: to, data: $scope.addressbookEntry.address,
toName: $scope.addressbookEntry.name, toName: $scope.addressbookEntry.name,
toEmail: $scope.addressbookEntry.email, toEmail: $scope.addressbookEntry.email,
coin: $scope.addressbookEntry.coin coin: $scope.addressbookEntry.coin
}; };
sendFlowService.pushState(stateParams); sendFlowService.start(stateParams);
$state.transitionTo('tabs.send.origin');
}, 100);
}; };
$scope.remove = function(addressbookEntry) { $scope.remove = function(addressbookEntry) {

View file

@ -68,13 +68,14 @@ function amountController(configService, $filter, gettextCatalog, $ionicHistory,
function onBeforeEnter(event, data) { function onBeforeEnter(event, data) {
if (data.direction == "back") { if (data.direction == "back") {
sendFlowService.popState(); sendFlowService.state.pop();
} }
console.log('amount onBeforeEnter after back sendflow ', sendFlowService.state);
initCurrencies(); initCurrencies();
passthroughParams = sendFlowService.getStateClone(); passthroughParams = sendFlowService.state.getClone();
console.log('amount onBeforeEnter after back sendflow ', passthroughParams);
vm.fromWalletId = passthroughParams.fromWalletId; vm.fromWalletId = passthroughParams.fromWalletId;
vm.toWalletId = passthroughParams.toWalletId; vm.toWalletId = passthroughParams.toWalletId;
@ -214,7 +215,7 @@ function amountController(configService, $filter, gettextCatalog, $ionicHistory,
} }
function goBack() { function goBack() {
$ionicHistory.goBack(); sendFlowService.router.goBack();
} }
function paste(value) { function paste(value) {
@ -467,11 +468,10 @@ function amountController(configService, $filter, gettextCatalog, $ionicHistory,
confirmData.thirdParty = vm.thirdParty; confirmData.thirdParty = vm.thirdParty;
} }
sendFlowService.pushState(confirmData);
if (!confirmData.fromWalletId) { if (!confirmData.fromWalletId) {
$state.transitionTo('tabs.paymentRequest.confirm', confirmData); $state.transitionTo('tabs.paymentRequest.confirm', confirmData);
} else { } else {
$state.transitionTo('tabs.send.review', confirmData); sendFlowService.goNext(confirmData);
$scope.useSendMax = null; $scope.useSendMax = null;
} }
} }

View file

@ -80,7 +80,7 @@ function reviewController(addressbookService, bitcoinCashJsService, bitcore, bit
function onBeforeEnter(event, data) { function onBeforeEnter(event, data) {
console.log('walletSelector onBeforeEnter sendflow ', sendFlowService.state); console.log('walletSelector onBeforeEnter sendflow ', sendFlowService.state);
defaults = configService.getDefaults(); defaults = configService.getDefaults();
sendFlowData = sendFlowService.getStateClone(); sendFlowData = sendFlowService.state.getClone();
originWalletId = sendFlowData.fromWalletId; originWalletId = sendFlowData.fromWalletId;
satoshis = parseInt(sendFlowData.amount, 10); satoshis = parseInt(sendFlowData.amount, 10);
toAddress = sendFlowData.toAddress; toAddress = sendFlowData.toAddress;
@ -403,7 +403,7 @@ function reviewController(addressbookService, bitcoinCashJsService, bitcore, bit
} }
function goBack() { function goBack() {
$ionicHistory.goBack(); sendFlowService.router.goBack();
} }
function handleDestinationAsAddress(address, originCoin) { function handleDestinationAsAddress(address, originCoin) {
@ -766,8 +766,12 @@ function reviewController(addressbookService, bitcoinCashJsService, bitcore, bit
((processName === 'signingTx') && vm.originWallet.m > 1) || ((processName === 'signingTx') && vm.originWallet.m > 1) ||
(processName == 'sendingTx' && !vm.originWallet.canSign() && !vm.originWallet.isPrivKeyExternal()) (processName == 'sendingTx' && !vm.originWallet.canSign() && !vm.originWallet.isPrivKeyExternal())
) && !isOn) { ) && !isOn) {
// Show the popup
vm.sendStatus = 'success'; vm.sendStatus = 'success';
// Clear the send flow service state
sendFlowService.state.clear();
if ($state.current.name === "tabs.send.review") { // XX SP: Otherwise all open wallets on other devices play this sound if you have been in a send flow before on that device. if ($state.current.name === "tabs.send.review") { // XX SP: Otherwise all open wallets on other devices play this sound if you have been in a send flow before on that device.
soundService.play('misc/payment_sent.mp3'); soundService.play('misc/payment_sent.mp3');
} }

View file

@ -6,22 +6,6 @@ angular.module('copayApp.controllers').controller('shapeshiftController', functi
$scope.showMyAddress = showMyAddress; $scope.showMyAddress = showMyAddress;
function generateAddress(wallet, cb) {
if (!wallet) return;
walletService.getAddress(wallet, false, function(err, addr) {
if (err) {
popupService.showAlert(err);
}
return cb(addr);
});
}
function showToWallets() {
$scope.toWallets = $scope.fromWallet.coin === 'btc' ? walletsBch : walletsBtc;
$scope.onToWalletSelect($scope.toWallets[0]);
$scope.singleToWallet = $scope.toWallets.length === 1;
}
$scope.$on("$ionicView.beforeEnter", function(event, data) { $scope.$on("$ionicView.beforeEnter", function(event, data) {
walletsBtc = profileService.getWallets({coin: 'btc'}); walletsBtc = profileService.getWallets({coin: 'btc'});
walletsBch = profileService.getWallets({coin: 'bch'}); walletsBch = profileService.getWallets({coin: 'bch'});
@ -62,18 +46,7 @@ angular.module('copayApp.controllers').controller('shapeshiftController', functi
id: 'shapeshift' id: 'shapeshift'
} }
}; };
sendFlowService.start(stateParams);
// Starting new send flow, so ensure everything is reset
sendFlowService.clear();
$state.go('tabs.home').then(function() {
$ionicHistory.clearHistory();
$state.go('tabs.send').then(function() {
$timeout(function () {
sendFlowService.pushState(stateParams);
$state.transitionTo('tabs.send.origin');
}, 60);
});
});
} }
function showMyAddress() { function showMyAddress() {

View file

@ -122,8 +122,7 @@ angular.module('copayApp.controllers').controller('tabHomeController',
}; };
$scope.startFreshSend = function() { $scope.startFreshSend = function() {
sendFlowService.clear(); sendFlowService.start();
$state.go('tabs.send');
} }
$scope.openExternalLink = function() { $scope.openExternalLink = function() {

View file

@ -18,10 +18,10 @@ angular.module('copayApp.controllers').controller('tabReceiveController', functi
$scope.displayBalanceAsFiat = true; $scope.displayBalanceAsFiat = true;
$scope.requestSpecificAmount = function() { $scope.requestSpecificAmount = function() {
sendFlowService.pushState({ sendFlowService.start({
toWalletId: $scope.wallet.credentials.walletId toWalletId: $scope.wallet.credentials.walletId,
isRequestAmount: true
}); });
$state.go('tabs.paymentRequest.amount');
}; };
$scope.setAddress = function(newAddr, copyAddress) { $scope.setAddress = function(newAddr, copyAddress) {

View file

@ -1,6 +1,6 @@
'use strict'; 'use strict';
angular.module('copayApp.controllers').controller('tabScanController', function(bitcoinUriService, gettextCatalog, popupService, $scope, $log, $timeout, scannerService, incomingData, $state, $ionicHistory, $rootScope, $ionicNavBarDelegate) { angular.module('copayApp.controllers').controller('tabScanController', function(gettextCatalog, popupService, $scope, $log, $timeout, scannerService, incomingDataService, $state, $ionicHistory, $rootScope, $ionicNavBarDelegate) {
var scannerStates = { var scannerStates = {
unauthorized: 'unauthorized', unauthorized: 'unauthorized',
@ -111,28 +111,19 @@ angular.module('copayApp.controllers').controller('tabScanController', function(
// Sometimes (testing in Chrome, when reading QR Code) data is an object // Sometimes (testing in Chrome, when reading QR Code) data is an object
// that has a string data.result. // that has a string data.result.
contents = contents.result || contents; contents = contents.result || contents;
incomingDataService.redir(contents, function onError(err) {
if (err) {
var title = gettextCatalog.getString('Scan Failed');
popupService.showAlert(title, err.message, function onAlertShown() {
// Enable another scan since we won't receive incomingDataMenu.menuHidden
activate();
});
} else {
scannerService.resumePreview();
var parsed = bitcoinUriService.parse(contents);
var title = '';
var msg = '';
if (parsed.isValid) {
if (parsed.isTestnet) {
title = gettextCatalog.getString('Unsupported');
msg = gettextCatalog.getString('Testnet is not supported.');
popupService.showAlert(title, msg, function onAlertShown() {
scannerService.resumePreview();
});
} else {
incomingData.redir(contents);
} }
} else {
title = gettextCatalog.getString('Scan Failed');
msg = gettextCatalog.getString('Data not recognised.');
popupService.showAlert(title, msg, function onAlertShown() {
scannerService.resumePreview();
}); });
} }
}
$rootScope.$on('incomingDataMenu.menuHidden', function() { $rootScope.$on('incomingDataMenu.menuHidden', function() {
activate(); activate();

View file

@ -1,6 +1,6 @@
'use strict'; 'use strict';
angular.module('copayApp.controllers').controller('tabSendController', function(bitcoinUriService, $scope, $rootScope, $log, $timeout, $ionicScrollDelegate, $ionicLoading, addressbookService, profileService, lodash, $state, walletService, incomingData, popupService, platformInfo, sendFlowService, bwcError, gettextCatalog, scannerService, configService, bitcoinCashJsService, $ionicPopup, $ionicNavBarDelegate, clipboardService) { angular.module('copayApp.controllers').controller('tabSendController', function(bitcoinUriService, $scope, $log, $timeout, $ionicScrollDelegate, addressbookService, profileService, lodash, $state, walletService, platformInfo, sendFlowService, gettextCatalog, configService, $ionicPopup, $ionicNavBarDelegate, clipboardService, incomingDataService) {
var clipboardHasAddress = false; var clipboardHasAddress = false;
var clipboardHasContent = false; var clipboardHasContent = false;
var originalList; var originalList;
@ -29,7 +29,7 @@ angular.module('copayApp.controllers').controller('tabSendController', function(
$scope.$on("$ionicView.enter", function(event, data) { $scope.$on("$ionicView.enter", function(event, data) {
var stateParams = sendFlowService.getStateClone(); var stateParams = sendFlowService.state.getClone();
$scope.fromWallet = profileService.getWallet(stateParams.fromWalletId); $scope.fromWallet = profileService.getWallet(stateParams.fromWalletId);
clipboardService.readFromClipboard(function(text) { clipboardService.readFromClipboard(function(text) {
@ -62,11 +62,6 @@ angular.module('copayApp.controllers').controller('tabSendController', function(
}); });
$scope.findContact = function(search) { $scope.findContact = function(search) {
if (incomingData.redir(search)) {
return;
}
if (!search || search.length < 1) { if (!search || search.length < 1) {
$scope.list = originalList; $scope.list = originalList;
$timeout(function() { $timeout(function() {
@ -75,12 +70,16 @@ angular.module('copayApp.controllers').controller('tabSendController', function(
return; return;
} }
var params = sendFlowService.state.getClone();
params.data = search;
sendFlowService.start(params, function onError() {
var result = lodash.filter(originalList, function(item) { var result = lodash.filter(originalList, function(item) {
var val = item.name; var val = item.name;
return lodash.startsWith(val.toLowerCase(), search.toLowerCase()); return lodash.startsWith(val.toLowerCase(), search.toLowerCase());
}); });
$scope.list = result; $scope.list = result;
});
}; };
var hasWallets = function() { var hasWallets = function() {
@ -186,27 +185,18 @@ angular.module('copayApp.controllers').controller('tabSendController', function(
$log.debug('Got toAddress:' + toAddress + ' | ' + item.name); $log.debug('Got toAddress:' + toAddress + ' | ' + item.name);
var stateParams = sendFlowService.getStateClone(); var stateParams = sendFlowService.state.getClone();
stateParams.toAddress = toAddress, stateParams.toAddress = toAddress;
stateParams.coin = item.coin; stateParams.coin = item.coin;
sendFlowService.pushState(stateParams); sendFlowService.start(stateParams);
if (!stateParams.fromWalletId) { // If we have no toAddress or fromWallet
$state.transitionTo('tabs.send.origin');
} else {
$state.transitionTo('tabs.send.amount');
}
}); });
}; };
$scope.startWalletToWalletTransfer = function() { $scope.startWalletToWalletTransfer = function() {
console.log('startWalletToWalletTransfer()'); console.log('startWalletToWalletTransfer()');
var params = sendFlowService.getStateClone(); var params = sendFlowService.state.getClone();
sendFlowService.pushState(params); params.isWalletTransfer = true;
$state.transitionTo('tabs.send.wallet-to-wallet', { sendFlowService.start(params);
fromWalletId: sendFlowService.fromWalletId
});
} }
// This could probably be enhanced refactoring the routes abstract states // This could probably be enhanced refactoring the routes abstract states
@ -240,7 +230,7 @@ angular.module('copayApp.controllers').controller('tabSendController', function(
}); });
if (data.direction == "back") { if (data.direction == "back") {
sendFlowService.clear(); sendFlowService.state.clear();
} }
}); });

View file

@ -1,11 +1,13 @@
'use strict'; 'use strict';
angular.module('copayApp.controllers').controller('tabsController', function($rootScope, $log, $scope, $state, $stateParams, $timeout, platformInfo, incomingData, lodash, popupService, gettextCatalog, scannerService, sendFlowService) { angular.module('copayApp.controllers').controller('tabsController', function($rootScope, $log, $scope, $state, $stateParams, $timeout, platformInfo, incomingDataService, lodash, popupService, gettextCatalog, scannerService, sendFlowService) {
$scope.onScan = function(data) { $scope.onScan = function(data) {
if (!incomingData.redir(data)) { incomingDataService.redir(data, function onError(err) {
popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Invalid data')); if (err) {
popupService.showAlert(gettextCatalog.getString('Error'), err.message);
} }
});
}; };
$scope.setScanFn = function(scanFn) { $scope.setScanFn = function(scanFn) {
@ -16,8 +18,7 @@ angular.module('copayApp.controllers').controller('tabsController', function($ro
}; };
$scope.startFreshSend = function() { $scope.startFreshSend = function() {
sendFlowService.clear(); sendFlowService.start();
$state.go('tabs.send');
}; };
$scope.importInit = function() { $scope.importInit = function() {
@ -28,7 +29,6 @@ angular.module('copayApp.controllers').controller('tabsController', function($ro
}; };
$scope.chooseScanner = function() { $scope.chooseScanner = function() {
sendFlowService.clear();
var isWindowsPhoneApp = platformInfo.isCordova && platformInfo.isWP; var isWindowsPhoneApp = platformInfo.isCordova && platformInfo.isWP;
if (!isWindowsPhoneApp) { if (!isWindowsPhoneApp) {
@ -38,10 +38,14 @@ angular.module('copayApp.controllers').controller('tabsController', function($ro
scannerService.useOldScanner(function(err, contents) { scannerService.useOldScanner(function(err, contents) {
if (err) { if (err) {
popupService.showAlert(gettextCatalog.getString('Error'), err); popupService.showAlert(gettextCatalog.getString('Error'), err.message);
return; } else {
incomingDataService.redir(contents, function onError(err) {
if (err) {
popupService.showAlert(gettextCatalog.getString('Error'), err.message);
}
});
} }
incomingData.redir(contents);
}); });
}; };

View file

@ -26,27 +26,6 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
}; };
var setPendingTxps = function(txps) { var setPendingTxps = function(txps) {
/* Uncomment to test multiple outputs */
// var txp = {
// message: 'test multi-output',
// fee: 1000,
// createdOn: new Date() / 1000,
// outputs: [],
// wallet: $scope.wallet
// };
//
// function addOutput(n) {
// txp.outputs.push({
// amount: 600,
// toAddress: '2N8bhEwbKtMvR2jqMRcTCQqzHP6zXGToXcK',
// message: 'output #' + (Number(n) + 1)
// });
// };
// lodash.times(15, addOutput);
// txps.push(txp);
if (!txps) { if (!txps) {
$scope.txps = []; $scope.txps = [];
return; return;
@ -378,8 +357,6 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
}); });
$scope.$on("$ionicView.beforeEnter", function(event, data) { $scope.$on("$ionicView.beforeEnter", function(event, data) {
sendFlowService.clear();
configService.whenAvailable(function (config) { configService.whenAvailable(function (config) {
$scope.selectedPriceDisplay = config.wallet.settings.priceDisplay; $scope.selectedPriceDisplay = config.wallet.settings.priceDisplay;
@ -477,16 +454,10 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
} }
$scope.goToSend = function() { $scope.goToSend = function() {
sendFlowService.startSend({ sendFlowService.start({
fromWalletId: $scope.wallet.id fromWalletId: $scope.wallet.id
}); });
// Go home first so that the Home tab works properly
$state.go('tabs.home').then(function () {
$ionicHistory.clearHistory();
$state.go('tabs.send');
});
}; };
$scope.goToReceive = function() { $scope.goToReceive = function() {
$state.go('tabs.home', { $state.go('tabs.home', {

View file

@ -1,6 +1,6 @@
'use strict'; 'use strict';
angular.module('copayApp.controllers').controller('walletSelectorController', function($scope, $rootScope, $state, $log, $ionicHistory, sendFlowService, configService, gettextCatalog, profileService, txFormatService) { angular.module('copayApp.controllers').controller('walletSelectorController', function($scope, $state, sendFlowService, configService, gettextCatalog, profileService, txFormatService) {
var fromWalletId = ''; var fromWalletId = '';
var priceDisplayAsFiat = false; var priceDisplayAsFiat = false;
@ -12,32 +12,23 @@ angular.module('copayApp.controllers').controller('walletSelectorController', fu
function onBeforeEnter(event, data) { function onBeforeEnter(event, data) {
if (data.direction == "back") { if (data.direction == "back") {
sendFlowService.popState(); sendFlowService.state.pop();
} }
console.log('walletSelector onBeforeEnter after back sendflow', sendFlowService.state);
$scope.params = sendFlowService.getStateClone(); $scope.params = sendFlowService.state.getClone();
console.log('walletSelector onBeforeEnter after back sendflow', $scope.params);
var config = configService.getSync().wallet.settings; var config = configService.getSync().wallet.settings;
priceDisplayAsFiat = config.priceDisplay === 'fiat'; priceDisplayAsFiat = config.priceDisplay === 'fiat';
unitDecimals = config.unitDecimals; unitDecimals = config.unitDecimals;
unitsFromSatoshis = 1 / config.unitToSatoshi; unitsFromSatoshis = 1 / config.unitToSatoshi;
switch($state.current.name) { if ($scope.params.isWalletTransfer) {
case 'tabs.send.wallet-to-wallet':
$scope.sendFlowTitle = gettextCatalog.getString('Transfer between wallets'); $scope.sendFlowTitle = gettextCatalog.getString('Transfer between wallets');
break; } else if (!$scope.params.thirdParty) {
case 'tabs.send.destination':
if ($scope.params.fromWalletId && !$scope.params.thirdParty) {
$scope.sendFlowTitle = gettextCatalog.getString('Transfer between wallets');
}
break;
default:
if (!$scope.params.thirdParty) {
$scope.sendFlowTitle = gettextCatalog.getString('Send'); $scope.sendFlowTitle = gettextCatalog.getString('Send');
} }
// nop
}
$scope.coin = false; // Wallets to show (for destination screen or contacts) $scope.coin = false; // Wallets to show (for destination screen or contacts)
$scope.type = $scope.params['fromWalletId'] ? 'destination' : 'origin'; // origin || destination $scope.type = $scope.params['fromWalletId'] ? 'destination' : 'origin'; // origin || destination
@ -105,16 +96,6 @@ angular.module('copayApp.controllers').controller('walletSelectorController', fu
} }
} }
function getNextStep(params) {
if (!params.toWalletId && !params.toAddress) { // If we have no toAddress or fromWallet
return 'tabs.send.destination';
} else if (!params.amount) { // If we have no amount
return 'tabs.send.amount';
} else { // If we do have them
return 'tabs.send.review';
}
}
function handleThirdPartyIfShapeshift() { function handleThirdPartyIfShapeshift() {
console.log($scope.thirdParty, $scope.coin); console.log($scope.thirdParty, $scope.coin);
if ($scope.thirdParty.id === 'shapeshift' && $scope.type === 'destination') { // Shapeshift wants to know the if ($scope.thirdParty.id === 'shapeshift' && $scope.type === 'destination') { // Shapeshift wants to know the
@ -192,20 +173,17 @@ angular.module('copayApp.controllers').controller('walletSelectorController', fu
$scope.useWallet = function(wallet) { $scope.useWallet = function(wallet) {
var params = sendFlowService.getStateClone(); var params = sendFlowService.state.getClone();
if ($scope.type === 'origin') { // we're on the origin screen, set wallet to send from if ($scope.type === 'origin') { // we're on the origin screen, set wallet to send from
params.fromWalletId = wallet.id; params.fromWalletId = wallet.id;
} else { // we're on the destination screen, set wallet to send to } else { // we're on the destination screen, set wallet to send to
params.toWalletId = wallet.id; params.toWalletId = wallet.id;
} }
sendFlowService.pushState(params); sendFlowService.goNext(params);
var nextStep = getNextStep(params);
console.log('walletSelector nextStep', nextStep);
$state.transitionTo(nextStep, $scope.params);
}; };
$scope.goBack = function() { $scope.goBack = function() {
$ionicHistory.goBack(); sendFlowService.router.goBack();
} }
}); });

View file

@ -1,23 +1,28 @@
'use strict'; 'use strict';
angular.module('copayApp.directives') angular.module('copayApp.directives')
.directive('incomingDataMenu', function($timeout, $rootScope, $state, externalLinkService) { .directive('incomingDataMenu', function($timeout, $rootScope, $state, externalLinkService, sendFlowService, bitcoinCashJsService) {
return { return {
restrict: 'E', restrict: 'E',
templateUrl: 'views/includes/incomingDataMenu.html', templateUrl: 'views/includes/incomingDataMenu.html',
link: function(scope, element, attrs) { link: function(scope, element, attrs) {
$rootScope.$on('incomingDataMenu.showMenu', function(event, data) { $rootScope.$on('incomingDataMenu.showMenu', function(event, data) {
$timeout(function() { $timeout(function() {
scope.data = data.data; scope.data = data;
scope.type = data.type;
scope.showMenu = true;
scope.https = false;
if (scope.type === 'url') { if (scope.data.parsed.privateKey) {
if (scope.data.indexOf('https://') === 0) { scope.type = "privateKey";
scope.https = true; } else if (scope.data.parsed.url) {
} scope.type = "url";
} else if (scope.data.parsed.publicAddress) {
scope.type = "bitcoinAddress";
var prefix = scope.data.parsed.isTestnet ? 'bchtest:' : 'bitcoincash:';
scope.data.toAddress = (prefix + scope.data.parsed.publicAddress.cashAddr) || scope.data.parsed.publicAddress.legacy || scope.data.parsed.publicAddress.bitpay;
} else {
scope.type = "text";
} }
scope.showMenu = true;
}); });
}); });
scope.hide = function() { scope.hide = function() {
@ -28,18 +33,9 @@ angular.module('copayApp.directives')
externalLinkService.open(url); externalLinkService.open(url);
}; };
scope.sendPaymentToAddress = function(bitcoinAddress) { scope.sendPaymentToAddress = function(bitcoinAddress) {
var noPrefixInAddress = 0;
if (bitcoinAddress.toLowerCase().indexOf('bitcoin') < 0) {
noPrefixInAddress = 1;
}
scope.showMenu = false; scope.showMenu = false;
$state.go('tabs.send').then(function() { sendFlowService.start({
$timeout(function() { data: bitcoinAddress
$state.transitionTo('tabs.send.amount', {
toAddress: bitcoinAddress,
noPrefix: noPrefixInAddress
});
}, 50);
}); });
}; };
scope.addToAddressBook = function(bitcoinAddress) { scope.addToAddressBook = function(bitcoinAddress) {

View file

@ -1,6 +1,6 @@
'use strict'; 'use strict';
angular.module('copayApp.directives').directive('shapeshiftCoinTrader', function($interval, shapeshiftApiService, profileService, incomingData, ongoingProcess) { angular.module('copayApp.directives').directive('shapeshiftCoinTrader', function($interval, shapeshiftApiService, profileService, incomingDataService, ongoingProcess) {
return { return {
restrict: 'E', restrict: 'E',
transclude: true, transclude: true,
@ -111,7 +111,8 @@ angular.module('copayApp.directives').directive('shapeshiftCoinTrader', function
orderId: $scope.depositInfo.orderId orderId: $scope.depositInfo.orderId
}; };
if (incomingData.redir(sendAddress, 'shapeshift', shapeshiftData)) { // How to handle this
if (incomingDataService.redir(sendAddress, 'shapeshift', shapeshiftData)) {
ongoingProcess.set('connectingShapeshift', false); ongoingProcess.set('connectingShapeshift', false);
return; return;
} }

View file

@ -0,0 +1,79 @@
'use strict';
/**
* incomingDataService is an intermediate to redirect either to the sendFlow
* or to import/join a wallet.
*/
angular.module('copayApp.services').factory('incomingDataService', function(bitcoinUriService, $log, $state, $rootScope, scannerService, sendFlowService, gettextCatalog) {
var root = {};
root.showMenu = function(data) {
$rootScope.$broadcast('incomingDataMenu.showMenu', data);
};
root.redir = function(data, cbError) {
var parsed = bitcoinUriService.parse(data);
console.log(parsed);
$log.debug(parsed);
if (parsed.isValid) {
if (parsed.isTestnet) {
if (cbError) {
var errorMessage = gettextCatalog.getString('Testnet is not supported.');
cbError(new Error(errorMessage));
}
} else {
scannerService.pausePreview();
/**
* Strategy for the action
*/
if (parsed.copayInvitation) {
$state.go('tabs.home').then(function() {
$state.transitionTo('tabs.add.join', {
url: data
});
});
} else if (parsed.import) {
$state.go('tabs.home').then(function() {
$state.transitionTo('tabs.add.import', {
code: data
});
});
} else if (
!parsed.isValid
|| parsed.privateKey
|| (sendFlowService.state.isEmpty() && !parsed.url && !parsed.amount)
) {
root.showMenu({
original: data,
parsed: parsed
});
} else {
var state = sendFlowService.state.getClone();
state.data = data;
sendFlowService.start(state, function onError(err) {
/**
* OnError, open the menu (link not validated)
*/
root.showMenu({
original: data,
parsed: parsed
});
});
}
}
} else {
if (cbError) {
var errorMessage = gettextCatalog.getString('Data not recognised.');
cbError(new Error(errorMessage));
}
}
};
return root;
});

View file

@ -1,490 +0,0 @@
'use strict';
angular.module('copayApp.services').factory('incomingData', function(externalLinkService, bitcoinUriService, $log, $state, $timeout, $ionicHistory, bitcore, bitcoreCash, $rootScope, payproService, scannerService, sendFlowService, appConfigService, popupService, gettextCatalog, bitcoinCashJsService) {
var root = {};
root.showMenu = function(data) {
$rootScope.$broadcast('incomingDataMenu.showMenu', data);
};
root.redir = function(data, serviceId, serviceData) {
var originalAddress = null;
var noPrefixInAddress = 0;
var allParsed = bitcoinUriService.parse(data);
if (allParsed.isValid && allParsed.isTestnet) {
popupService.showAlert(
gettextCatalog.getString('Unsupported'),
gettextCatalog.getString('Testnet is not supported.')
);
return false;
}
if (data.toLowerCase().indexOf('bitcoin') < 0) {
noPrefixInAddress = 1;
}
if (typeof(data) == 'string' && !(/^bitcoin(cash)?:\?r=[\w+]/).exec(data) && (data.toLowerCase().indexOf('bitcoincash:') >= 0 || data[0] == 'q' || data[0] == 'p' || data[0] == 'C' || data[0] == 'H')) {
try {
noPrefixInAddress = 0;
if (data[0] == 'p' || data[0] == 'q') {
data = 'bitcoincash:' + data;
}
var paramString = '';
if (data.indexOf('?') >= 0) {
paramString = data.substring(data.indexOf('?'));
data = data.substring(0, data.indexOf('?'));
}
if (data.indexOf('BITCOINCASH:') >= 0) {
data = data.toLowerCase();
}
originalAddress = data.replace('bitcoincash:', '');
var legacyAddress = bitcoinCashJsService.readAddress(data).legacy;
data = 'bitcoincash:' + legacyAddress + paramString;
} catch (ex) {}
}
$log.debug('Processing incoming data: ' + data);
function sanitizeUri(data) {
// Fixes when a region uses comma to separate decimals
var regex = /[\?\&]amount=(\d+([\,\.]\d+)?)/i;
var match = regex.exec(data);
if (!match || match.length === 0) {
return data;
}
var value = match[0].replace(',', '.');
var newUri = data.replace(regex, value);
// mobile devices, uris like copay://glidera
newUri.replace('://', ':');
return newUri;
}
function getParameterByName(name, url) {
if (!url) return;
name = name.replace(/[\[\]]/g, "\\$&");
var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, " "));
}
function checkPrivateKey(privateKey) {
try {
new bitcore.PrivateKey(privateKey, 'livenet');
} catch (err) {
return false;
}
return true;
}
function goSend(addr, amount, message, coin, serviceId, serviceData) {
$state.go('tabs.send', {}, {
'reload': true,
'notify': $state.current.name == 'tabs.send' ? false : true
});
// Timeout is required to enable the "Back" button
$timeout(function() {
var params = sendFlowService.getStateClone();
if (amount) {
params.amount = amount;
}
if (addr) {
params.toAddress = addr;
params.displayAddress = originalAddress ? originalAddress : addr;
}
if (coin) {
params.coin = coin;
}
if (noPrefixInAddress) {
params.noPrefixInAddress = noPrefixInAddress;
}
if (serviceId) {
params.thirdParty = [];
params.thirdParty.id = serviceId;
params.thirdParty.data = serviceData;
sendFlowService.pushState(params);
$state.transitionTo('tabs.send.amount');
} else {
sendFlowService.pushState(params);
$state.transitionTo('tabs.send.origin');
}
}, 100);
}
// data extensions for Payment Protocol with non-backwards-compatible request
if (allParsed.isValid && allParsed.coin && allParsed.url && !allParsed.isTestnet) {
var coin = allParsed.coin;
data = allParsed.url;
if (allParsed.coin == 'bch') {
payproService.getPayProDetailsViaHttp(data, function onGetPayProDetailsViaHttp(err, details) {
if (err) {
var message = err.toString();
if (typeof err.data === 'string') {
// i.e. 'This invoice is no longer accepting payments'
message = gettextCatalog.getString(err.data);
}
popupService.showAlert(gettextCatalog.getString('Error'), message)
} else {
handlePayPro(details, allParsed.coin);
}
});
} else {
payproService.getPayProDetails(data, allParsed.coin, function onGetPayProDetails(err, details) {
if (err) {
popupService.showAlert(gettextCatalog.getString('Error'), err);
} else {
handlePayPro(details, allParsed.coin);
}
});
}
return true;
}
data = sanitizeUri(data);
var addr = '';
// Bitcoin URL
if (bitcore.URI.isValid(data)) {
var coin = 'btc';
var parsed = new bitcore.URI(data);
var addr = parsed.address ? parsed.address.toString() : '';
var message = parsed.message;
var amount = parsed.amount ? parsed.amount : '';
if (parsed.r) {
payproService.getPayProDetails(parsed.r, coin, function(err, details) {
if (err) {
if (addr && amount) goSend(addr, amount, message, coin, serviceId, serviceData);
else popupService.showAlert(gettextCatalog.getString('Error'), err);
} else handlePayPro(details, coin);
});
} else {
goSend(addr, amount, message, coin, serviceId, serviceData);
}
return true;
// Cash URI
} else if (allParsed.isValid && allParsed.coin === 'bch' && allParsed.publicAddress && !allParsed.isTestnet) {
var prefix = allParsed.isTestnet ? 'bchtest:' : 'bitcoincash:';
var addrIn = allParsed.publicAddress.legacy || allParsed.publicAddress.bitpay || prefix + allParsed.publicAddress.cashAddr;
originalAddress = allParsed.publicAddress.cashAddr || allParsed.publicAddress.legacy || allParsed.publicAddress.bitpay;
var addresses = bitcoinCashJsService.readAddress(addrIn);
if (!addresses) {
return false;
}
addr = addresses.legacy;
var message = allParsed.message;
var amount = allParsed.amount ? allParsed.amount : '';
// paypro not yet supported on cash
if (allParsed.url) {
payproService.getPayProDetails(allParsed.url, allParsed.coin, function(err, details) {
if (err) {
if (addr && amount)
goSend(addr, amount, message, allParsed.coin, serviceId, serviceData);
else
popupService.showAlert(gettextCatalog.getString('Error'), err);
}
handlePayPro(details, allParsed.coin);
});
} else {
goSend(addr, amount, message, allParsed.coin, serviceId, serviceData);
}
return true;
// Cash URI with bitcoin (btc) 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, coin, function(err, details) {
if (err) {
if (addr && amount)
goSend(addr, amount, message, coin, serviceId, serviceData);
else
popupService.showAlert(gettextCatalog.getString('Error'), err);
}
handlePayPro(details, coin);
});
} else {
goSend(addr, amount, message, coin, serviceId, serviceData);
}
}
);
return true;
// Plain URL
} else if (allParsed.bareUrl) {
if ($state.includes('tabs.scan')) {
root.showMenu({
data: allParsed.bareUrl,
type: 'url'
});
} else {
externalLinkService.open(
allParsed.bareUrl,
true,
gettextCatalog.getString('Open in web browser'),
allParsed.bareUrl
);
}
return true;
// Plain Address
} else if (bitcore.Address.isValid(data, 'livenet') || bitcore.Address.isValid(data, 'testnet')) {
if ($state.includes('tabs.scan')) {
root.showMenu({
data: data,
type: 'bitcoinAddress'
});
} 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({
disableAnimate: true
});
$state.go('tabs.home', {}, {
'reload': true,
'notify': $state.current.name == 'tabs.home' ? false : true
}).then(function() {
$ionicHistory.nextViewOptions({
disableAnimate: true
});
$state.transitionTo('tabs.buyandsell.glidera', {
code: code
});
});
return true;
} else if (data && data.indexOf(appConfigService.name + '://coinbase') === 0) {
var code = getParameterByName('code', data);
$ionicHistory.nextViewOptions({
disableAnimate: true
});
$state.go('tabs.home', {}, {
'reload': true,
'notify': $state.current.name == 'tabs.home' ? false : true
}).then(function() {
$ionicHistory.nextViewOptions({
disableAnimate: true
});
$state.transitionTo('tabs.buyandsell.coinbase', {
code: code
});
});
return true;
// BitPayCard Authentication
} else if (data && data.indexOf(appConfigService.name + '://') === 0) {
// Disable BitPay Card
if (!appConfigService._enabledExtensions.debitcard) return false;
var secret = getParameterByName('secret', data);
var email = getParameterByName('email', data);
var otp = getParameterByName('otp', data);
var reason = getParameterByName('r', data);
$state.go('tabs.home', {}, {
'reload': true,
'notify': $state.current.name == 'tabs.home' ? false : true
}).then(function() {
switch (reason) {
default:
case '0':
/* For BitPay card binding */
$state.transitionTo('tabs.bitpayCardIntro', {
secret: secret,
email: email,
otp: otp
});
break;
}
});
return true;
// Join
} else if (data && data.match(/^copay:[0-9A-HJ-NP-Za-km-z]{70,80}$/)) {
$state.go('tabs.home', {}, {
'reload': true,
'notify': $state.current.name == 'tabs.home' ? false : true
}).then(function() {
$state.transitionTo('tabs.add.join', {
url: data
});
});
return true;
// Old join
} else if (data && data.match(/^[0-9A-HJ-NP-Za-km-z]{70,80}$/)) {
$state.go('tabs.home', {}, {
'reload': true,
'notify': $state.current.name == 'tabs.home' ? false : true
}).then(function() {
$state.transitionTo('tabs.add.join', {
url: data
});
});
return true;
} else if (data && (data.substring(0, 2) == '6P' || checkPrivateKey(data))) {
root.showMenu({
data: data,
type: 'privateKey'
});
} else if (data && ((data.substring(0, 2) == '1|') || (data.substring(0, 2) == '2|') || (data.substring(0, 2) == '3|'))) {
$state.go('tabs.home').then(function() {
$state.transitionTo('tabs.add.import', {
code: data
});
});
return true;
} else {
if ($state.includes('tabs.scan')) {
root.showMenu({
data: data,
type: 'text'
});
}
}
return false;
};
function goToAmountPage(toAddress, coin) {
$state.go('tabs.send', {}, {
'reload': true,
'notify': $state.current.name == 'tabs.send' ? false : true
});
$timeout(function() {
var stateParams = {
toAddress: toAddress,
displayAddress: toAddress,
coin: coin,
noPrefix: 1
};
sendFlowService.pushState(stateParams);
$state.transitionTo('tabs.send.origin');
}, 100);
}
function handlePayPro(payProData, coin) {
console.log('payProData', payProData);
var toAddr = payProData.toAddress;
var amount = payProData.amount;
var paymentUrl = payProData.url;
var expires = payProData.expires;
var time = payProData.time;
if (coin === 'bch') {
var displayAddr = payProData.outputs[0].address;
toAddr = bitcoinCashJsService.readAddress('bitcoincash:' + displayAddr).legacy;
amount = payProData.outputs[0].amount;
paymentUrl = payProData.paymentUrl;
expires = Math.floor(new Date(expires).getTime() / 1000)
time = Math.ceil(new Date(time).getTime() / 1000)
}
var name = payProData.domain;
if (payProData.memo.indexOf('eGifter') > -1) {
name = 'eGifter'
} else if (paymentUrl.indexOf('https://bitpay.com') > -1) {
name = 'BitPay';
}
var thirdPartyData = {
id: 'bip70',
amount: amount,
caTrusted: true,
name: name,
domain: payProData.domain,
expires: expires,
memo: payProData.memo,
network: 'livenet',
requiredFeeRate: payProData.requiredFeeRate,
selfSigned: 0,
time: time,
displayAddress: displayAddr,
toAddress: toAddr,
url: paymentUrl,
verified: true
};
var stateParams = {
amount: thirdPartyData.amount,
toAddress: thirdPartyData.toAddress,
coin: coin,
thirdParty: thirdPartyData
};
// fee
if (thirdPartyData.requiredFeeRate) {
stateParams.requiredFeeRate = thirdPartyData.requiredFeeRate * 1024;
}
scannerService.pausePreview();
$state.go('tabs.send', {}, {
'reload': true,
'notify': $state.current.name == 'tabs.send' ? false : true
}).then(function() {
$timeout(function() {
sendFlowService.pushState(stateParams); // Need to do more here
$state.transitionTo('tabs.send.origin');
});
});
}
return root;
});

View file

@ -1,6 +1,6 @@
'use strict'; 'use strict';
angular.module('copayApp.services').factory('openURLService', function($rootScope, $ionicHistory, $document, $log, $state, platformInfo, lodash, profileService, incomingData, appConfigService) { angular.module('copayApp.services').factory('openURLService', function($rootScope, $ionicHistory, $document, $log, $state, platformInfo, lodash, profileService, incomingDataService, appConfigService) {
var root = {}; var root = {};
var handleOpenURL = function(args) { var handleOpenURL = function(args) {
@ -23,9 +23,12 @@ angular.module('copayApp.services').factory('openURLService', function($rootScop
document.addEventListener('handleopenurl', handleOpenURL, false); document.addEventListener('handleopenurl', handleOpenURL, false);
if (!incomingData.redir(url)) { incomingDataService.redir(url, function onError(err) {
if (err) {
$log.warn('Unknown URL! : ' + url); $log.warn('Unknown URL! : ' + url);
popupService.showAlert(gettextCatalog.getString('Error'), err.message);
} }
});
}; };
var handleResume = function() { var handleResume = function() {

View file

@ -0,0 +1,85 @@
'use strict';
(function(){
angular
.module('bitcoincom.services')
.factory('sendFlowRouterService', sendFlowRouterService);
function sendFlowRouterService(
sendFlowStateService
, $state, $ionicHistory, $timeout
) {
var service = {
// Functions
start: start,
goNext: goNext,
goBack: goBack,
};
return service;
/**
* Start new send flow
*/
function start() {
var state = sendFlowStateService.state;
if (state.isRequestAmount) {
$state.go('tabs.paymentRequest.amount');
} else {
if ($state.current.name != 'tabs.send') {
$state.go('tabs.home').then(function () {
$ionicHistory.clearHistory();
$state.go('tabs.send').then(function () {
$timeout(function () {
goNext();
}, 60);
});
});
} else {
goNext();
}
}
}
/**
* Go to the next page
* Routing strategy : https://bitcoindotcom.atlassian.net/wiki/x/BQDWKQ
*/
function goNext() {
var state = sendFlowStateService.state;
var needsDestination = !state.toWalletId && !state.toAddress;
var needsOrigin = !state.fromWalletId;
var needsAmount = !state.amount && !state.sendMax;
if (needsDestination) {
if (!state.isWalletTransfer && !state.thirdParty) {
$state.go('tabs.send');
return;
} else if (!needsOrigin) {
$state.go('tabs.send.destination');
return;
}
}
if (needsOrigin) {
$state.go('tabs.send.origin');
} else if (needsAmount) {
$state.go('tabs.send.amount');
} else {
$state.go('tabs.send.review');
}
}
/**
* Go to the previous page
*/
function goBack() {
$ionicHistory.goBack();
}
};
})();

View file

@ -3,14 +3,13 @@
(function(){ (function(){
angular angular
.module('copayApp.services') .module('bitcoincom.services')
.factory('sendFlowService', sendFlowService); .factory('sendFlowStateService', sendFlowStateService);
function sendFlowService($log) { function sendFlowStateService($log) {
var service = { var service = {
// A separate state variable so we can ensure it is cleared of everything, // Variables
// even other properties added that this service does not know about. (such as "coin")
state: { state: {
amount: '', amount: '',
displayAddress: null, displayAddress: null,
@ -18,29 +17,55 @@ angular
sendMax: false, sendMax: false,
thirdParty: null, thirdParty: null,
toAddress: '', toAddress: '',
toWalletId: '' toWalletId: '',
coin: '',
isRequestAmount: false,
isWalletTransfer: false
}, },
previousStates: [], previousStates: [],
// Functions // Functions
init: init,
clear: clear, clear: clear,
getStateClone: getStateClone, getClone: getClone,
map: map, map: map,
popState: popState, pop: pop,
pushState: pushState, push: push,
startSend: startSend isEmpty: isEmpty
}; };
return service; return service;
/**
* Init state & stack
* @param {Object} params
*/
function init(params) {
$log.debug("send-flow-state init()");
clear();
if (params) {
push(params);
}
}
/**
* Clear a state & stack
*/
function clear() { function clear() {
console.log("sendFlow clear()"); $log.debug("send-flow-state clear()");
clearCurrent(); clearCurrent();
service.previousStates = []; service.previousStates = [];
} }
/**
* Clear current state only
*/
function clearCurrent() { function clearCurrent() {
console.log("sendFlow clearCurrent()"); $log.debug("send-flow-state clearCurrent()");
service.state = { service.state = {
amount: '', amount: '',
displayAddress: null, displayAddress: null,
@ -48,14 +73,17 @@ angular
sendMax: false, sendMax: false,
thirdParty: null, thirdParty: null,
toAddress: '', toAddress: '',
toWalletId: '' toWalletId: '',
coin: '',
isRequestAmount: false,
isWalletTransfer: false
} }
} }
/** /**
* Handy for debugging * Get a clone of the current state
*/ */
function getStateClone() { function getClone() {
var currentState = {}; var currentState = {};
Object.keys(service.state).forEach(function forCurrentParam(key) { Object.keys(service.state).forEach(function forCurrentParam(key) {
if (typeof service.state[key] !== 'function' && key !== 'previousStates') { if (typeof service.state[key] !== 'function' && key !== 'previousStates') {
@ -66,22 +94,21 @@ angular
} }
/** /**
* Clears all previous state * Fill in the current state from the params
* @param {Object} params
*/ */
function startSend(params) {
console.log('startSend()');
clear();
map(params);
}
function map(params) { function map(params) {
Object.keys(params).forEach(function forNewParam(key) { Object.keys(params).forEach(function forNewParam(key) {
service.state[key] = params[key]; service.state[key] = params[key];
}); });
}; };
function popState() { /**
console.log('sendFlow pop'); * Pop state
*/
function pop() {
$log.debug('send-flow-state pop');
if (service.previousStates.length) { if (service.previousStates.length) {
var params = service.previousStates.pop(); var params = service.previousStates.pop();
clearCurrent(); clearCurrent();
@ -91,13 +118,25 @@ angular
} }
}; };
function pushState(params) { /**
console.log('sendFlow push'); * Push state
var currentParams = getStateClone(); * @param {Object} params
*/
function push(params) {
$log.debug('send-flow-state push');
var currentParams = getClone();
service.previousStates.push(currentParams); service.previousStates.push(currentParams);
clearCurrent(); clearCurrent();
map(params); map(params);
}; };
/**
* Is empty stack
*/
function isEmpty() {
return service.previousStates.length == 0;
};
}; };
})(); })();

View file

@ -0,0 +1,149 @@
'use strict';
(function(){
angular
.module('bitcoincom.services')
.factory('sendFlowService', sendFlowService);
function sendFlowService(
sendFlowStateService, sendFlowRouterService
, bitcoinUriService, payproService, bitcoinCashJsService
, popupService, gettextCatalog
, $state, $log
) {
var service = {
// Variables
state: sendFlowStateService,
router: sendFlowRouterService,
// Functions
start: start,
goNext: goNext,
goBack: goBack
};
return service;
/**
* Start a new send flow
* @param {Object} params
* @param {Function} onError
*/
function start(params, onError) {
$log.debug('send-flow start()');
if (params && params.data) {
var res = bitcoinUriService.parse(params.data);
if (res.isValid) {
// If BIP70 (url)
if (res.url) {
var url = res.url;
var coin = res.coin || '';
payproService.getPayProDetails(url, coin, function onGetPayProDetails(err, payProData) {
if (err) {
popupService.showAlert(gettextCatalog.getString('Error'), err);
} else {
var name = payProData.domain;
// Detect some merchant that we know
if (payProData.memo.indexOf('eGifter') > -1) {
name = 'eGifter'
} else if (paymentUrl.indexOf('https://bitpay.com') > -1) {
name = 'BitPay';
}
// Init thirdParty
var thirdPartyData = {
id: 'bip70',
caTrusted: true,
name: name,
domain: payProData.domain,
expires: payProData.expires,
memo: payProData.memo,
network: 'livenet',
requiredFeeRate: payProData.requiredFeeRate,
selfSigned: 0,
time: payProData.time,
url: payProData.url,
verified: true
};
// Fill in params
params.amount = payProData.amount,
params.toAddress = payProData.toAddress,
params.coin = coin,
params.thirdParty = thirdPartyData
}
// Resolve
_next();
});
} else {
if (res.coin) {
params.coin = res.coin;
}
if (res.amountInSatoshis) {
params.amount = res.amountInSatoshis;
}
if (res.publicAddress) {
var prefix = res.isTestnet ? 'bchtest:' : 'bitcoincash:';
params.displayAddress = res.publicAddress.cashAddr || res.publicAddress.legacy || res.publicAddress.bitpay;
var formatAddress = res.publicAddress.cashAddr ? prefix + params.displayAddress : params.displayAddress;
params.toAddress = bitcoinCashJsService.readAddress(formatAddress).legacy;
}
_next();
}
} else {
if (onError) {
onError();
}
}
} else {
_next();
}
// Next used for sync the async task
function _next() {
sendFlowStateService.init(params);
// Routing strategy to -> send-flow-router.service
sendFlowRouterService.start();
}
}
/**
* Go to the next step
* @param {Object} state
*/
function goNext(state) {
$log.debug('send-flow goNext()');
// Save the current route before leaving
state.route = $state.current.name;
// Save the state and redirect the user
sendFlowStateService.push(state);
sendFlowRouterService.goNext();
}
/**
* Go to the previous step
*/
function goBack() {
$log.debug('send-flow goBack()');
// Remove the state on top and redirect the user
sendFlowStateService.pop();
sendFlowRouterService.goBack();
}
};
})();

View file

@ -1,6 +1,6 @@
'use strict'; 'use strict';
angular.module('copayApp.services').factory('shapeshiftService', function ($http, $interval, $log, lodash, moment, ongoingProcess, shapeshiftApiService, storageService, configService, incomingData, platformInfo, servicesService) { angular.module('copayApp.services').factory('shapeshiftService', function ($http, $interval, $log, lodash, moment, ongoingProcess, shapeshiftApiService, storageService, configService, incomingDataService, platformInfo, servicesService) {
var root = {}; var root = {};
root.ShiftState = 'Shift'; root.ShiftState = 'Shift';
root.coinIn = ''; root.coinIn = '';
@ -111,7 +111,7 @@ angular.module('copayApp.services').factory('shapeshiftService', function ($http
toAddress: txData.deposit toAddress: txData.deposit
}; };
// //
// if (incomingData.redir(sendAddress, 'shapeshift', shapeshiftData)) { // if (incomingDataService.redir(sendAddress, 'shapeshift', shapeshiftData)) {
ongoingProcess.set('connectingShapeshift', false); ongoingProcess.set('connectingShapeshift', false);
// return; // return;
// } // }

View file

@ -9,21 +9,21 @@
<img src="img/icon-bitcoin-small.svg"> <img src="img/icon-bitcoin-small.svg">
</div> </div>
<div class="incoming-data-menu__url__text"> <div class="incoming-data-menu__url__text">
{{data}} {{data.original}}
</div> </div>
</div> </div>
</div> </div>
<a class="incoming-data-menu__item item item-icon-right" ng-click="addToAddressBook(data)"> <a class="incoming-data-menu__item item item-icon-right" ng-click="addToAddressBook(data.toAddress)">
<img src="img/icon-contacts.svg"> <img src="img/icon-contacts.svg">
<div class="incoming-data-menu__item__text" translate>Add as a contact</div> <div class="incoming-data-menu__item__text" translate>Add as a contact</div>
<i class="icon bp-arrow-right"></i> <i class="icon bp-arrow-right"></i>
</a> </a>
<a class="incoming-data-menu__item item item-icon-right" ng-click="sendPaymentToAddress(data)"> <a class="incoming-data-menu__item item item-icon-right" ng-click="sendPaymentToAddress(data.toAddress)">
<img src="img/icon-send-alt.svg"> <img src="img/icon-send-alt.svg">
<div class="incoming-data-menu__item__text" translate>Send payment to this address</div> <div class="incoming-data-menu__item__text" translate>Send payment to this address</div>
<i class="icon bp-arrow-right"></i> <i class="icon bp-arrow-right"></i>
</a> </a>
<a class="incoming-data-menu__item item item-icon-right" copy-to-clipboard="data"> <a class="incoming-data-menu__item item item-icon-right" copy-to-clipboard="data.original">
<img src="img/icon-paperclip.svg"> <img src="img/icon-paperclip.svg">
<div class="incoming-data-menu__item__text" translate>Copy to clipboard</div> <div class="incoming-data-menu__item__text" translate>Copy to clipboard</div>
<i class="icon bp-arrow-right"></i> <i class="icon bp-arrow-right"></i>
@ -38,11 +38,11 @@
<div class="incoming-data-menu__header" translate>Text</div> <div class="incoming-data-menu__header" translate>Text</div>
<div class="incoming-data-menu__url"> <div class="incoming-data-menu__url">
<div class="incoming-data-menu__url__text" style="border: 0;"> <div class="incoming-data-menu__url__text" style="border: 0;">
{{data}} {{data.original}}
</div> </div>
</div> </div>
</div> </div>
<a class="incoming-data-menu__item item item-icon-right" copy-to-clipboard="data"> <a class="incoming-data-menu__item item item-icon-right" copy-to-clipboard="data.original">
<img src="img/icon-paperclip.svg"> <img src="img/icon-paperclip.svg">
<div class="incoming-data-menu__item__text" translate>Copy to clipboard</div> <div class="incoming-data-menu__item__text" translate>Copy to clipboard</div>
<i class="icon bp-arrow-right"></i> <i class="icon bp-arrow-right"></i>
@ -57,16 +57,16 @@
<div class="incoming-data-menu__header" translate>Private Key</div> <div class="incoming-data-menu__header" translate>Private Key</div>
<div class="incoming-data-menu__url"> <div class="incoming-data-menu__url">
<div class="incoming-data-menu__url__text" style="border: 0;"> <div class="incoming-data-menu__url__text" style="border: 0;">
{{data}} {{data.original}}
</div> </div>
</div> </div>
</div> </div>
<a class="incoming-data-menu__item item item-icon-right" ng-click="scanPaperWallet(data)"> <a class="incoming-data-menu__item item item-icon-right" ng-click="scanPaperWallet(data.original)">
<img src="img/icon-import.svg"> <img src="img/icon-import.svg">
<div class="incoming-data-menu__item__text" translate>Sweep paper wallet</div> <div class="incoming-data-menu__item__text" translate>Sweep paper wallet</div>
<i class="icon bp-arrow-right"></i> <i class="icon bp-arrow-right"></i>
</a> </a>
<a class="incoming-data-menu__item item item-icon-right" copy-to-clipboard="data"> <a class="incoming-data-menu__item item item-icon-right" copy-to-clipboard="data.original">
<img src="img/icon-paperclip.svg"> <img src="img/icon-paperclip.svg">
<div class="incoming-data-menu__item__text" translate>Copy to clipboard</div> <div class="incoming-data-menu__item__text" translate>Copy to clipboard</div>
<i class="icon bp-arrow-right"></i> <i class="icon bp-arrow-right"></i>
@ -81,16 +81,16 @@
<div class="incoming-data-menu__header" translate>URL</div> <div class="incoming-data-menu__header" translate>URL</div>
<div class="incoming-data-menu__url"> <div class="incoming-data-menu__url">
<div class="incoming-data-menu__url__text" style="border: 0;"> <div class="incoming-data-menu__url__text" style="border: 0;">
{{data}} {{data.original}}
</div> </div>
</div> </div>
</div> </div>
<a class="incoming-data-menu__item item item-icon-right" ng-click="goToUrl(data)"> <a class="incoming-data-menu__item item item-icon-right" ng-click="goToUrl(data.original)">
<img src="img/icon-link-external.svg"> <img src="img/icon-link-external.svg">
<div class="incoming-data-menu__item__text" translate>Open in web browser</div> <div class="incoming-data-menu__item__text" translate>Open in web browser</div>
<i class="icon bp-arrow-right"></i> <i class="icon bp-arrow-right"></i>
</a> </a>
<a class="incoming-data-menu__item item item-icon-right" copy-to-clipboard="data"> <a class="incoming-data-menu__item item item-icon-right" copy-to-clipboard="data.original">
<img src="img/icon-paperclip.svg"> <img src="img/icon-paperclip.svg">
<div class="incoming-data-menu__item__text" translate>Copy to clipboard</div> <div class="incoming-data-menu__item__text" translate>Copy to clipboard</div>
<i class="icon bp-arrow-right"></i> <i class="icon bp-arrow-right"></i>