From 941e7ba70094a1d4a20cb4db27107cc29821b740 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ho=C4=8Devar?=
Date: Mon, 12 Aug 2019 15:21:03 +0200
Subject: [PATCH 1/4] Implemented GoCrypto integration
---
src/js/controllers/review.controller.js | 140 +++++++-----
src/js/services/goCryptoService.js | 201 ++++++++++++++++++
src/js/services/incoming-data.service.js | 100 ++++-----
.../services/send-flow/send-flow.service.js | 21 +-
www/img/icon-gocrypto.svg | 27 +++
www/views/review.html | 5 +-
6 files changed, 395 insertions(+), 99 deletions(-)
create mode 100644 src/js/services/goCryptoService.js
create mode 100644 www/img/icon-gocrypto.svg
diff --git a/src/js/controllers/review.controller.js b/src/js/controllers/review.controller.js
index fb1d98b8f..41ffa1184 100644
--- a/src/js/controllers/review.controller.js
+++ b/src/js/controllers/review.controller.js
@@ -31,6 +31,7 @@ angular
, $scope
, sendFlowService
, sideshiftService
+ , goCryptoService
, soundService
, $state
, $timeout
@@ -56,6 +57,7 @@ angular
var toAddress = '';
var tx = {};
var txPayproData = null;
+ var txGoCryptoData = null;
var unitFromSat = 0;
var FEE_TOO_HIGH_LIMIT_PERCENTAGE = 15;
@@ -83,6 +85,7 @@ angular
toAddress = '';
tx = {};
txPayproData = null;
+ txGoCryptoData = null;
unitFromSat = 0;
// Public variables
@@ -180,6 +183,8 @@ angular
break;
case 'bip70':
initBip70();
+ case 'gocrypto':
+ initGoCrypto();
default:
_next();
break;
@@ -208,7 +213,76 @@ angular
}
vm.approve = function() {
-
+ if (vm.thirdParty != null && vm.thirdParty.id === 'gocrypto') {
+ goCryptoService.validateTx(vm.thirdParty.url).then(function(isValid) {
+ if (isValid) {
+ _onApprove();
+ } else {
+ popupService.showAlert(null, gettextCatalog.getString('GoCrypto payment is no longer valid. Please try again.', function onAlert() {
+ $state.go('tabs.scan').then(function () {
+ $ionicHistory.clearHistory();
+ });
+ }));
+ }
+ }, function(err) {
+ popupService.showAlert(null, gettextCatalog.getString('An error occurred while trying to validate GoCrypto payment. Please try again.', function onAlert() {
+ $state.go('tabs.scan').then(function () {
+ $ionicHistory.clearHistory();
+ });
+ }));
+ });
+ } else {
+ _onApprove();
+ }
+ };
+
+ vm.chooseFeeLevel = function(tx, wallet) {
+
+ if (wallet.coin == 'bch') return;
+ if (usingMerchantFee) return;
+
+ var scope = $rootScope.$new(true);
+ scope.network = tx.network;
+ scope.feeLevel = tx.feeLevel;
+ scope.noSave = true;
+ scope.coin = vm.originWallet.coin;
+
+ if (usingCustomFee) {
+ scope.customFeePerKB = tx.feeRate;
+ scope.feePerSatByte = tx.feeRate / 1000;
+ }
+
+ $ionicModal.fromTemplateUrl('views/modals/chooseFeeLevel.html', {
+ scope: scope,
+ backdropClickToClose: false,
+ hardwareBackButtonClose: false
+ }).then(function(modal) {
+ scope.chooseFeeLevelModal = modal;
+ scope.openModal();
+ });
+ scope.openModal = function() {
+ scope.chooseFeeLevelModal.show();
+ };
+
+ scope.hideModal = function(newFeeLevel, customFeePerKB) {
+ scope.chooseFeeLevelModal.hide();
+ $log.debug('New fee level choosen:' + newFeeLevel + ' was:' + tx.feeLevel);
+
+ usingCustomFee = newFeeLevel == 'custom' ? true : false;
+
+ if (tx.feeLevel == newFeeLevel && !usingCustomFee) return;
+
+ tx.feeLevel = newFeeLevel;
+ if (usingCustomFee) tx.feeRate = parseInt(customFeePerKB);
+
+ updateTx(tx, vm.originWallet, {
+ clearCache: true,
+ dryRun: true
+ }, function() {});
+ };
+ };
+
+ function _onApprove() {
if (!tx || !vm.originWallet) return;
if (vm.paymentExpired) {
@@ -269,53 +343,7 @@ angular
publishAndSign();
});
});
- };
-
- vm.chooseFeeLevel = function(tx, wallet) {
-
- if (wallet.coin == 'bch') return;
- if (usingMerchantFee) return;
-
- var scope = $rootScope.$new(true);
- scope.network = tx.network;
- scope.feeLevel = tx.feeLevel;
- scope.noSave = true;
- scope.coin = vm.originWallet.coin;
-
- if (usingCustomFee) {
- scope.customFeePerKB = tx.feeRate;
- scope.feePerSatByte = tx.feeRate / 1000;
- }
-
- $ionicModal.fromTemplateUrl('views/modals/chooseFeeLevel.html', {
- scope: scope,
- backdropClickToClose: false,
- hardwareBackButtonClose: false
- }).then(function(modal) {
- scope.chooseFeeLevelModal = modal;
- scope.openModal();
- });
- scope.openModal = function() {
- scope.chooseFeeLevelModal.show();
- };
-
- scope.hideModal = function(newFeeLevel, customFeePerKB) {
- scope.chooseFeeLevelModal.hide();
- $log.debug('New fee level choosen:' + newFeeLevel + ' was:' + tx.feeLevel);
-
- usingCustomFee = newFeeLevel == 'custom' ? true : false;
-
- if (tx.feeLevel == newFeeLevel && !usingCustomFee) return;
-
- tx.feeLevel = newFeeLevel;
- if (usingCustomFee) tx.feeRate = parseInt(customFeePerKB);
-
- updateTx(tx, vm.originWallet, {
- clearCache: true,
- dryRun: true
- }, function() {});
- };
- };
+ }
function createVanityTransaction() {
var configFeeLevel = config.wallet.settings.feeLevel ? config.wallet.settings.feeLevel : 'normal';
@@ -327,6 +355,7 @@ angular
fromWalletId: sendFlowData.fromWalletId,
toAddress: sendFlowData.toAddress,
paypro: txPayproData,
+ gocrypto: txGoCryptoData,
outs: sendFlowData.outs,
feeLevel: configFeeLevel,
@@ -632,6 +661,17 @@ angular
};
}
+ function initGoCrypto() {
+ vm.sendingTitle = gettextCatalog.getString('You are paying');
+ vm.memo = vm.thirdParty.memo;
+ vm.memoExpanded = !!vm.memo;
+ vm.destination.name = vm.thirdParty.name;
+
+ txGoCryptoData = {
+ expires: vm.thirdParty.expires
+ };
+ }
+
function initSideshift(cb) {
vm.sendingTitle = gettextCatalog.getString('You are shifting');
if (!vm.thirdParty.data) {
@@ -868,6 +908,10 @@ angular
if (tx.paypro)
startExpirationTimer(tx.paypro.expires);
+ if (tx.gocrypto) {
+ startExpirationTimer(tx.gocrypto.expires);
+ }
+
updateTx(tx, vm.originWallet, {
dryRun: true
}, function(err) {
diff --git a/src/js/services/goCryptoService.js b/src/js/services/goCryptoService.js
new file mode 100644
index 000000000..1ab66e026
--- /dev/null
+++ b/src/js/services/goCryptoService.js
@@ -0,0 +1,201 @@
+'use strict';
+
+(function() {
+
+ angular.module('bitcoincom.services')
+ .factory('goCryptoService', GoCryptoService);
+
+ function GoCryptoService($log, $http, $timeout, $q, gettextCatalog) {
+ var GOCRYPTO_PAYMENT_STATUSES = Object.freeze({
+ 'OPENED': 0,
+ 'IN_PAYMENT': 1,
+ 'PAID': 2,
+ 'PROCESSING': 3,
+ 'AUTO_CLOSED': 4,
+ 'FAILED': 5,
+ 'NOT_VALID': 6,
+ 'REFUND': 7
+ });
+ var GOCRYPTO_CURRENCIES = Object.freeze({
+ 'BITCOIN_CORE': 2,
+ 'BITCOIN_CASH': 7,
+ });
+ var GOCRYPTO_URL_REGEX = /^https?:\/\/gocrypto\.com\/sticker(\/)?/;
+ var GOCRYPTO_BACKWARD_COMPATIBILITY_URL_REGEX = /^https?:\/\/www\.elipay\.com\/getelipay(\/)?/;
+ var GOCRYPTO_ENDPOINT_URL = 'https://api.gocrypto.com/publicapi/payment?merchant_id=';
+ var GOCRYPTO_AUTH_HEADERS = {'Authorization': 'publicauth 6a15c40d-c3fa-41ac-a7ae-b089e95cf8fc'};
+
+ var req = {
+ method: 'GET',
+ url: null,
+ headers: GOCRYPTO_AUTH_HEADERS,
+ };
+
+ var service = {
+ // Functions
+ checkAndUpdateTx: checkAndUpdateTx,
+ validateTx: validateTx,
+ encodePaymentUrl: encodePaymentUrl,
+ decodePaymentUrl: decodePaymentUrl,
+ };
+
+ return service;
+
+ function checkAndUpdateTx(data) {
+ $log.debug('Checking if scanned data has GoCrypto payload...');
+ var defer = $q.defer();
+
+ if (typeof data !== 'string') {
+ defer.resolve(data);
+ }
+
+ var trimmedUrl = data.trim();
+ if (GOCRYPTO_URL_REGEX.test(trimmedUrl) || GOCRYPTO_BACKWARD_COMPATIBILITY_URL_REGEX.test(trimmedUrl)) {
+ req.url = GOCRYPTO_ENDPOINT_URL + data;
+
+ $http(req).then(function(response) {
+ if (response.status === 200) {
+ $log.info('Successfully received GoCrypto payment data');
+
+ var payment = response.data;
+
+ var paymentOption = null;
+ for (var i=0; i
+
+
diff --git a/www/views/review.html b/www/views/review.html
index 34f6c623e..9e57649c8 100644
--- a/www/views/review.html
+++ b/www/views/review.html
@@ -49,10 +49,11 @@ {{vm.destination.name}}[Balance Hidden]
-

+ ng-if="vm.thirdParty && (vm.thirdParty.id === 'bip70' || vm.thirdParty.id === 'gocrypto')">
+

+
{{vm.destination.name}}
Payment expires: {{vm.remainingTimeStr}}
Payment request has expired
From 17c7ccb12ef1360940b8108df74e710fd63b41d9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ho=C4=8Devar?=
Date: Fri, 30 Aug 2019 15:26:05 +0200
Subject: [PATCH 2/4] Updated GoCrypto sticker URL
---
src/js/services/goCryptoService.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/js/services/goCryptoService.js b/src/js/services/goCryptoService.js
index 1ab66e026..cb4798d89 100644
--- a/src/js/services/goCryptoService.js
+++ b/src/js/services/goCryptoService.js
@@ -20,8 +20,8 @@
'BITCOIN_CORE': 2,
'BITCOIN_CASH': 7,
});
- var GOCRYPTO_URL_REGEX = /^https?:\/\/gocrypto\.com\/sticker(\/)?/;
- var GOCRYPTO_BACKWARD_COMPATIBILITY_URL_REGEX = /^https?:\/\/www\.elipay\.com\/getelipay(\/)?/;
+ var GOCRYPTO_URL_REGEX = /^https?:\/\/(www\.)?gocrypto\.com/;
+ var GOCRYPTO_BACKWARD_COMPATIBILITY_URL_REGEX = /^https?:\/\/(www\.)?elipay\.com/;
var GOCRYPTO_ENDPOINT_URL = 'https://api.gocrypto.com/publicapi/payment?merchant_id=';
var GOCRYPTO_AUTH_HEADERS = {'Authorization': 'publicauth 6a15c40d-c3fa-41ac-a7ae-b089e95cf8fc'};
From d13ac944916b2f3fb816a824b6c0337aaadb38cb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ho=C4=8Devar?=
Date: Mon, 14 Oct 2019 09:30:53 +0200
Subject: [PATCH 3/4] Improve error messages
---
src/js/services/goCryptoService.js | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/src/js/services/goCryptoService.js b/src/js/services/goCryptoService.js
index cb4798d89..0130802ce 100644
--- a/src/js/services/goCryptoService.js
+++ b/src/js/services/goCryptoService.js
@@ -85,14 +85,14 @@
raiseError(
defer,
'Failed to get GoCrypto payment data.',
- 'An error occurred while trying to retrieve GoCrypto POS verification data. Please try again.'
+ 'GoCrypto payment order was not found. Please try again.'
);
}
}, function(error) {
raiseError(
defer,
'An error occurred while trying to get GoCrypto payment data.',
- 'An error occurred while trying to retrieve GoCrypto POS verification data. Please try again.'
+ 'GoCrypto payment order was not found. Please try again.'
);
});
} else {
@@ -128,14 +128,14 @@
raiseError(
defer,
'Failed to get GoCrypto payment data.',
- 'An error occurred while trying to retrieve GoCrypto POS verification data. Please try again.'
+ 'GoCrypto payment order was not found. Please try again.'
);
}
}, function(error) {
raiseError(
defer,
'An error occurred while trying to get GoCrypto payment data.',
- 'An error occurred while trying to retrieve GoCrypto POS verification data. Please try again.'
+ 'GoCrypto payment order was not found. Please try again.'
);
});
} else {
@@ -152,8 +152,8 @@
if (expiry_date < Date.now()) {
raiseError(
defer,
- 'GoCrypto payment expired.',
- 'An error occurred while trying to retrieve GoCrypto POS verification data. Please try again.'
+ 'GoCrypto payment order has expired.',
+ 'GoCrypto payment order has expired.'
);
}
}
@@ -162,8 +162,8 @@
if (paymentStatus !== GOCRYPTO_PAYMENT_STATUSES['IN_PAYMENT']) {
raiseError(
defer,
- 'Incorrect GoCrypto payment.',
- 'An error occurred while trying to retrieve GoCrypto POS verification data. Please try again.'
+ 'GoCrypto payment order was not found.',
+ 'GoCrypto payment order was not found.'
);
}
}
@@ -172,8 +172,8 @@
if (paymentOption == null) {
raiseError(
defer,
- 'Could not found GoCrypto payment option.',
- 'An error occurred while trying to retrieve GoCrypto POS verification data. Please try again.'
+ 'Incorrect GoCrypto payment order.',
+ 'Incorrect GoCrypto payment order.'
);
}
}
From cd8fed35f299a524c4f8ff62fc3441702481b734 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ho=C4=8Devar?=
Date: Mon, 14 Oct 2019 12:11:38 +0200
Subject: [PATCH 4/4] Improve more error messages
---
src/js/controllers/review.controller.js | 22 +++++++++++-----------
src/js/services/goCryptoService.js | 4 ++--
2 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/src/js/controllers/review.controller.js b/src/js/controllers/review.controller.js
index 41ffa1184..8cf94dcb1 100644
--- a/src/js/controllers/review.controller.js
+++ b/src/js/controllers/review.controller.js
@@ -39,7 +39,7 @@ angular
, txFormatService
, walletService
) {
-
+
var vm = this;
var sendFlowData;
@@ -61,7 +61,7 @@ angular
var unitFromSat = 0;
var FEE_TOO_HIGH_LIMIT_PERCENTAGE = 15;
-
+
// Functions
vm.goBack = goBack;
vm.onReplay = onReplay;
@@ -218,14 +218,14 @@ angular
if (isValid) {
_onApprove();
} else {
- popupService.showAlert(null, gettextCatalog.getString('GoCrypto payment is no longer valid. Please try again.', function onAlert() {
+ popupService.showAlert(null, gettextCatalog.getString('GoCrypto payment order has expired.', function onAlert() {
$state.go('tabs.scan').then(function () {
$ionicHistory.clearHistory();
});
}));
}
}, function(err) {
- popupService.showAlert(null, gettextCatalog.getString('An error occurred while trying to validate GoCrypto payment. Please try again.', function onAlert() {
+ popupService.showAlert(null, gettextCatalog.getString('GoCrypto payment order was not found. Please try again.', function onAlert() {
$state.go('tabs.scan').then(function () {
$ionicHistory.clearHistory();
});
@@ -375,8 +375,8 @@ angular
//tx.toAddress = vm.thirdParty.toAddress;
tx.toAddress = bitcoinCashJsService.readAddress(vm.thirdParty.toAddress).legacy;
}
-
- if (sendFlowData.thirdParty && sendFlowData.thirdParty.requiredFeeRate) {
+
+ if (sendFlowData.thirdParty && sendFlowData.thirdParty.requiredFeeRate) {
vm.usingMerchantFee = true;
tx.feeRate = parseInt(sendFlowData.thirdParty.requiredFeeRate);
}
@@ -558,7 +558,7 @@ angular
}
// Check if the recipient is a contact
- addressbookService.get(originCoin + address, function onGetContact(err, contact) {
+ addressbookService.get(originCoin + address, function onGetContact(err, contact) {
if (!err && contact) {
handleDestinationAsAddressOfContact(contact);
} else {
@@ -631,7 +631,7 @@ angular
if (vm.originWallet.coin !== 'bch') {
return;
}
-
+
var address = vm.destinationAddress;
if (address) {
// So the address can be parsed properly
@@ -687,11 +687,11 @@ angular
walletService.getAddress(vm.originWallet, false, function onReturnWalletAddress(err, returnAddr) {
if (err) {
return cb(err);
- }
+ }
walletService.getAddress(toWallet, false, function onWithdrawalWalletAddress(err, withdrawalAddr) {
if (err) {
return cb(err);
- }
+ }
// Need to use the correct service to do it.
var amount = parseFloat(satoshis / 100000000);
@@ -728,7 +728,7 @@ angular
ionicToast.show(gettextCatalog.getString('Copied to clipboard'), 'bottom', false, 3000);
clipboardService.copyToClipboard(explorerTxUrl);
}
-
+
}
function _onTransactionCompletedSuccessfully() {
diff --git a/src/js/services/goCryptoService.js b/src/js/services/goCryptoService.js
index 0130802ce..b996de88d 100644
--- a/src/js/services/goCryptoService.js
+++ b/src/js/services/goCryptoService.js
@@ -172,8 +172,8 @@
if (paymentOption == null) {
raiseError(
defer,
- 'Incorrect GoCrypto payment order.',
- 'Incorrect GoCrypto payment order.'
+ 'Incorrect GoCrypto payment order details.',
+ 'Incorrect GoCrypto payment order details.'
);
}
}