Merge pull request #5334 from cmgustavo/feat/coinbase-integration
Re-enable Coinbase integration
This commit is contained in:
commit
6bbb1fd442
30 changed files with 1632 additions and 1241 deletions
|
|
@ -20,6 +20,9 @@ angular.module('copayApp.controllers').controller('amountController', function($
|
|||
$scope.isGlidera = data.stateParams.isGlidera;
|
||||
$scope.glideraAccessToken = data.stateParams.glideraAccessToken;
|
||||
|
||||
// Go to...
|
||||
$scope.nextStep = data.stateParams.nextStep;
|
||||
|
||||
$scope.cardId = data.stateParams.cardId;
|
||||
$scope.showMenu = $ionicHistory.backView() && $ionicHistory.backView().stateName == 'tabs.send';
|
||||
var isWallet = data.stateParams.isWallet || 'false';
|
||||
|
|
@ -27,13 +30,13 @@ angular.module('copayApp.controllers').controller('amountController', function($
|
|||
$scope.toAddress = data.stateParams.toAddress;
|
||||
$scope.toName = data.stateParams.toName;
|
||||
$scope.toEmail = data.stateParams.toEmail;
|
||||
$scope.showAlternativeAmount = !!$scope.cardId || !!$scope.isGiftCard || !!$scope.isGlidera;
|
||||
$scope.showAlternativeAmount = !!$scope.cardId || !!$scope.isGiftCard || !!$scope.isGlidera || !!$scope.nextStep;
|
||||
$scope.toColor = data.stateParams.toColor;
|
||||
$scope.showSendMax = false;
|
||||
|
||||
$scope.customAmount = data.stateParams.customAmount;
|
||||
|
||||
if (!$scope.cardId && !$scope.isGiftCard && !$scope.isGlidera && !data.stateParams.toAddress) {
|
||||
if (!$scope.cardId && !$scope.isGiftCard && !$scope.isGlidera && !$scope.nextStep && !data.stateParams.toAddress) {
|
||||
$log.error('Bad params at amount')
|
||||
throw ('bad params');
|
||||
}
|
||||
|
|
@ -72,7 +75,11 @@ angular.module('copayApp.controllers').controller('amountController', function($
|
|||
|
||||
var config = configService.getSync().wallet.settings;
|
||||
$scope.unitName = config.unitName;
|
||||
$scope.alternativeIsoCode = !!$scope.cardId || !!$scope.isGiftCard ? 'USD' : config.alternativeIsoCode;
|
||||
if (data.stateParams.currency) {
|
||||
$scope.alternativeIsoCode = data.stateParams.currency;
|
||||
} else {
|
||||
$scope.alternativeIsoCode = !!$scope.cardId || !!$scope.isGiftCard ? 'USD' : config.alternativeIsoCode;
|
||||
}
|
||||
$scope.specificAmount = $scope.specificAlternativeAmount = '';
|
||||
$scope.isCordova = platformInfo.isCordova;
|
||||
unitToSatoshi = config.unitToSatoshi;
|
||||
|
|
@ -350,6 +357,11 @@ angular.module('copayApp.controllers').controller('amountController', function($
|
|||
isGlidera: $scope.isGlidera,
|
||||
glideraAccessToken: $scope.glideraAccessToken
|
||||
});
|
||||
} else if ($scope.nextStep) {
|
||||
$state.transitionTo($scope.nextStep, {
|
||||
amount: _amount,
|
||||
currency: $scope.showAlternativeAmount ? $scope.alternativeIsoCode : ''
|
||||
});
|
||||
} else {
|
||||
var amount = $scope.showAlternativeAmount ? fromFiat(_amount) : _amount;
|
||||
if ($scope.customAmount) {
|
||||
|
|
|
|||
|
|
@ -1,175 +1,210 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('buyCoinbaseController',
|
||||
function($scope, $log, $ionicModal, $timeout, lodash, profileService, coinbaseService, addressService, ongoingProcess) {
|
||||
var self = this;
|
||||
angular.module('copayApp.controllers').controller('buyCoinbaseController', function($scope, $log, $state, $timeout, $ionicHistory, $ionicScrollDelegate, lodash, coinbaseService, popupService, profileService, ongoingProcess, walletService) {
|
||||
|
||||
this.init = function(testnet) {
|
||||
self.allWallets = profileService.getWallets(testnet ? 'testnet' : 'livenet');
|
||||
var amount;
|
||||
var currency;
|
||||
|
||||
var client = profileService.focusedClient;
|
||||
if (client) {
|
||||
$timeout(function() {
|
||||
self.selectedWalletId = client.credentials.walletId;
|
||||
self.selectedWalletName = client.credentials.walletName;
|
||||
$scope.$apply();
|
||||
}, 100);
|
||||
var showErrorAndBack = function(err) {
|
||||
$scope.sendStatus = '';
|
||||
$log.error(err);
|
||||
err = err.errors ? err.errors[0].message : err;
|
||||
popupService.showAlert('Error', err, function() {
|
||||
$ionicHistory.goBack();
|
||||
});
|
||||
};
|
||||
|
||||
var showError = function(err) {
|
||||
$scope.sendStatus = '';
|
||||
$log.error(err);
|
||||
err = err.errors ? err.errors[0].message : err;
|
||||
popupService.showAlert('Error', err);
|
||||
};
|
||||
|
||||
var statusChangeHandler = function (processName, showName, isOn) {
|
||||
$log.debug('statusChangeHandler: ', processName, showName, isOn);
|
||||
if ( processName == 'buyingBitcoin' && !isOn) {
|
||||
$scope.sendStatus = 'success';
|
||||
$timeout(function() {
|
||||
$scope.$digest();
|
||||
}, 100);
|
||||
} else if (showName) {
|
||||
$scope.sendStatus = showName;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
coinbaseService.setCredentials();
|
||||
|
||||
$scope.isFiat = data.stateParams.currency ? true : false;
|
||||
[amount, currency, $scope.amountUnitStr] = coinbaseService.parseAmount(
|
||||
data.stateParams.amount,
|
||||
data.stateParams.currency);
|
||||
|
||||
$scope.network = coinbaseService.getNetwork();
|
||||
$scope.wallets = profileService.getWallets({
|
||||
onlyComplete: true,
|
||||
network: $scope.network
|
||||
});
|
||||
$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;
|
||||
|
||||
this.getPaymentMethods = function(token) {
|
||||
coinbaseService.getPaymentMethods(token, function(err, p) {
|
||||
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) {
|
||||
self.error = err;
|
||||
ongoingProcess.set('connectingCoinbase', false);
|
||||
showErrorAndBack(err);
|
||||
return;
|
||||
}
|
||||
self.paymentMethods = [];
|
||||
lodash.each(p.data, function(pm) {
|
||||
|
||||
var hasPrimary;
|
||||
var pm;
|
||||
for(var i = 0; i < p.data.length; i++) {
|
||||
pm = p.data[i];
|
||||
if (pm.allow_buy) {
|
||||
self.paymentMethods.push(pm);
|
||||
$scope.paymentMethods.push(pm);
|
||||
}
|
||||
if (pm.allow_buy && pm.primary_buy) {
|
||||
$scope.selectedPaymentMethod = pm;
|
||||
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();
|
||||
});
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
this.getPrice = function(token) {
|
||||
var currency = 'USD';
|
||||
coinbaseService.buyPrice(token, currency, function(err, b) {
|
||||
if (err) return;
|
||||
self.buyPrice = b.data || null;
|
||||
});
|
||||
};
|
||||
|
||||
$scope.openWalletsModal = function(wallets) {
|
||||
self.error = null;
|
||||
|
||||
$scope.type = 'BUY';
|
||||
$scope.wallets = wallets;
|
||||
$scope.noColor = true;
|
||||
$scope.self = self;
|
||||
|
||||
$ionicModal.fromTemplateUrl('views/modals/wallets.html', {
|
||||
scope: $scope,
|
||||
animation: 'slide-in-up'
|
||||
}).then(function(modal) {
|
||||
$scope.walletsModal = modal;
|
||||
$scope.walletsModal.show();
|
||||
});
|
||||
|
||||
$scope.$on('walletSelected', function(ev, walletId) {
|
||||
$timeout(function() {
|
||||
var client = profileService.getClient(walletId);
|
||||
self.selectedWalletId = walletId;
|
||||
self.selectedWalletName = client.credentials.walletName;
|
||||
$scope.$apply();
|
||||
}, 100);
|
||||
$scope.walletsModal.hide();
|
||||
});
|
||||
};
|
||||
|
||||
this.buyRequest = function(token, account) {
|
||||
self.error = null;
|
||||
var accountId = account.id;
|
||||
var amount = $scope.amount ? $scope.amount : $scope.fiat;
|
||||
var currency = $scope.amount ? 'BTC' : 'USD';
|
||||
if (!amount) return;
|
||||
$scope.buyRequest = function() {
|
||||
ongoingProcess.set('connectingCoinbase', true);
|
||||
coinbaseService.init(function(err, res) {
|
||||
if (err) {
|
||||
ongoingProcess.set('connectingCoinbase', false);
|
||||
showErrorAndBack(err);
|
||||
return;
|
||||
}
|
||||
var accessToken = res.accessToken;
|
||||
var accountId = res.accountId;
|
||||
var dataSrc = {
|
||||
amount: amount,
|
||||
currency: currency,
|
||||
payment_method: $scope.selectedPaymentMethod.id || null
|
||||
payment_method: $scope.selectedPaymentMethodId.value,
|
||||
quote: true
|
||||
};
|
||||
ongoingProcess.set('Sending request...', true);
|
||||
coinbaseService.buyRequest(token, accountId, dataSrc, function(err, data) {
|
||||
ongoingProcess.set('Sending request...', false);
|
||||
coinbaseService.buyRequest(accessToken, accountId, dataSrc, function(err, data) {
|
||||
ongoingProcess.set('connectingCoinbase', false);
|
||||
if (err) {
|
||||
self.error = err;
|
||||
showErrorAndBack(err);
|
||||
return;
|
||||
}
|
||||
self.buyInfo = data.data;
|
||||
$scope.buyRequestInfo = data.data;
|
||||
$timeout(function() {
|
||||
$scope.$apply();
|
||||
}, 100);
|
||||
});
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
this.confirmBuy = function(token, account, buy) {
|
||||
self.error = null;
|
||||
var accountId = account.id;
|
||||
var buyId = buy.id;
|
||||
ongoingProcess.set('Buying Bitcoin...', true);
|
||||
coinbaseService.buyCommit(token, accountId, buyId, function(err, b) {
|
||||
ongoingProcess.set('Buying Bitcoin...', false);
|
||||
$scope.buyConfirm = function() {
|
||||
var message = 'Buy bitcoin for ' + amount + ' ' + currency;
|
||||
var okText = 'Confirm';
|
||||
var cancelText = 'Cancel';
|
||||
popupService.showConfirm(null, message, okText, cancelText, function(ok) {
|
||||
if (!ok) return;
|
||||
|
||||
ongoingProcess.set('buyingBitcoin', true, statusChangeHandler);
|
||||
coinbaseService.init(function(err, res) {
|
||||
if (err) {
|
||||
self.error = err;
|
||||
ongoingProcess.set('buyingBitcoin', false, statusChangeHandler);
|
||||
showError(err);
|
||||
return;
|
||||
} else {
|
||||
var tx = b.data.transaction;
|
||||
if (!tx) return;
|
||||
}
|
||||
var accessToken = res.accessToken;
|
||||
var accountId = res.accountId;
|
||||
var dataSrc = {
|
||||
amount: amount,
|
||||
currency: currency,
|
||||
payment_method: $scope.selectedPaymentMethodId.value,
|
||||
commit: true
|
||||
};
|
||||
coinbaseService.buyRequest(accessToken, accountId, dataSrc, function(err, b) {
|
||||
if (err) {
|
||||
ongoingProcess.set('buyingBitcoin', false, statusChangeHandler);
|
||||
showError(err);
|
||||
return;
|
||||
}
|
||||
var tx = b.data ? b.data.transaction : null;
|
||||
if (!tx) {
|
||||
ongoingProcess.set('buyingBitcoin', false, statusChangeHandler);
|
||||
showError('Transaction not found');
|
||||
return;
|
||||
}
|
||||
|
||||
ongoingProcess.set('Fetching transaction...', true);
|
||||
coinbaseService.getTransaction(token, accountId, tx.id, function(err, updatedTx) {
|
||||
ongoingProcess.set('Fetching transaction...', false);
|
||||
if (err) $log.debug(err);
|
||||
addressService.getAddress(self.selectedWalletId, false, function(err, addr) {
|
||||
$timeout(function() {
|
||||
coinbaseService.getTransaction(accessToken, accountId, tx.id, function(err, updatedTx) {
|
||||
if (err) {
|
||||
self.error = {
|
||||
errors: [{
|
||||
message: 'Could not create address'
|
||||
}]
|
||||
};
|
||||
ongoingProcess.set('buyingBitcoin', false, statusChangeHandler);
|
||||
showError(err);
|
||||
return;
|
||||
}
|
||||
updatedTx.data['toAddr'] = addr;
|
||||
coinbaseService.savePendingTransaction(updatedTx.data, {}, function(err) {
|
||||
if (err) $log.debug(err);
|
||||
if (updatedTx.data.status == 'completed') {
|
||||
self.sendToCopay(token, account, updatedTx.data);
|
||||
} else {
|
||||
self.success = updatedTx.data;
|
||||
$timeout(function() {
|
||||
$scope.$emit('Local/CoinbaseTx');
|
||||
}, 1000);
|
||||
walletService.getAddress($scope.wallet, false, function(err, walletAddr) {
|
||||
if (err) {
|
||||
ongoingProcess.set('buyingBitcoin', false, statusChangeHandler);
|
||||
showError(err);
|
||||
return;
|
||||
}
|
||||
updatedTx.data['toAddr'] = walletAddr;
|
||||
updatedTx.data['status'] = 'pending'; // Forcing "pending" status to process later
|
||||
|
||||
$log.debug('Saving transaction to process later...');
|
||||
coinbaseService.savePendingTransaction(updatedTx.data, {}, function(err) {
|
||||
ongoingProcess.set('buyingBitcoin', false, statusChangeHandler);
|
||||
if (err) $log.debug(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}, 8000);
|
||||
});
|
||||
});
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
this.sendToCopay = function(token, account, tx) {
|
||||
self.error = null;
|
||||
var accountId = account.id;
|
||||
$scope.showWalletSelector = function() {
|
||||
$scope.walletSelectorTitle = 'Receive in';
|
||||
$scope.showWallets = true;
|
||||
};
|
||||
|
||||
ongoingProcess.set('Sending funds to Copay...', true);
|
||||
var data = {
|
||||
to: tx.toAddr,
|
||||
amount: tx.amount.amount,
|
||||
currency: tx.amount.currency,
|
||||
description: 'Copay Wallet: ' + self.selectedWalletName
|
||||
};
|
||||
coinbaseService.sendTo(token, accountId, data, function(err, res) {
|
||||
ongoingProcess.set('Sending funds to Copay...', false);
|
||||
if (err) {
|
||||
self.error = err;
|
||||
} else {
|
||||
self.receiveInfo = res.data;
|
||||
if (!res.data.id) return;
|
||||
coinbaseService.getTransaction(token, accountId, res.data.id, function(err, sendTx) {
|
||||
coinbaseService.savePendingTransaction(tx, {
|
||||
remove: true
|
||||
}, function(err) {
|
||||
coinbaseService.savePendingTransaction(sendTx.data, {}, function(err) {
|
||||
$timeout(function() {
|
||||
$scope.$emit('Local/CoinbaseTx');
|
||||
}, 1000);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
$scope.onWalletSelect = function(wallet) {
|
||||
$scope.wallet = wallet;
|
||||
};
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
});
|
||||
$scope.goBackHome = function() {
|
||||
$scope.sendStatus = '';
|
||||
$ionicHistory.nextViewOptions({
|
||||
disableAnimate: true,
|
||||
historyRoot: true
|
||||
});
|
||||
$ionicHistory.clearHistory();
|
||||
$state.go('tabs.home').then(function() {
|
||||
$state.transitionTo('tabs.buyandsell.coinbase');
|
||||
});
|
||||
};
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,78 +1,117 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('coinbaseController',
|
||||
function($rootScope, $scope, $timeout, $ionicModal, profileService, configService, storageService, coinbaseService, lodash, platformInfo, ongoingProcess) {
|
||||
angular.module('copayApp.controllers').controller('coinbaseController', function($scope, $timeout, $ionicModal, $log, coinbaseService, lodash, platformInfo, ongoingProcess, popupService, externalLinkService) {
|
||||
|
||||
var isNW = platformInfo.isNW;
|
||||
var isNW = platformInfo.isNW;
|
||||
var isCordova = platformInfo.isCordova;
|
||||
|
||||
if (platformInfo.isCordova && StatusBar.isVisible) {
|
||||
StatusBar.backgroundColorByHexString("#4B6178");
|
||||
}
|
||||
|
||||
this.openAuthenticateWindow = function() {
|
||||
var oauthUrl = this.getAuthenticateUrl();
|
||||
if (!isNW) {
|
||||
$rootScope.openExternalLink(oauthUrl, '_system');
|
||||
} else {
|
||||
var self = this;
|
||||
var gui = require('nw.gui');
|
||||
var win = gui.Window.open(oauthUrl, {
|
||||
focus: true,
|
||||
position: 'center'
|
||||
});
|
||||
win.on('loaded', function() {
|
||||
var title = win.title;
|
||||
if (title.indexOf('Coinbase') == -1) {
|
||||
$scope.code = title;
|
||||
self.submitOauthCode(title);
|
||||
win.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.getAuthenticateUrl = function() {
|
||||
return coinbaseService.getOauthCodeUrl();
|
||||
};
|
||||
|
||||
this.submitOauthCode = function(code) {
|
||||
var self = this;
|
||||
var coinbaseTestnet = configService.getSync().coinbase.testnet;
|
||||
var network = coinbaseTestnet ? 'testnet' : 'livenet';
|
||||
ongoingProcess.set('connectingCoinbase', true);
|
||||
this.error = null;
|
||||
$timeout(function() {
|
||||
coinbaseService.getToken(code, function(err, data) {
|
||||
ongoingProcess.set('connectingCoinbase', false);
|
||||
var init = function() {
|
||||
$scope.currency = coinbaseService.getAvailableCurrency();
|
||||
coinbaseService.getStoredToken(function(at) {
|
||||
$scope.accessToken = at;
|
||||
|
||||
// Update Access Token if necessary
|
||||
$scope.loading = true;
|
||||
coinbaseService.init(function(err, data) {
|
||||
$scope.loading = false;
|
||||
if (err || lodash.isEmpty(data)) {
|
||||
if (err) {
|
||||
self.error = err;
|
||||
$timeout(function() {
|
||||
$scope.$apply();
|
||||
}, 100);
|
||||
} else if (data && data.access_token && data.refresh_token) {
|
||||
storageService.setCoinbaseToken(network, data.access_token, function() {
|
||||
storageService.setCoinbaseRefreshToken(network, data.refresh_token, function() {
|
||||
$scope.$emit('Local/CoinbaseUpdated', data.access_token);
|
||||
$timeout(function() {
|
||||
$scope.$apply();
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
popupService.showAlert('Error', err);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Show rates
|
||||
coinbaseService.buyPrice(data.accessToken, $scope.currency, function(err, b) {
|
||||
$scope.buyPrice = b.data || null;
|
||||
});
|
||||
coinbaseService.sellPrice(data.accessToken, $scope.currency, function(err, s) {
|
||||
$scope.sellPrice = s.data || null;
|
||||
});
|
||||
}, 100);
|
||||
};
|
||||
|
||||
this.openTxModal = function(tx) {
|
||||
$scope.tx = tx;
|
||||
|
||||
$ionicModal.fromTemplateUrl('views/modals/coinbase-tx-details.html', {
|
||||
scope: $scope,
|
||||
animation: 'slide-in-up'
|
||||
}).then(function(modal) {
|
||||
$scope.coinbaseTxDetailsModal = modal;
|
||||
$scope.coinbaseTxDetailsModal.show();
|
||||
// Updating accessToken and accountId
|
||||
$timeout(function() {
|
||||
$scope.accessToken = data.accessToken;
|
||||
$scope.accountId = data.accountId;
|
||||
$scope.updateTransactions();
|
||||
$scope.$apply();
|
||||
}, 100);
|
||||
});
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
$scope.updateTransactions = function() {
|
||||
$log.debug('Getting transactions...');
|
||||
$scope.pendingTransactions = { data: {} };
|
||||
coinbaseService.getPendingTransactions($scope.pendingTransactions);
|
||||
};
|
||||
|
||||
this.openAuthenticateWindow = function() {
|
||||
var oauthUrl = this.getAuthenticateUrl();
|
||||
if (!isNW) {
|
||||
externalLinkService.open(oauthUrl);
|
||||
} else {
|
||||
var self = this;
|
||||
var gui = require('nw.gui');
|
||||
gui.Window.open(oauthUrl, {
|
||||
focus: true,
|
||||
position: 'center'
|
||||
}, function(new_win) {
|
||||
new_win.on('loaded', function() {
|
||||
var title = new_win.window.document.title;
|
||||
$timeout(function() {
|
||||
if (title.indexOf('Coinbase') == -1) {
|
||||
$scope.code = title;
|
||||
self.submitOauthCode($scope.code);
|
||||
new_win.close();
|
||||
}
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.getAuthenticateUrl = function() {
|
||||
$scope.showOauthForm = isCordova || isNW ? false : true;
|
||||
return coinbaseService.getOauthCodeUrl();
|
||||
};
|
||||
|
||||
this.submitOauthCode = function(code) {
|
||||
var self = this;
|
||||
ongoingProcess.set('connectingCoinbase', true);
|
||||
$scope.error = null;
|
||||
$timeout(function() {
|
||||
coinbaseService.getToken(code, function(err, accessToken) {
|
||||
ongoingProcess.set('connectingCoinbase', false);
|
||||
if (err) {
|
||||
popupService.showAlert('Error', err);
|
||||
return;
|
||||
}
|
||||
$scope.accessToken = accessToken;
|
||||
init();
|
||||
});
|
||||
}, 100);
|
||||
};
|
||||
|
||||
this.openTxModal = function(tx) {
|
||||
$scope.tx = tx;
|
||||
|
||||
$ionicModal.fromTemplateUrl('views/modals/coinbase-tx-details.html', {
|
||||
scope: $scope,
|
||||
animation: 'slide-in-up'
|
||||
}).then(function(modal) {
|
||||
$scope.modal = modal;
|
||||
$scope.modal.show();
|
||||
});
|
||||
};
|
||||
|
||||
var self = this;
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
coinbaseService.setCredentials();
|
||||
if (data.stateParams && data.stateParams.code) {
|
||||
self.submitOauthCode(data.stateParams.code);
|
||||
} else {
|
||||
init();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,44 +0,0 @@
|
|||
'use strict';
|
||||
angular.module('copayApp.controllers').controller('coinbaseUriController',
|
||||
function($scope, $stateParams, $timeout, profileService, configService, coinbaseService, storageService, $state, ongoingProcess) {
|
||||
|
||||
this.submitOauthCode = function(code) {
|
||||
var self = this;
|
||||
var coinbaseTestnet = configService.getSync().coinbase.testnet;
|
||||
var network = coinbaseTestnet ? 'testnet' : 'livenet';
|
||||
ongoingProcess.set('connectingCoinbase', true);
|
||||
this.error = null;
|
||||
$timeout(function() {
|
||||
coinbaseService.getToken(code, function(err, data) {
|
||||
ongoingProcess.set('connectingCoinbase', false);
|
||||
if (err) {
|
||||
self.error = err;
|
||||
$timeout(function() {
|
||||
$scope.$apply();
|
||||
}, 100);
|
||||
} else if (data && data.access_token && data.refresh_token) {
|
||||
storageService.setCoinbaseToken(network, data.access_token, function() {
|
||||
storageService.setCoinbaseRefreshToken(network, data.refresh_token, function() {
|
||||
$scope.$emit('Local/CoinbaseUpdated', data.access_token);
|
||||
$timeout(function() {
|
||||
$state.go('coinbase');
|
||||
$scope.$apply();
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}, 100);
|
||||
};
|
||||
|
||||
this.checkCode = function() {
|
||||
if ($stateParams.url) {
|
||||
var match = $stateParams.url.match(/code=(.+)&/);
|
||||
if (match && match[1]) {
|
||||
this.code = match[1];
|
||||
return this.submitOauthCode(this.code);
|
||||
}
|
||||
}
|
||||
$log.error('Bad state: ' + JSON.stringify($stateParams));
|
||||
}
|
||||
});
|
||||
|
|
@ -528,7 +528,7 @@ angular.module('copayApp.controllers').controller('confirmController', function(
|
|||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ongoingProcess.set('creatingTx', true, onSendStatusChange);
|
||||
createTx(wallet, false, function(err, txp) {
|
||||
ongoingProcess.set('creatingTx', false, onSendStatusChange);
|
||||
|
|
@ -577,12 +577,14 @@ angular.module('copayApp.controllers').controller('confirmController', function(
|
|||
$log.debug('statusChangeHandler: ', processName, showName, isOn);
|
||||
if (
|
||||
(
|
||||
processName === 'broadcastingTx' ||
|
||||
((processName === 'signingTx') && $scope.wallet.m > 1) ||
|
||||
processName === 'broadcastingTx' ||
|
||||
((processName === 'signingTx') && $scope.wallet.m > 1) ||
|
||||
(processName == 'sendingTx' && !$scope.wallet.canSign() && !$scope.wallet.isPrivKeyExternal())
|
||||
) && !isOn) {
|
||||
$scope.sendStatus = 'success';
|
||||
$scope.$digest();
|
||||
$timeout(function() {
|
||||
$scope.$digest();
|
||||
}, 100);
|
||||
} else if (showName) {
|
||||
$scope.sendStatus = showName;
|
||||
}
|
||||
|
|
@ -831,7 +833,7 @@ angular.module('copayApp.controllers').controller('confirmController', function(
|
|||
debounceCreate(count, dataSrc, onSendStatusChange);
|
||||
}
|
||||
}, onSendStatusChange);
|
||||
}
|
||||
};
|
||||
|
||||
var debounceCreate = lodash.throttle(function(count, dataSrc) {
|
||||
debounceCreateGiftCard(count, dataSrc);
|
||||
|
|
|
|||
|
|
@ -1,20 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('coinbaseConfirmationController', function($scope, $timeout, coinbaseService, applicationService) {
|
||||
|
||||
$scope.ok = function() {
|
||||
|
||||
coinbaseService.logout($scope.network, function() {
|
||||
|
||||
$timeout(function() {
|
||||
applicationService.restart();
|
||||
}, 1000);
|
||||
});
|
||||
$scope.cancel();
|
||||
};
|
||||
|
||||
$scope.cancel = function() {
|
||||
$scope.coinbaseConfirmationModal.hide();
|
||||
};
|
||||
|
||||
});
|
||||
|
|
@ -1,18 +1,28 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('coinbaseTxDetailsController', function($scope, $rootScope, coinbaseService) {
|
||||
angular.module('copayApp.controllers').controller('coinbaseTxDetailsController', function($scope, coinbaseService, popupService) {
|
||||
|
||||
$scope.remove = function() {
|
||||
coinbaseService.savePendingTransaction($scope.tx, {
|
||||
remove: true
|
||||
}, function(err) {
|
||||
$rootScope.$emit('Local/CoinbaseTx');
|
||||
$scope.cancel();
|
||||
coinbaseService.setCredentials();
|
||||
$scope.updateRequired = false;
|
||||
var message = 'Are you sure you want to remove this transaction?';
|
||||
popupService.showConfirm(null, message, null, null, function(ok) {
|
||||
if (!ok) {
|
||||
return;
|
||||
}
|
||||
coinbaseService.savePendingTransaction($scope.tx, {
|
||||
remove: true
|
||||
}, function(err) {
|
||||
$scope.updateRequired = true;
|
||||
$scope.close();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.cancel = function() {
|
||||
$scope.coinbaseTxDetailsModal.hide();
|
||||
$scope.close = function() {
|
||||
$scope.modal.hide().then(function() {
|
||||
if ($scope.updateRequired) $scope.updateTransactions();
|
||||
});
|
||||
};
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,18 +1,41 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('preferencesCoinbaseController',
|
||||
function($scope, $timeout, $ionicModal, applicationService, coinbaseService) {
|
||||
angular.module('copayApp.controllers').controller('preferencesCoinbaseController', function($scope, $timeout, $state, $ionicHistory, lodash, ongoingProcess, popupService, coinbaseService) {
|
||||
|
||||
this.revokeToken = function(testnet) {
|
||||
$scope.network = testnet ? 'testnet' : 'livenet';
|
||||
$scope.revokeToken = function() {
|
||||
popupService.showConfirm('Coinbase', 'Are you sure you would like to log out of your Coinbase account?', null, null, function(res) {
|
||||
if (res) {
|
||||
coinbaseService.logout(function() {
|
||||
$ionicHistory.clearHistory();
|
||||
$timeout(function() {
|
||||
$state.go('tabs.home');
|
||||
}, 100);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$ionicModal.fromTemplateUrl('views/modals/coinbase-confirmation.html', {
|
||||
scope: $scope,
|
||||
animation: 'slide-in-up'
|
||||
}).then(function(modal) {
|
||||
$scope.coinbaseConfirmationModal = modal;
|
||||
$scope.coinbaseConfirmationModal.show();
|
||||
$scope.$on("$ionicView.enter", function(event, data){
|
||||
coinbaseService.setCredentials();
|
||||
ongoingProcess.set('connectingCoinbase', true);
|
||||
coinbaseService.init(function(err, data) {
|
||||
if (err || lodash.isEmpty(data)) {
|
||||
ongoingProcess.set('connectingCoinbase', false);
|
||||
if (err) {
|
||||
popupService.showAlert(gettextCatalog.getString('Error'), err);
|
||||
}
|
||||
return;
|
||||
}
|
||||
var accessToken = data.accessToken;
|
||||
var accountId = data.accountId;
|
||||
coinbaseService.getAccount(accessToken, accountId, function(err, account) {
|
||||
ongoingProcess.set('connectingCoinbase', false);
|
||||
$scope.coinbaseAccount = account.data;
|
||||
});
|
||||
};
|
||||
|
||||
coinbaseService.getCurrentUser(accessToken, function(err, user) {
|
||||
$scope.coinbaseUser = user.data;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,187 +1,258 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('sellCoinbaseController',
|
||||
function($rootScope, $scope, $log, $timeout, $ionicModal, lodash, profileService, coinbaseService, configService, walletService, fingerprintService, ongoingProcess, go) {
|
||||
angular.module('copayApp.controllers').controller('sellCoinbaseController', function($scope, $log, $state, $timeout, $ionicHistory, $ionicScrollDelegate, lodash, coinbaseService, popupService, profileService, ongoingProcess, walletService, appConfigService, configService) {
|
||||
|
||||
var self = this;
|
||||
var client;
|
||||
var amount;
|
||||
var currency;
|
||||
|
||||
$scope.priceSensitivity = [
|
||||
{
|
||||
value: 0.5,
|
||||
name: '0.5%'
|
||||
},
|
||||
{
|
||||
value: 1,
|
||||
name: '1%'
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
name: '2%'
|
||||
},
|
||||
{
|
||||
value: 5,
|
||||
name: '5%'
|
||||
},
|
||||
{
|
||||
value: 10,
|
||||
name: '10%'
|
||||
}
|
||||
];
|
||||
$scope.selectedPriceSensitivity = $scope.priceSensitivity[1];
|
||||
var showErrorAndBack = function(err) {
|
||||
$scope.sendStatus = '';
|
||||
$log.error(err);
|
||||
err = err.errors ? err.errors[0].message : err;
|
||||
popupService.showAlert('Error', err, function() {
|
||||
$ionicHistory.goBack();
|
||||
});
|
||||
};
|
||||
|
||||
this.init = function(testnet) {
|
||||
self.allWallets = profileService.getWallets(testnet ? 'testnet' : 'livenet', 1);
|
||||
var showError = function(err) {
|
||||
$scope.sendStatus = '';
|
||||
$log.error(err);
|
||||
err = err.errors ? err.errors[0].message : err;
|
||||
popupService.showAlert('Error', err);
|
||||
};
|
||||
|
||||
client = profileService.focusedClient;
|
||||
if (client && client.credentials.m == 1) {
|
||||
$timeout(function() {
|
||||
self.selectedWalletId = client.credentials.walletId;
|
||||
self.selectedWalletName = client.credentials.walletName;
|
||||
$scope.$apply();
|
||||
}, 100);
|
||||
}
|
||||
};
|
||||
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);
|
||||
}
|
||||
|
||||
this.getPaymentMethods = function(token) {
|
||||
coinbaseService.getPaymentMethods(token, function(err, p) {
|
||||
if (err) {
|
||||
self.error = err;
|
||||
return;
|
||||
}
|
||||
self.paymentMethods = [];
|
||||
lodash.each(p.data, function(pm) {
|
||||
if (pm.allow_sell) {
|
||||
self.paymentMethods.push(pm);
|
||||
}
|
||||
if (pm.allow_sell && pm.primary_sell) {
|
||||
$scope.selectedPaymentMethod = pm;
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
walletService.publishAndSign(wallet, txp, function(err, txp) {
|
||||
if (err) return cb(err);
|
||||
return cb(null, txp);
|
||||
}, onSendStatusChange);
|
||||
};
|
||||
|
||||
this.getPrice = function(token) {
|
||||
var currency = 'USD';
|
||||
coinbaseService.sellPrice(token, currency, function(err, s) {
|
||||
if (err) return;
|
||||
self.sellPrice = s.data || null;
|
||||
});
|
||||
};
|
||||
|
||||
$scope.openWalletsModal = function(wallets) {
|
||||
self.error = null;
|
||||
|
||||
$scope.type = 'SELL';
|
||||
$scope.wallets = wallets;
|
||||
$scope.noColor = true;
|
||||
$scope.self = self;
|
||||
|
||||
$ionicModal.fromTemplateUrl('views/modals/wallets.html', {
|
||||
scope: $scope,
|
||||
animation: 'slide-in-up'
|
||||
}).then(function(modal) {
|
||||
$scope.walletsModal = modal;
|
||||
$scope.walletsModal.show();
|
||||
});
|
||||
|
||||
$scope.$on('walletSelected', function(ev, walletId) {
|
||||
$timeout(function() {
|
||||
client = profileService.getClient(walletId);
|
||||
self.selectedWalletId = walletId;
|
||||
self.selectedWalletName = client.credentials.walletName;
|
||||
$scope.$apply();
|
||||
}, 100);
|
||||
$scope.walletsModal.hide();
|
||||
});
|
||||
};
|
||||
|
||||
this.depositFunds = function(token, account) {
|
||||
self.error = null;
|
||||
if ($scope.amount) {
|
||||
this.createTx(token, account, $scope.amount)
|
||||
} else if ($scope.fiat) {
|
||||
var btcValue = ($scope.fiat / self.sellPrice.amount).toFixed(8);
|
||||
this.createTx(token, account, btcValue);
|
||||
}
|
||||
};
|
||||
|
||||
this.sellRequest = function(token, account, ctx) {
|
||||
self.error = null;
|
||||
if (!ctx.amount) return;
|
||||
var accountId = account.id;
|
||||
var data = ctx.amount;
|
||||
data['payment_method'] = $scope.selectedPaymentMethod.id || null;
|
||||
ongoingProcess.set('Sending request...', true);
|
||||
coinbaseService.sellRequest(token, accountId, data, function(err, sell) {
|
||||
ongoingProcess.set('Sending request...', false);
|
||||
if (err) {
|
||||
self.error = err;
|
||||
return;
|
||||
}
|
||||
self.sellInfo = sell.data;
|
||||
});
|
||||
};
|
||||
|
||||
this.confirmSell = function(token, account, sell) {
|
||||
self.error = null;
|
||||
var accountId = account.id;
|
||||
var sellId = sell.id;
|
||||
ongoingProcess.set('Selling Bitcoin...', true);
|
||||
coinbaseService.sellCommit(token, accountId, sellId, function(err, data) {
|
||||
ongoingProcess.set('Selling Bitcoin...', false);
|
||||
if (err) {
|
||||
self.error = err;
|
||||
return;
|
||||
}
|
||||
self.success = data.data;
|
||||
$scope.$emit('Local/CoinbaseTx');
|
||||
});
|
||||
};
|
||||
|
||||
this.createTx = function(token, account, amount) {
|
||||
self.error = null;
|
||||
|
||||
if (!client) {
|
||||
self.error = 'No wallet selected';
|
||||
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;
|
||||
|
||||
var accountId = account.id;
|
||||
var dataSrc = {
|
||||
name: 'Received from Copay: ' + self.selectedWalletName
|
||||
};
|
||||
var outputs = [];
|
||||
var config = configService.getSync();
|
||||
var configWallet = config.wallet;
|
||||
var walletSettings = configWallet.settings;
|
||||
|
||||
|
||||
ongoingProcess.set('Creating Transaction...', true);
|
||||
$timeout(function() {
|
||||
|
||||
coinbaseService.createAddress(token, accountId, dataSrc, function(err, data) {
|
||||
coinbaseService.getTransactions(accessToken, accountId, function(err, ctxs) {
|
||||
if (err) {
|
||||
ongoingProcess.set('Creating Transaction...', false);
|
||||
self.error = err;
|
||||
$log.debug(err);
|
||||
checkTransaction(count, txp);
|
||||
return;
|
||||
}
|
||||
|
||||
var address, comment;
|
||||
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
|
||||
});
|
||||
|
||||
address = data.data.address;
|
||||
amount = parseInt((amount * 100000000).toFixed(0));
|
||||
comment = 'Send funds to Coinbase Account: ' + account.name;
|
||||
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.beforeEnter", function(event, data) {
|
||||
coinbaseService.setCredentials();
|
||||
|
||||
$scope.isFiat = data.stateParams.currency ? true : false;
|
||||
[amount, currency, $scope.amountUnitStr] = coinbaseService.parseAmount(
|
||||
data.stateParams.amount,
|
||||
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
|
||||
});
|
||||
$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.sellPrice(accessToken, coinbaseService.getAvailableCurrency(), function(err, s) {
|
||||
$scope.sellPrice = s.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_sell) {
|
||||
$scope.paymentMethods.push(pm);
|
||||
}
|
||||
if (pm.allow_sell && pm.primary_sell) {
|
||||
hasPrimary = true;
|
||||
$scope.selectedPaymentMethodId.value = pm.id;
|
||||
}
|
||||
}
|
||||
if (lodash.isEmpty($scope.paymentMethods)) {
|
||||
ongoingProcess.set('connectingCoinbase', false);
|
||||
showErrorAndBack('No payment method available to sell');
|
||||
return;
|
||||
}
|
||||
if (!hasPrimary) $scope.selectedPaymentMethodId.value = $scope.paymentMethods[0].id;
|
||||
$scope.sellRequest();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
$scope.sellRequest = function() {
|
||||
ongoingProcess.set('connectingCoinbase', true);
|
||||
coinbaseService.init(function(err, res) {
|
||||
if (err) {
|
||||
ongoingProcess.set('connectingCoinbase', false);
|
||||
showErrorAndBack(err);
|
||||
return;
|
||||
}
|
||||
var accessToken = res.accessToken;
|
||||
var accountId = res.accountId;
|
||||
var dataSrc = {
|
||||
amount: amount,
|
||||
currency: currency,
|
||||
payment_method: $scope.selectedPaymentMethodId.value,
|
||||
quote: true
|
||||
};
|
||||
coinbaseService.sellRequest(accessToken, accountId, dataSrc, function(err, data) {
|
||||
ongoingProcess.set('connectingCoinbase', false);
|
||||
if (err) {
|
||||
showErrorAndBack(err);
|
||||
return;
|
||||
}
|
||||
$scope.sellRequestInfo = data.data;
|
||||
$timeout(function() {
|
||||
$scope.$apply();
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.sellConfirm = function() {
|
||||
var config = configService.getSync();
|
||||
var configWallet = config.wallet;
|
||||
var walletSettings = configWallet.settings;
|
||||
|
||||
var message = 'Selling bitcoin for ' + amount + ' ' + currency;
|
||||
var okText = 'Confirm';
|
||||
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) {
|
||||
ongoingProcess.set('sellingBitcoin', false, statusChangeHandler);
|
||||
showError(err);
|
||||
return;
|
||||
}
|
||||
var accessToken = res.accessToken;
|
||||
var accountId = res.accountId;
|
||||
|
||||
var dataSrc = {
|
||||
name: 'Received from ' + appConfigService.nameCase
|
||||
};
|
||||
coinbaseService.createAddress(accessToken, accountId, dataSrc, function(err, data) {
|
||||
if (err) {
|
||||
ongoingProcess.set('sellingBitcoin', false, statusChangeHandler);
|
||||
showError(err);
|
||||
return;
|
||||
}
|
||||
var outputs = [];
|
||||
var toAddress = data.data.address;
|
||||
var amountSat = parseInt(($scope.sellRequestInfo.amount.amount * 100000000).toFixed(0));
|
||||
var comment = 'Sell bitcoin (Coinbase)';
|
||||
|
||||
outputs.push({
|
||||
'toAddress': address,
|
||||
'amount': amount,
|
||||
'toAddress': toAddress,
|
||||
'amount': amountSat,
|
||||
'message': comment
|
||||
});
|
||||
|
||||
var txp = {
|
||||
toAddress: address,
|
||||
amount: amount,
|
||||
toAddress: toAddress,
|
||||
amount: amountSat,
|
||||
outputs: outputs,
|
||||
message: comment,
|
||||
payProUrl: null,
|
||||
|
|
@ -189,73 +260,47 @@ angular.module('copayApp.controllers').controller('sellCoinbaseController',
|
|||
feeLevel: walletSettings.feeLevel || 'normal'
|
||||
};
|
||||
|
||||
walletService.createTx(client, txp, function(err, createdTxp) {
|
||||
walletService.createTx($scope.wallet, txp, function(err, ctxp) {
|
||||
if (err) {
|
||||
$log.debug(err);
|
||||
ongoingProcess.set('Creating Transaction...', false);
|
||||
self.error = {
|
||||
errors: [{
|
||||
message: 'Could not create transaction: ' + err.message
|
||||
}]
|
||||
};
|
||||
$scope.$apply();
|
||||
ongoingProcess.set('sellingBitcoin', false, statusChangeHandler);
|
||||
showError(err);
|
||||
return;
|
||||
}
|
||||
ongoingProcess.set('Creating Transaction...', false);
|
||||
$scope.$emit('Local/NeedsConfirmation', createdTxp, function(accept) {
|
||||
if (accept) {
|
||||
self.confirmTx(createdTxp, function(err, tx) {
|
||||
ongoingProcess.clear();
|
||||
if (err) {
|
||||
self.error = {
|
||||
errors: [{
|
||||
message: 'Could not create transaction: ' + err.message
|
||||
}]
|
||||
};
|
||||
return;
|
||||
}
|
||||
ongoingProcess.set('Checking Transaction...', false);
|
||||
coinbaseService.getTransactions(token, accountId, function(err, ctxs) {
|
||||
if (err) {
|
||||
$log.debug(err);
|
||||
return;
|
||||
}
|
||||
lodash.each(ctxs.data, function(ctx) {
|
||||
if (ctx.type == 'send' && ctx.from) {
|
||||
ongoingProcess.clear();
|
||||
if (ctx.status == 'completed') {
|
||||
self.sellRequest(token, account, ctx);
|
||||
} else {
|
||||
// Save to localstorage
|
||||
ctx['price_sensitivity'] = $scope.selectedPriceSensitivity;
|
||||
ctx['sell_price_amount'] = self.sellPrice ? self.sellPrice.amount : '';
|
||||
ctx['sell_price_currency'] = self.sellPrice ? self.sellPrice.currency : 'USD';
|
||||
ctx['description'] = 'Copay Wallet: ' + client.credentials.walletName;
|
||||
coinbaseService.savePendingTransaction(ctx, null, function(err) {
|
||||
if (err) $log.debug(err);
|
||||
self.sendInfo = ctx;
|
||||
$timeout(function() {
|
||||
$scope.$emit('Local/CoinbaseTx');
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
go.path('coinbase');
|
||||
$log.debug('Transaction created.');
|
||||
publishAndSign($scope.wallet, ctxp, function() {}, function(err, txSent) {
|
||||
if (err) {
|
||||
ongoingProcess.set('sellingBitcoin', false, statusChangeHandler);
|
||||
showError(err);
|
||||
return;
|
||||
}
|
||||
$log.debug('Transaction broadcasted. Wait for Coinbase confirmation...');
|
||||
checkTransaction(1, txSent);
|
||||
});
|
||||
});
|
||||
});
|
||||
}, 100);
|
||||
};
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
this.confirmTx = function(txp, cb) {
|
||||
$scope.showWalletSelector = function() {
|
||||
$scope.walletSelectorTitle = 'Sell From';
|
||||
$scope.showWallets = true;
|
||||
};
|
||||
|
||||
// TODO see walletService createAndPublish
|
||||
};
|
||||
$scope.onWalletSelect = function(wallet) {
|
||||
$scope.wallet = wallet;
|
||||
};
|
||||
|
||||
});
|
||||
$scope.goBackHome = function() {
|
||||
$scope.sendStatus = '';
|
||||
$ionicHistory.nextViewOptions({
|
||||
disableAnimate: true,
|
||||
historyRoot: true
|
||||
});
|
||||
$ionicHistory.clearHistory();
|
||||
$state.go('tabs.home').then(function() {
|
||||
$state.transitionTo('tabs.buyandsell.coinbase');
|
||||
});
|
||||
};
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('tabHomeController',
|
||||
function($rootScope, $timeout, $scope, $state, $stateParams, $ionicModal, $ionicScrollDelegate, $window, gettextCatalog, lodash, popupService, ongoingProcess, externalLinkService, latestReleaseService, profileService, walletService, configService, $log, platformInfo, storageService, txpModalService, appConfigService, bitpayCardService, startupService, addressbookService, feedbackService, bwcError) {
|
||||
function($rootScope, $timeout, $scope, $state, $stateParams, $ionicModal, $ionicScrollDelegate, $window, gettextCatalog, lodash, popupService, ongoingProcess, externalLinkService, latestReleaseService, profileService, walletService, configService, $log, platformInfo, storageService, txpModalService, appConfigService, bitpayCardService, startupService, addressbookService, feedbackService, bwcError, coinbaseService) {
|
||||
var wallet;
|
||||
var listeners = [];
|
||||
var notifications = [];
|
||||
|
|
@ -83,6 +83,10 @@ angular.module('copayApp.controllers').controller('tabHomeController',
|
|||
var wallet = profileService.getWallet(walletId);
|
||||
updateWallet(wallet);
|
||||
if ($scope.recentTransactionsEnabled) getNotifications();
|
||||
if (type == 'NewBlock' && n && n.data && n.data.network == 'livenet') {
|
||||
// Update Coinbase
|
||||
coinbaseService.updatePendingTransactions();
|
||||
}
|
||||
}),
|
||||
$rootScope.$on('Local/TxAction', function(e, walletId) {
|
||||
$log.debug('Got action for wallet ' + walletId);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('tabSettingsController', function($scope, appConfigService, $ionicModal, $log, lodash, uxLanguage, platformInfo, profileService, feeService, configService, externalLinkService, bitpayCardService, storageService, glideraService, gettextCatalog) {
|
||||
angular.module('copayApp.controllers').controller('tabSettingsController', function($scope, appConfigService, $log, lodash, uxLanguage, platformInfo, profileService, feeService, configService, externalLinkService, bitpayCardService, storageService, glideraService, coinbaseService, gettextCatalog) {
|
||||
|
||||
var updateConfig = function() {
|
||||
var isCordova = platformInfo.isCordova;
|
||||
|
|
@ -26,6 +26,7 @@ angular.module('copayApp.controllers').controller('tabSettingsController', funct
|
|||
|
||||
$scope.bitpayCardEnabled = config.bitpayCard.enabled;
|
||||
$scope.glideraEnabled = config.glidera.enabled && !isWindowsPhoneApp;
|
||||
$scope.coinbaseEnabled = config.coinbase.enabled && !isWindowsPhoneApp;
|
||||
|
||||
if ($scope.bitpayCardEnabled) {
|
||||
bitpayCardService.getBitpayDebitCards(function(err, cards) {
|
||||
|
|
@ -41,6 +42,13 @@ angular.module('copayApp.controllers').controller('tabSettingsController', funct
|
|||
});
|
||||
}
|
||||
|
||||
if ($scope.coinbaseEnabled) {
|
||||
coinbaseService.setCredentials();
|
||||
coinbaseService.getStoredToken(function(at) {
|
||||
$scope.coinbaseToken = at;
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -142,10 +142,6 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
controller: 'glideraUriController',
|
||||
templateUrl: 'views/glideraUri.html'
|
||||
})
|
||||
.state('uricoinbase', {
|
||||
url: '/uri-coinbase/:url',
|
||||
templateUrl: 'views/coinbaseUri.html'
|
||||
})
|
||||
|
||||
/*
|
||||
*
|
||||
|
|
@ -926,22 +922,52 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
*
|
||||
*/
|
||||
|
||||
.state('coinbase', {
|
||||
url: '/coinbase',
|
||||
templateUrl: 'views/coinbase.html'
|
||||
})
|
||||
.state('preferencesCoinbase', {
|
||||
url: '/preferencesCoinbase',
|
||||
templateUrl: 'views/preferencesCoinbase.html'
|
||||
})
|
||||
.state('buyCoinbase', {
|
||||
url: '/buycoinbase',
|
||||
templateUrl: 'views/buyCoinbase.html'
|
||||
})
|
||||
.state('sellCoinbase', {
|
||||
url: '/sellcoinbase',
|
||||
templateUrl: 'views/sellCoinbase.html'
|
||||
})
|
||||
.state('tabs.buyandsell.coinbase', {
|
||||
url: '/coinbase/:code',
|
||||
views: {
|
||||
'tab-home@tabs': {
|
||||
controller: 'coinbaseController',
|
||||
controllerAs: 'coinbase',
|
||||
templateUrl: 'views/coinbase.html'
|
||||
}
|
||||
}
|
||||
})
|
||||
.state('tabs.preferences.coinbase', {
|
||||
url: '/coinbase',
|
||||
views: {
|
||||
'tab-settings@tabs': {
|
||||
controller: 'preferencesCoinbaseController',
|
||||
templateUrl: 'views/preferencesCoinbase.html'
|
||||
}
|
||||
}
|
||||
})
|
||||
.state('tabs.buyandsell.coinbase.amount', {
|
||||
url: '/amount/:nextStep/:currency',
|
||||
views: {
|
||||
'tab-home@tabs': {
|
||||
controller: 'amountController',
|
||||
templateUrl: 'views/amount.html'
|
||||
}
|
||||
}
|
||||
})
|
||||
.state('tabs.buyandsell.coinbase.buy', {
|
||||
url: '/buy/:amount/:currency',
|
||||
views: {
|
||||
'tab-home@tabs': {
|
||||
controller: 'buyCoinbaseController',
|
||||
templateUrl: 'views/buyCoinbase.html'
|
||||
}
|
||||
}
|
||||
})
|
||||
.state('tabs.buyandsell.coinbase.sell', {
|
||||
url: '/sell/:amount/:currency',
|
||||
views: {
|
||||
'tab-home@tabs': {
|
||||
controller: 'sellCoinbaseController',
|
||||
templateUrl: 'views/sellCoinbase.html'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
/*
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,11 +1,51 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.services').factory('coinbaseService', function($http, $log, platformInfo, lodash, storageService, configService) {
|
||||
angular.module('copayApp.services').factory('coinbaseService', function($http, $log, $window, $filter, platformInfo, lodash, storageService, configService, appConfigService, txFormatService) {
|
||||
var root = {};
|
||||
var credentials = {};
|
||||
var isCordova = platformInfo.isCordova;
|
||||
var isNW = platformInfo.isNW;
|
||||
|
||||
root.setCredentials = function(network) {
|
||||
root.priceSensitivity = [
|
||||
{
|
||||
value: 0.5,
|
||||
name: '0.5%'
|
||||
},
|
||||
{
|
||||
value: 1,
|
||||
name: '1%'
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
name: '2%'
|
||||
},
|
||||
{
|
||||
value: 5,
|
||||
name: '5%'
|
||||
},
|
||||
{
|
||||
value: 10,
|
||||
name: '10%'
|
||||
}
|
||||
];
|
||||
|
||||
root.selectedPriceSensitivity = root.priceSensitivity[1];
|
||||
|
||||
root.setCredentials = function() {
|
||||
|
||||
if (!$window.externalServices || !$window.externalServices.coinbase) {
|
||||
return;
|
||||
}
|
||||
|
||||
var coinbase = $window.externalServices.coinbase;
|
||||
|
||||
/*
|
||||
* Development: 'testnet'
|
||||
* Production: 'livenet'
|
||||
*/
|
||||
credentials.NETWORK = 'livenet';
|
||||
|
||||
// Coinbase permissions
|
||||
credentials.SCOPE = ''
|
||||
+ 'wallet:accounts:read,'
|
||||
+ 'wallet:addresses:read,'
|
||||
|
|
@ -20,26 +60,78 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $
|
|||
+ 'wallet:transactions:send,'
|
||||
+ 'wallet:payment-methods:read';
|
||||
|
||||
// NW has a bug with Window Object
|
||||
if (isCordova) {
|
||||
credentials.REDIRECT_URI = 'copay://coinbase';
|
||||
credentials.REDIRECT_URI = coinbase.redirect_uri.mobile;
|
||||
} else {
|
||||
credentials.REDIRECT_URI = 'urn:ietf:wg:oauth:2.0:oob';
|
||||
credentials.REDIRECT_URI = coinbase.redirect_uri.desktop;
|
||||
}
|
||||
|
||||
if (network == 'testnet') {
|
||||
credentials.HOST = 'https://sandbox.coinbase.com';
|
||||
credentials.API = 'https://api.sandbox.coinbase.com';
|
||||
credentials.CLIENT_ID = '6cdcc82d5d46654c46880e93ab3d2a43c639776347dd88022904bd78cd067841';
|
||||
credentials.CLIENT_SECRET = '228cb6308951f4b6f41ba010c7d7981b2721a493c40c50fd2425132dcaccce59';
|
||||
if (credentials.NETWORK == 'testnet') {
|
||||
credentials.HOST = coinbase.sandbox.host;
|
||||
credentials.API = coinbase.sandbox.api;
|
||||
credentials.CLIENT_ID = coinbase.sandbox.client_id;
|
||||
credentials.CLIENT_SECRET = coinbase.sandbox.client_secret;
|
||||
}
|
||||
else {
|
||||
credentials.HOST = 'https://coinbase.com';
|
||||
credentials.API = 'https://api.coinbase.com';
|
||||
credentials.CLIENT_ID = window.coinbase_client_id;
|
||||
credentials.CLIENT_SECRET = window.coinbase_client_secret;
|
||||
credentials.HOST = coinbase.production.host;
|
||||
credentials.API = coinbase.production.api;
|
||||
credentials.CLIENT_ID = coinbase.production.client_id;
|
||||
credentials.CLIENT_SECRET = coinbase.production.client_secret;
|
||||
};
|
||||
};
|
||||
|
||||
var _afterTokenReceived = function(data, cb) {
|
||||
if (data && data.access_token && data.refresh_token) {
|
||||
storageService.setCoinbaseToken(credentials.NETWORK, data.access_token, function() {
|
||||
storageService.setCoinbaseRefreshToken(credentials.NETWORK, data.refresh_token, function() {
|
||||
return cb(null, data.access_token);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
return cb('Could not get the access token');
|
||||
}
|
||||
};
|
||||
|
||||
root.getNetwork = function() {
|
||||
return credentials.NETWORK;
|
||||
};
|
||||
|
||||
root.getStoredToken = function(cb) {
|
||||
storageService.getCoinbaseToken(credentials.NETWORK, function(err, accessToken) {
|
||||
if (err || !accessToken) return cb();
|
||||
return cb(accessToken);
|
||||
});
|
||||
};
|
||||
|
||||
root.getAvailableCurrency = function() {
|
||||
var config = configService.getSync().wallet.settings;
|
||||
// ONLY "USD"
|
||||
switch(config.alternativeIsoCode) {
|
||||
default : return 'USD'
|
||||
};
|
||||
};
|
||||
|
||||
root.parseAmount = function(amount, currency) {
|
||||
var config = configService.getSync().wallet.settings;
|
||||
var satToBtc = 1 / 100000000;
|
||||
var unitToSatoshi = config.unitToSatoshi;
|
||||
var amountUnitStr;
|
||||
|
||||
// IF 'USD'
|
||||
if (currency) {
|
||||
amountUnitStr = $filter('formatFiatAmount')(amount) + ' ' + currency;
|
||||
} else {
|
||||
var amountSat = parseInt((amount * unitToSatoshi).toFixed(0));
|
||||
amountUnitStr = txFormatService.formatAmountStr(amountSat);
|
||||
// convert unit to BTC
|
||||
amount = (amountSat * satToBtc).toFixed(8);
|
||||
currency = 'BTC';
|
||||
}
|
||||
|
||||
return [amount, currency, amountUnitStr];
|
||||
};
|
||||
|
||||
root.getOauthCodeUrl = function() {
|
||||
return credentials.HOST
|
||||
+ '/oauth/authorize?response_type=code&client_id='
|
||||
|
|
@ -54,7 +146,7 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $
|
|||
root.getToken = function(code, cb) {
|
||||
var req = {
|
||||
method: 'POST',
|
||||
url: credentials.API + '/oauth/token',
|
||||
url: credentials.HOST + '/oauth/token',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json'
|
||||
|
|
@ -71,18 +163,18 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $
|
|||
$http(req).then(function(data) {
|
||||
$log.info('Coinbase Authorization Access Token: SUCCESS');
|
||||
// Show pending task from the UI
|
||||
storageService.setNextStep('BuyAndSell', true, function(err) {});
|
||||
return cb(null, data.data);
|
||||
storageService.setNextStep('BuyAndSell', 'true', function(err) {});
|
||||
_afterTokenReceived(data.data, cb);
|
||||
}, function(data) {
|
||||
$log.error('Coinbase Authorization Access Token: ERROR ' + data.statusText);
|
||||
return cb(data.data);
|
||||
return cb(data.data || 'Could not get the access token');
|
||||
});
|
||||
};
|
||||
|
||||
root.refreshToken = function(refreshToken, cb) {
|
||||
var _refreshToken = function(refreshToken, cb) {
|
||||
var req = {
|
||||
method: 'POST',
|
||||
url: credentials.API + '/oauth/token',
|
||||
url: credentials.HOST + '/oauth/token',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json'
|
||||
|
|
@ -98,10 +190,58 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $
|
|||
|
||||
$http(req).then(function(data) {
|
||||
$log.info('Coinbase Refresh Access Token: SUCCESS');
|
||||
return cb(null, data.data);
|
||||
_afterTokenReceived(data.data, cb);
|
||||
}, function(data) {
|
||||
$log.error('Coinbase Refresh Access Token: ERROR ' + data.statusText);
|
||||
return cb(data.data);
|
||||
return cb(data.data || 'Could not get the access token');
|
||||
});
|
||||
};
|
||||
|
||||
var _getMainAccountId = function(accessToken, cb) {
|
||||
root.getAccounts(accessToken, function(err, a) {
|
||||
if (err) return cb(err);
|
||||
var data = a.data;
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
if (data[i].primary && data[i].type == 'wallet') {
|
||||
return cb(null, data[i].id);
|
||||
}
|
||||
}
|
||||
root.logout(function() {});
|
||||
return cb('Your primary account should be a WALLET. Set your wallet account as primary and try again');
|
||||
});
|
||||
};
|
||||
|
||||
root.init = function(cb) {
|
||||
if (lodash.isEmpty(credentials.CLIENT_ID)) {
|
||||
return cb('Coinbase is Disabled');
|
||||
}
|
||||
$log.debug('Trying to initialise Coinbase...');
|
||||
|
||||
storageService.getCoinbaseToken(credentials.NETWORK, function(err, accessToken) {
|
||||
if (err || !accessToken) return cb();
|
||||
else {
|
||||
_getMainAccountId(accessToken, function(err, accountId) {
|
||||
if (err) {
|
||||
if (err.errors && err.errors[0] && err.errors[0].id == 'expired_token') {
|
||||
$log.debug('Refresh token');
|
||||
storageService.getCoinbaseRefreshToken(credentials.NETWORK, function(err, refreshToken) {
|
||||
if (err) return cb(err);
|
||||
_refreshToken(refreshToken, function(err, newToken) {
|
||||
if (err) return cb(err);
|
||||
_getMainAccountId(newToken, function(err, accountId) {
|
||||
if (err) return cb(err);
|
||||
return cb(null, {accessToken: newToken, accountId: accountId});
|
||||
});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
return cb(err);
|
||||
}
|
||||
} else {
|
||||
return cb(null, {accessToken: accessToken, accountId: accountId});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -124,7 +264,7 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $
|
|||
return cb(null, data.data);
|
||||
}, function(data) {
|
||||
$log.error('Coinbase Get Accounts: ERROR ' + data.statusText);
|
||||
return cb(data.data);
|
||||
return cb(data.data || 'Could not get the accounts');
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -172,6 +312,17 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $
|
|||
});
|
||||
};
|
||||
|
||||
root.getAddressTransactions = function(token, accountId, addressId, cb) {
|
||||
if (!token) return cb('Invalid Token');
|
||||
$http(_get('/accounts/' + accountId + '/addresses/' + addressId + '/transactions', token)).then(function(data) {
|
||||
$log.info('Coinbase Address s Transactions: SUCCESS');
|
||||
return cb(null, data.data);
|
||||
}, function(data) {
|
||||
$log.error('Coinbase Address s Transactions: ERROR ' + data.statusText);
|
||||
return cb(data.data);
|
||||
});
|
||||
};
|
||||
|
||||
root.getTransactions = function(token, accountId, cb) {
|
||||
if (!token) return cb('Invalid Token');
|
||||
$http(_get('/accounts/' + accountId + '/transactions', token)).then(function(data) {
|
||||
|
|
@ -252,7 +403,8 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $
|
|||
amount: data.amount,
|
||||
currency: data.currency,
|
||||
payment_method: data.payment_method || null,
|
||||
commit: data.commit || false
|
||||
commit: data.commit || false,
|
||||
quote: data.quote || false
|
||||
};
|
||||
$http(_post('/accounts/' + accountId + '/sells', token, data)).then(function(data) {
|
||||
$log.info('Coinbase Sell Request: SUCCESS');
|
||||
|
|
@ -278,7 +430,8 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $
|
|||
amount: data.amount,
|
||||
currency: data.currency,
|
||||
payment_method: data.payment_method || null,
|
||||
commit: false
|
||||
commit: data.commit || false,
|
||||
quote: data.quote || false
|
||||
};
|
||||
$http(_post('/accounts/' + accountId + '/buys', token, data)).then(function(data) {
|
||||
$log.info('Coinbase Buy Request: SUCCESS');
|
||||
|
|
@ -330,10 +483,13 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $
|
|||
};
|
||||
|
||||
// Pending transactions
|
||||
|
||||
|
||||
root.savePendingTransaction = function(ctx, opts, cb) {
|
||||
var network = configService.getSync().coinbase.testnet ? 'testnet' : 'livenet';
|
||||
storageService.getCoinbaseTxs(network, function(err, oldTxs) {
|
||||
_savePendingTransaction(ctx, opts, cb);
|
||||
};
|
||||
|
||||
var _savePendingTransaction = function(ctx, opts, cb) {
|
||||
storageService.getCoinbaseTxs(credentials.NETWORK, function(err, oldTxs) {
|
||||
if (lodash.isString(oldTxs)) {
|
||||
oldTxs = JSON.parse(oldTxs);
|
||||
}
|
||||
|
|
@ -350,23 +506,200 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $
|
|||
}
|
||||
tx = JSON.stringify(tx);
|
||||
|
||||
storageService.setCoinbaseTxs(network, tx, function(err) {
|
||||
storageService.setCoinbaseTxs(credentials.NETWORK, tx, function(err) {
|
||||
return cb(err);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
root.getPendingTransactions = function(cb) {
|
||||
var network = configService.getSync().coinbase.testnet ? 'testnet' : 'livenet';
|
||||
storageService.getCoinbaseTxs(network, function(err, txs) {
|
||||
var _txs = txs ? JSON.parse(txs) : {};
|
||||
return cb(err, _txs);
|
||||
root.getPendingTransactions = function(coinbasePendingTransactions) {
|
||||
storageService.getCoinbaseTxs(credentials.NETWORK, function(err, txs) {
|
||||
txs = txs ? JSON.parse(txs) : {};
|
||||
coinbasePendingTransactions.data = lodash.isEmpty(txs) ? null : txs;
|
||||
|
||||
root.init(function(err, data) {
|
||||
if (err || lodash.isEmpty(data)) {
|
||||
if (err) $log.error(err);
|
||||
return;
|
||||
}
|
||||
var accessToken = data.accessToken;
|
||||
var accountId = data.accountId;
|
||||
|
||||
lodash.forEach(coinbasePendingTransactions.data, function(dataFromStorage, txId) {
|
||||
if ((dataFromStorage.type == 'sell' && dataFromStorage.status == 'completed') ||
|
||||
(dataFromStorage.type == 'buy' && dataFromStorage.status == 'completed') ||
|
||||
dataFromStorage.status == 'error' ||
|
||||
(dataFromStorage.type == 'send' && dataFromStorage.status == 'completed'))
|
||||
return;
|
||||
root.getTransaction(accessToken, accountId, txId, function(err, tx) {
|
||||
if (err || lodash.isEmpty(tx) || (tx.data && tx.data.error)) {
|
||||
_savePendingTransaction(dataFromStorage, {
|
||||
status: 'error',
|
||||
error: (tx.data && tx.data.error) ? tx.data.error : err
|
||||
}, function(err) {
|
||||
if (err) $log.debug(err);
|
||||
_updateTxs(coinbasePendingTransactions);
|
||||
});
|
||||
return;
|
||||
}
|
||||
_updateCoinbasePendingTransactions(dataFromStorage, tx.data);
|
||||
coinbasePendingTransactions.data[txId] = dataFromStorage;
|
||||
if (tx.data.type == 'send' && tx.data.status == 'completed' && tx.data.from) {
|
||||
root.sellPrice(accessToken, dataFromStorage.sell_price_currency, function(err, s) {
|
||||
if (err) {
|
||||
_savePendingTransaction(dataFromStorage, {
|
||||
status: 'error',
|
||||
error: err
|
||||
}, function(err) {
|
||||
if (err) $log.debug(err);
|
||||
_updateTxs(coinbasePendingTransactions);
|
||||
});
|
||||
return;
|
||||
}
|
||||
var newSellPrice = s.data.amount;
|
||||
var variance = Math.abs((newSellPrice - dataFromStorage.sell_price_amount) / dataFromStorage.sell_price_amount * 100);
|
||||
if (variance < dataFromStorage.price_sensitivity.value) {
|
||||
_sellPending(dataFromStorage, accessToken, accountId, coinbasePendingTransactions);
|
||||
} else {
|
||||
var error = {
|
||||
errors: [{
|
||||
message: 'Price falls over the selected percentage'
|
||||
}]
|
||||
};
|
||||
_savePendingTransaction(dataFromStorage, {
|
||||
status: 'error',
|
||||
error: error
|
||||
}, function(err) {
|
||||
if (err) $log.debug(err);
|
||||
_updateTxs(coinbasePendingTransactions);
|
||||
});
|
||||
}
|
||||
});
|
||||
} else if (tx.data.type == 'buy' && tx.data.status == 'completed' && tx.data.buy) {
|
||||
_sendToWallet(dataFromStorage, accessToken, accountId, coinbasePendingTransactions);
|
||||
} else {
|
||||
_savePendingTransaction(dataFromStorage, {}, function(err) {
|
||||
if (err) $log.debug(err);
|
||||
_updateTxs(coinbasePendingTransactions);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
root.logout = function(network, cb) {
|
||||
storageService.removeCoinbaseToken(network, function() {
|
||||
storageService.removeCoinbaseRefreshToken(network, function() {
|
||||
root.updatePendingTransactions = lodash.throttle(function() {
|
||||
$log.debug('Updating pending transactions...');
|
||||
root.setCredentials();
|
||||
var pendingTransactions = { data: {} };
|
||||
root.getPendingTransactions(pendingTransactions);
|
||||
}, 20000);
|
||||
|
||||
var _updateTxs = function(coinbasePendingTransactions) {
|
||||
storageService.getCoinbaseTxs(credentials.NETWORK, function(err, txs) {
|
||||
txs = txs ? JSON.parse(txs) : {};
|
||||
coinbasePendingTransactions.data = lodash.isEmpty(txs) ? null : txs;
|
||||
});
|
||||
};
|
||||
|
||||
var _sellPending = function(tx, accessToken, accountId, coinbasePendingTransactions) {
|
||||
var data = tx.amount;
|
||||
data['payment_method'] = tx.payment_method || null;
|
||||
data['commit'] = true;
|
||||
root.sellRequest(accessToken, accountId, data, function(err, res) {
|
||||
if (err) {
|
||||
_savePendingTransaction(tx, {
|
||||
status: 'error',
|
||||
error: err
|
||||
}, function(err) {
|
||||
if (err) $log.debug(err);
|
||||
_updateTxs(coinbasePendingTransactions);
|
||||
});
|
||||
} else {
|
||||
if (res.data && !res.data.transaction) {
|
||||
_savePendingTransaction(tx, {
|
||||
status: 'error',
|
||||
error: err
|
||||
}, function(err) {
|
||||
if (err) $log.debug(err);
|
||||
_updateTxs(coinbasePendingTransactions);
|
||||
});
|
||||
return;
|
||||
}
|
||||
_savePendingTransaction(tx, {
|
||||
remove: true
|
||||
}, function(err) {
|
||||
root.getTransaction(accessToken, accountId, res.data.transaction.id, function(err, updatedTx) {
|
||||
_savePendingTransaction(updatedTx.data, {}, function(err) {
|
||||
if (err) $log.debug(err);
|
||||
_updateTxs(coinbasePendingTransactions);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var _sendToWallet = function(tx, accessToken, accountId, coinbasePendingTransactions) {
|
||||
if (!tx) return;
|
||||
var desc = appConfigService.nameCase + ' Wallet';
|
||||
var data = {
|
||||
to: tx.toAddr,
|
||||
amount: tx.amount.amount,
|
||||
currency: tx.amount.currency,
|
||||
description: desc
|
||||
};
|
||||
root.sendTo(accessToken, accountId, data, function(err, res) {
|
||||
if (err) {
|
||||
_savePendingTransaction(tx, {
|
||||
status: 'error',
|
||||
error: err
|
||||
}, function(err) {
|
||||
if (err) $log.debug(err);
|
||||
_updateTxs(coinbasePendingTransactions);
|
||||
});
|
||||
} else {
|
||||
if (res.data && !res.data.id) {
|
||||
_savePendingTransaction(tx, {
|
||||
status: 'error',
|
||||
error: err
|
||||
}, function(err) {
|
||||
if (err) $log.debug(err);
|
||||
_updateTxs(coinbasePendingTransactions);
|
||||
});
|
||||
return;
|
||||
}
|
||||
root.getTransaction(accessToken, accountId, res.data.id, function(err, sendTx) {
|
||||
_savePendingTransaction(tx, {
|
||||
remove: true
|
||||
}, function(err) {
|
||||
_savePendingTransaction(sendTx.data, {}, function(err) {
|
||||
if (err) $log.debug(err);
|
||||
_updateTxs(coinbasePendingTransactions);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var _updateCoinbasePendingTransactions = function(obj /*, …*/ ) {
|
||||
for (var i = 1; i < arguments.length; i++) {
|
||||
for (var prop in arguments[i]) {
|
||||
var val = arguments[i][prop];
|
||||
if (typeof val == "object")
|
||||
_updateCoinbasePendingTransactions(obj[prop], val);
|
||||
else
|
||||
obj[prop] = val ? val : obj[prop];
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
|
||||
root.logout = function(cb) {
|
||||
storageService.removeCoinbaseToken(credentials.NETWORK, function() {
|
||||
storageService.removeCoinbaseRefreshToken(credentials.NETWORK, function() {
|
||||
return cb();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ angular.module('copayApp.services').factory('configService', function(storageSer
|
|||
},
|
||||
|
||||
coinbase: {
|
||||
enabled: false, //disable coinbase for this release
|
||||
enabled: true,
|
||||
testnet: false
|
||||
},
|
||||
|
||||
|
|
@ -222,10 +222,6 @@ angular.module('copayApp.services').factory('configService', function(storageSer
|
|||
configCache.aliasFor = configCache.aliasFor || {};
|
||||
configCache.emailFor = configCache.emailFor || {};
|
||||
|
||||
// Coinbase
|
||||
// Disabled for testnet
|
||||
configCache.coinbase.testnet = false;
|
||||
|
||||
$log.debug('Preferences read:', configCache)
|
||||
|
||||
lodash.each(root._queue, function(x) {
|
||||
|
|
|
|||
|
|
@ -126,9 +126,16 @@ angular.module('copayApp.services').factory('incomingData', function($log, $stat
|
|||
url: data
|
||||
});
|
||||
} else if (data && data.indexOf(appConfigService.name + '://coinbase') === 0) {
|
||||
return $state.go('uricoinbase', {
|
||||
url: data
|
||||
var code = getParameterByName('code', data);
|
||||
$state.go('tabs.home', {}, {
|
||||
'reload': true,
|
||||
'notify': $state.current.name == 'tabs.home' ? false : true
|
||||
}).then(function() {
|
||||
$state.transitionTo('tabs.buyandsell.coinbase', {
|
||||
code: code
|
||||
});
|
||||
});
|
||||
return true;
|
||||
|
||||
// BitPayCard Authentication
|
||||
} else if (data && data.indexOf(appConfigService.name + '://') === 0) {
|
||||
|
|
|
|||
|
|
@ -80,7 +80,6 @@
|
|||
padding: 24px 0;
|
||||
font-size: 18px;
|
||||
.title {
|
||||
float: left;
|
||||
padding-top: 10px;
|
||||
color: $dark-gray;
|
||||
font-weight: bold;
|
||||
|
|
@ -89,6 +88,9 @@
|
|||
color: $light-gray;
|
||||
font-size: 12px;
|
||||
}
|
||||
.select {
|
||||
margin: 10px 1px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.amount {
|
||||
|
|
|
|||
|
|
@ -1,21 +1,129 @@
|
|||
.coinbase-preferences {
|
||||
ul {
|
||||
font-size: 14px;
|
||||
background: white;
|
||||
li {
|
||||
padding: 16px 10px 16px 16px;
|
||||
border-bottom: 1px solid #E9E9EC;
|
||||
#coinbase {
|
||||
$item-lateral-padding: 20px;
|
||||
$item-vertical-padding: 10px;
|
||||
$item-border-color: #EFEFEF;
|
||||
$item-label-color: #6C6C6E;
|
||||
@extend .deflash-blue;
|
||||
|
||||
.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.5rem;
|
||||
|
||||
img {
|
||||
margin-right: 1rem;
|
||||
height: 35px;
|
||||
width: 35px;
|
||||
}
|
||||
|
||||
span {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
}
|
||||
.amount-label{
|
||||
line-height: 30px;
|
||||
.amount{
|
||||
font-size: 38px;
|
||||
margin-bottom: .5rem;
|
||||
|
||||
> .unit {
|
||||
font-family: "Roboto-Light";
|
||||
}
|
||||
}
|
||||
.alternative {
|
||||
font-size: 16px;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.coinbase-last-transactions-content {
|
||||
background: #fff;
|
||||
padding: 0.8rem 1rem;
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid #E4E8EC;
|
||||
}
|
||||
|
||||
.coinbase-pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,12 +21,9 @@
|
|||
<span class="toggle-label" translate>Enable Glidera Service</span>
|
||||
</ion-toggle>
|
||||
|
||||
<!-- disable coinbase for this release -->
|
||||
|
||||
<!-- <ion-toggle ng-show="!isWP" ng-model="coinbaseEnabled" toggle-class="toggle-balanced" ng-change="coinbaseChange()">
|
||||
<ion-toggle ng-show="!isWP" ng-model="coinbaseEnabled.value" toggle-class="toggle-balanced" ng-change="coinbaseChange()">
|
||||
<span class="toggle-label" translate>Enable Coinbase Service</span>
|
||||
</ion-toggle> -->
|
||||
|
||||
</ion-toggle>
|
||||
|
||||
<div class="item item-divider" translate>Wallet Operation</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -14,14 +14,14 @@
|
|||
|
||||
<ion-content scroll="false">
|
||||
|
||||
<div ng-if="!customAmount && !isGlidera">
|
||||
<div ng-if="!customAmount && !isGlidera && !nextStep">
|
||||
<div class="item item-no-bottom-border recipient-label" translate>Recipient</div>
|
||||
|
||||
<div class="item item-text-wrap item-icon-left bitcoin-address" ng-class="{'item-big-icon-left':cardId}">
|
||||
<i class="icon big-icon-svg" ng-if="isWallet">
|
||||
<img src="img/icon-wallet.svg" ng-style="{'background-color': toColor}" class="bg"/>
|
||||
</i>
|
||||
<span ng-if="!isWallet && !isGiftCard && !isGlidera">
|
||||
<span ng-if="!isWallet && !isGiftCard">
|
||||
<i class="icon big-icon-svg" ng-if="isChromeApp">
|
||||
<img src="img/contact-placeholder.svg" class="bg"/>
|
||||
</i>
|
||||
|
|
@ -39,7 +39,8 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-class="{'amount-pane-recipient': !customAmount && !isGlidera, 'amount-pane-no-recipient': customAmount || isGlidera}">
|
||||
<div ng-class="{'amount-pane-recipient': !customAmount && !isGlidera && !nextStep,
|
||||
'amount-pane-no-recipient': customAmount || isGlidera || nextStep}">
|
||||
|
||||
<div class="amount-bar oh">
|
||||
<div class="title">
|
||||
|
|
|
|||
|
|
@ -1,169 +1,113 @@
|
|||
<div
|
||||
class="topbar-container"
|
||||
ng-include="'views/includes/topbar.html'"
|
||||
ng-init="titleSection='Buy'; goBackToState = 'coinbase'; noColor = true">
|
||||
</div>
|
||||
<ion-view id="coinbase" hide-tabs>
|
||||
<ion-nav-bar class="bar-royal">
|
||||
<ion-nav-back-button>
|
||||
</ion-nav-back-button>
|
||||
<ion-nav-title>Buy bitcoin</ion-nav-title>
|
||||
</ion-nav-bar>
|
||||
|
||||
<ion-content class="add-bottom-for-cta">
|
||||
<!-- BUY -->
|
||||
<div class="list" ng-if="buyRequestInfo">
|
||||
|
||||
<div class="content coinbase" ng-controller="buyCoinbaseController as buy">
|
||||
|
||||
<div class="row m20t" ng-show="buy.error || index.coinbaseError" ng-click="buy.error = null">
|
||||
<div class="columns">
|
||||
<div class="box-notification">
|
||||
<ul class="no-bullet m0 size-12 text-warning">
|
||||
<li ng-repeat="err in (buy.error.errors || index.coinbaseError.errors)" ng-bind-html="err.message"></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row m20ti"
|
||||
ng-show="index.coinbaseAccount && !buy.buyInfo && !buy.receiveInfo">
|
||||
<div class="columns">
|
||||
|
||||
<form name="buyCoinbaseForm"
|
||||
ng-submit="buy.buyRequest(index.coinbaseToken, index.coinbaseAccount)" novalidate>
|
||||
|
||||
<div ng-if="index.coinbaseToken" ng-init="buy.getPaymentMethods(index.coinbaseToken)">
|
||||
<label>Payment method</label>
|
||||
<select
|
||||
ng-model="selectedPaymentMethod.id"
|
||||
ng-options="item.id as item.name for item in buy.paymentMethods">
|
||||
</select>
|
||||
<div class="item head">
|
||||
<div class="sending-label">
|
||||
<img src="img/buy-bitcoin.svg" alt="buy bitcoin" width="35" class="item-img-buy">
|
||||
<span>Buying</span>
|
||||
</div>
|
||||
<div class="amount-label">
|
||||
<div class="amount">{{amountUnitStr}}</div>
|
||||
<div class="alternative" ng-if="buyPrice">
|
||||
<span ng-show="isFiat">{{buyRequestInfo.amount.amount}} {{buyRequestInfo.amount.currency}}</span>
|
||||
@ ${{buyPrice.amount}} per BTC
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label>Amount
|
||||
<span
|
||||
ng-if="index.coinbaseToken"
|
||||
ng-init="buy.getPrice(index.coinbaseToken)"
|
||||
ng-show="buy.buyPrice"
|
||||
class="size-11 text-light right">
|
||||
1 BTC <i class="icon-arrow-right"></i> {{buy.buyPrice.amount}} {{buy.buyPrice.currency}}
|
||||
</span>
|
||||
<div class="info">
|
||||
<label class="item item-input item-select">
|
||||
<div class="input-label">
|
||||
Payment Method
|
||||
</div>
|
||||
<select ng-model="selectedPaymentMethodId.value"
|
||||
ng-options="item.id as item.name for item in paymentMethods"
|
||||
ng-change="buyRequest()">
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<div class="input">
|
||||
<input ng-show="!showAlternative" type="number" id="amount" ignore-mouse-wheel
|
||||
name="amount" ng-attr-placeholder="{{'Amount in ' + (showAlternative ? 'USD' : 'BTC')}}"
|
||||
ng-minlength="0.00000001" ng-maxlength="10000000000"
|
||||
ng-model="amount" autocomplete="off" ng-disabled="buy.loading">
|
||||
|
||||
<input ng-show="showAlternative" type="number" id="fiat" ignore-mouse-wheel
|
||||
name="fiat" ng-attr-placeholder="{{'Amount in ' + (showAlternative ? 'USD' : 'BTC')}}"
|
||||
ng-model="fiat" autocomplete="off" ng-disabled="buy.loading">
|
||||
|
||||
<a ng-show="!showAlternative" class="postfix button"
|
||||
ng-click="showAlternative = true; amount = null">BTC</a>
|
||||
<a ng-show="showAlternative" class="postfix button black"
|
||||
ng-click="showAlternative = false; fiat = null">USD</a>
|
||||
</div>
|
||||
|
||||
<div class="text-center text-gray size-12 m10b">
|
||||
<span ng-show="!(amount || fiat)">
|
||||
Enter the amount to get the exchange rate
|
||||
</span>
|
||||
<span ng-show="!buy.buyPrice && (amount || fiat)">
|
||||
Not available
|
||||
</span>
|
||||
<span ng-show="buy.buyPrice && amount && !fiat">
|
||||
~ {{buy.buyPrice.amount * amount | currency : 'USD ' : 2}}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="text-center">
|
||||
<i class="db fi-arrow-down size-24 m10v"></i>
|
||||
</div>
|
||||
|
||||
<div
|
||||
ng-if="index.coinbaseToken"
|
||||
ng-init="buy.init(index.coinbaseTestnet)"
|
||||
ng-click="openWalletsModal(buy.allWallets)">
|
||||
<label>Copay Wallet</label>
|
||||
<div class="input">
|
||||
<input type="text" id="address" name="address" ng-disabled="buy.selectedWalletId"
|
||||
ng-attr-placeholder="{{'Choose a wallet to receive bitcoin'}}" ng-model="buy.selectedWalletName" required>
|
||||
<a class="postfix size-12 m0 text-gray">
|
||||
<i class="icon-wallet size-18"></i>
|
||||
</a>
|
||||
<div class="item item-icon-right" ng-click="showWalletSelector()">
|
||||
<div class="label">Receive in</div>
|
||||
<div class="wallet">
|
||||
<i class="icon big-icon-svg">
|
||||
<img src="img/icon-wallet.svg" ng-style="{'background-color': wallet.color}" class="bg">
|
||||
</i>
|
||||
{{wallet ? wallet.name : '...'}}
|
||||
</div>
|
||||
<i class="icon bp-arrow-right"></i>
|
||||
</div>
|
||||
|
||||
<div class="input m20t">
|
||||
<input class="button black expand round"
|
||||
ng-disabled="buy.loading || (!amount && !fiat) || !selectedPaymentMethod"
|
||||
ng-style="{'background-color': '#2b71b1'}"
|
||||
type="submit" value="{{'Continue'}}">
|
||||
<div class="item item-divider">
|
||||
Transaction details
|
||||
</div>
|
||||
<div class="item">
|
||||
Amount
|
||||
<span class="item-note">
|
||||
{{buyRequestInfo.subtotal.amount}} {{buyRequestInfo.subtotal.currency}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="item" ng-repeat="fee in buyRequestInfo.fees">
|
||||
<span class="capitalized">
|
||||
{{fee.type}} fee
|
||||
</span>
|
||||
<span class="item-note">
|
||||
{{fee.amount.amount}} {{fee.amount.currency}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="item">
|
||||
Total to pay
|
||||
<span class="item-note total-amount">
|
||||
{{buyRequestInfo.total.amount}} {{buyRequestInfo.total.currency}}
|
||||
</span>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="m20ti row" ng-show="buy.receiveInfo && !buy.sellInfo && !buy.success">
|
||||
<div class="columns">
|
||||
<h1>Funds sent to Copay Wallet</h1>
|
||||
<p class="size-12 text-gray">
|
||||
Buy confirmed. Funds will be send soon to your selected Copay Wallet
|
||||
</p>
|
||||
<button class="m20t outline black round expand"
|
||||
ng-style="{'background-color': '#2b71b1'}"
|
||||
href ui-sref="coinbase">OK</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-show="buy.buyInfo && !buy.receiveInfo && !buy.success">
|
||||
<h4 class="title">Confirm transaction</h4>
|
||||
|
||||
<ul class="no-bullet m10t size-12 white">
|
||||
<li class="line-b line-t p15">
|
||||
<span class="m10 text-normal text-bold">Amount</span>
|
||||
<span class="right text-gray">{{buy.buyInfo.amount.amount}} {{buy.buyInfo.amount.currency}}</span>
|
||||
</li>
|
||||
<li class="line-b oh p15">
|
||||
<span class="m10 text-normal text-bold">Fees</span>
|
||||
<span class="right text-gray">
|
||||
<div ng-repeat="fee in buy.buyInfo.fees">
|
||||
<b>{{fee.type}}</b> {{fee.amount.amount}} {{fee.amount.currency}}
|
||||
</div>
|
||||
</span>
|
||||
</li>
|
||||
<li class="line-b p15">
|
||||
<span class="m10 text-normal text-bold">Subtotal</span>
|
||||
<span class="right text-gray">{{buy.buyInfo.subtotal.amount}} {{buy.buyInfo.subtotal.currency}}</span>
|
||||
</li>
|
||||
<li class="line-b p15">
|
||||
<span class="m10 text-normal text-bold">Total</span>
|
||||
<span class="right text-gray">{{buy.buyInfo.total.amount}} {{buy.buyInfo.total.currency}}</span>
|
||||
</li>
|
||||
<li class="line-b p15">
|
||||
<span class="m10 text-normal text-bold">Payout at</span>
|
||||
<span class="right text-gray">{{buy.buyInfo.payout_at | amCalendar}}</span>
|
||||
</li>
|
||||
<li class="line-b p15">
|
||||
<span class="m10 text-normal text-bold">Deposit into Copay Wallet</span>
|
||||
<span class="right text-gray">{{buy.selectedWalletName}}</span>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="row">
|
||||
<div class="columns">
|
||||
<button class="button black round expand"
|
||||
ng-style="{'background-color': '#2b71b1'}"
|
||||
ng-click="buy.confirmBuy(index.coinbaseToken, index.coinbaseAccount, buy.buyInfo)"
|
||||
ng-disabled="buy.loading">
|
||||
Buy
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="m20t row text-center" ng-show="buy.success">
|
||||
<div class="columns">
|
||||
<h1>Purchase initiated</h1>
|
||||
<p class="text-gray">
|
||||
Bitcoin purchase completed. Coinbase has queued the transfer to your selected Copay wallet.
|
||||
</p>
|
||||
|
||||
<button class="outline dark-gray round expand" href ui-sref="coinbase">OK</button>
|
||||
</ion-content>
|
||||
|
||||
<click-to-accept
|
||||
ng-disabled="!selectedPaymentMethodId.value || !buyRequestInfo || !wallet"
|
||||
ng-click="buyConfirm()"
|
||||
ng-if="!isCordova && buyRequestInfo"
|
||||
click-send-status="sendStatus"
|
||||
has-wallet-chosen="wallet"
|
||||
insufficient-funds="!selectedPaymentMethodId.value"
|
||||
no-matching-wallet="!buyRequestInfo">
|
||||
Confirm purchase
|
||||
</click-to-accept>
|
||||
<slide-to-accept
|
||||
ng-disabled="!selectedPaymentMethodId.value || !buyRequestInfo || !wallet"
|
||||
ng-if="isCordova && buyRequestInfo"
|
||||
slide-on-confirm="buyConfirm()"
|
||||
slide-send-status="sendStatus"
|
||||
has-wallet-chosen="wallet"
|
||||
insufficient-funds="!selectedPaymentMethodId.value"
|
||||
no-matching-wallet="!buyRequestInfo">
|
||||
Slide to buy
|
||||
</slide-to-accept>
|
||||
<slide-to-accept-success
|
||||
slide-success-show="sendStatus === 'success'"
|
||||
slide-success-on-confirm="goBackHome()"
|
||||
slide-success-hide-on-confirm="true">
|
||||
<span>Bought</span>
|
||||
<div class="m10 size-14">
|
||||
Bitcoin purchase completed. Coinbase has queued the transfer to your selected wallet
|
||||
</div>
|
||||
</div>
|
||||
</slide-to-accept-success>
|
||||
|
||||
</div>
|
||||
<div class="extra-margin-bottom"></div>
|
||||
<wallet-selector
|
||||
wallet-selector-title="walletSelectorTitle"
|
||||
wallet-selector-wallets="wallets"
|
||||
wallet-selector-selected-wallet="wallet"
|
||||
wallet-selector-show="showWallets"
|
||||
wallet-selector-on-select="onWalletSelect">
|
||||
</wallet-selector>
|
||||
</ion-view>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,10 @@
|
|||
</ion-nav-bar>
|
||||
<ion-content>
|
||||
<ion-list>
|
||||
<ion-item class="item item-icon-right" ui-sref="tabs.buyandsell.coinbase">
|
||||
<img src="img/coinbase-logo.png" width="90">
|
||||
<i class="icon bp-arrow-right"></i>
|
||||
</ion-item>
|
||||
<ion-item class="item item-icon-right" ui-sref="tabs.buyandsell.glidera">
|
||||
<img src="img/glidera-logo.png" width="90">
|
||||
<i class="icon bp-arrow-right"></i>
|
||||
|
|
|
|||
|
|
@ -1,59 +1,19 @@
|
|||
<ion-view id="coinbase">
|
||||
<ion-nav-bar class="bar-royal">
|
||||
<ion-nav-back-button>
|
||||
</ion-nav-back-button>
|
||||
<ion-nav-title>Coinbase</ion-nav-title>
|
||||
</ion-nav-bar>
|
||||
|
||||
<div class="topbar-container">
|
||||
<nav ng-controller="topbarController as topbar"
|
||||
class="tab-bar"
|
||||
ng-style="{'background-color': '#2b71b1'}">
|
||||
<section class="left-small">
|
||||
<a class="p10"
|
||||
ng-click="topbar.goHome()">
|
||||
<span class="text-close">Close</span>
|
||||
</a>
|
||||
</section>
|
||||
<ion-content>
|
||||
|
||||
<section class="right-small" ng-show="index.coinbaseAccount">
|
||||
<a class="p10" href ui-sref="preferencesCoinbase">
|
||||
<i class="fi-widget size-24"></i>
|
||||
</a>
|
||||
</section>
|
||||
|
||||
<section class="middle tab-bar-section">
|
||||
<h1 class="title ellipsis">
|
||||
Buy & Sell Bitcoin
|
||||
</h1>
|
||||
</section>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<div class="content coinbase p20b" ng-controller="coinbaseController as coinbase">
|
||||
<div class="row" ng-show="index.coinbaseError || (index.coinbaseToken && !index.coinbaseAccount)">
|
||||
<div class="m20b box-notification" ng-show="index.coinbaseError">
|
||||
<ul class="no-bullet m0 text-warning size-12">
|
||||
<li ng-repeat="err in index.coinbaseError.errors" ng-bind-html="err.message"></li>
|
||||
<div class="box-notification error" ng-show="error">
|
||||
<ul class="no-bullet m0 size-12">
|
||||
<li ng-repeat="err in error.errors" ng-bind-html="err.message"></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="m20b box-notification" ng-show="index.coinbaseToken && !index.coinbaseAccount">
|
||||
<div class="text-warning">
|
||||
<span>Your primary account should be a WALLET. Set your wallet account as primary and try again.</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="m10t text-center">
|
||||
<button
|
||||
class="dark-gray outline round tiny"
|
||||
ng-click="index.initCoinbase(index.coinbaseToken)">
|
||||
Reconnect
|
||||
</button>
|
||||
<div class="m20t size-12">
|
||||
Or go to <a class="text-gray" href ui-sref="preferencesCoinbase">Preferences</a> and log out manually.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-if="!index.coinbaseToken && !index.coinbaseError" class="row">
|
||||
<div class="box-notification text-center size-12 text-warning" ng-show="index.coinbaseTestnet">
|
||||
<i class="fi-info"></i>
|
||||
Testnet wallets only work with Coinbase Sandbox Accounts
|
||||
</div>
|
||||
<div class="columns" ng-init="showOauthForm = false">
|
||||
<div ng-if="!accessToken && !error" ng-init="showOauthForm = false">
|
||||
<div class="text-center m20v">
|
||||
<img src="img/coinbase-logo.png" width="200">
|
||||
</div>
|
||||
|
|
@ -61,111 +21,112 @@
|
|||
|
||||
<p class="m20t text-gray size-12">Connect your Coinbase account to get started</p>
|
||||
|
||||
<a class="button light-gray outline round small"
|
||||
ng-click="coinbase.openAuthenticateWindow(); showOauthForm = true">
|
||||
<button class="button button-standard button-primary"
|
||||
ng-click="coinbase.openAuthenticateWindow()">
|
||||
Connect to Coinbase
|
||||
</a>
|
||||
<div>
|
||||
</button>
|
||||
<div class="m20t">
|
||||
<a href ng-click="showOauthForm = true" class="text-gray size-12">
|
||||
Do you already have the Oauth Code?
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-center" ng-show="showOauthForm">
|
||||
<div ng-show="showOauthForm">
|
||||
<div class="text-left box-notification" ng-show="coinbase.error">
|
||||
<ul class="no-bullet m0 text-warning size-12">
|
||||
<li ng-repeat="err in coinbase.error.errors" ng-bind-html="err.message"></li>
|
||||
</ul>
|
||||
</div>
|
||||
<form name="oauthCodeForm" ng-submit="coinbase.submitOauthCode(code)" novalidate>
|
||||
<label>OAuth Code</label>
|
||||
<input type="text" ng-model="code" ng-disabled="coinbase.loading"
|
||||
ng-attr-placeholder="{{'Paste the authorization code here'}}" required>
|
||||
<input
|
||||
class="button expand round"
|
||||
ng-style="{'background-color': '#2b71b1'}"
|
||||
type="submit" value="Get started" ng-disabled="oauthCodeForm.$invalid || coinbase.loading">
|
||||
</form>
|
||||
<button class="button light-gray expand outline round"
|
||||
ng-click="showOauthForm = false; index.coinbaseError = null; coinbase.error = null">
|
||||
<i class="fi-arrow-left"></i> <span class="tu">Back</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-if="index.coinbaseToken && index.coinbaseAccount && !index.coinbaseError">
|
||||
|
||||
<div class="p20v text-center" ng-show="index.coinbaseAccount" ng-click="index.updateCoinbase({updateAccount: true})">
|
||||
<img src="img/coinbase-logo.png" width="100">
|
||||
</div>
|
||||
|
||||
<ul ng-show="index.coinbaseAccount" class="no-bullet m0 size-12">
|
||||
<li class="line-b line-t p15 coinbase-pointer"
|
||||
href ui-sref="buyCoinbase">
|
||||
<img src="img/buy-bitcoin.svg" alt="buy bitcoin" width="30">
|
||||
<span class="m10 text-normal text-bold">Buy Bitcoin</span>
|
||||
<span class="right text-gray">
|
||||
<i class="icon-arrow-right3 size-24 right"></i>
|
||||
</span>
|
||||
</li>
|
||||
<li class="line-b p15 coinbase-pointer"
|
||||
href ui-sref="sellCoinbase">
|
||||
<img src="img/sell-bitcoin.svg" alt="sell bitcoin" width="30">
|
||||
<span class="m10 text-normal text-bold">Sell Bitcoin</span>
|
||||
<span class="right text-gray">
|
||||
<i class="icon-arrow-right3 size-24 right"></i>
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div ng-show="index.coinbasePendingTransactions && !index.coinbaseError">
|
||||
<h4 class="title">Activity</h4>
|
||||
<div class="m20b box-notification" ng-show="index.coinbasePendingError">
|
||||
<ul class="no-bullet m0 text-warning size-12">
|
||||
<li ng-repeat="err in index.coinbasePendingError.errors" ng-bind-html="err.message"></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div ng-repeat="(id, tx) in index.coinbasePendingTransactions | orderObjectBy:'updated_at':true track by $index"
|
||||
ng-click="coinbase.openTxModal(tx)"
|
||||
class="row collapse coinbase-last-transactions-content">
|
||||
<div class="large-2 medium-2 small-2 columns">
|
||||
<img src="img/bought-pending.svg" alt="bought" width="24" ng-show="(tx.type == 'buy' || (tx.to && tx.type == 'send')) && tx.status != 'completed'">
|
||||
<img src="img/bought.svg" alt="bought" width="30" ng-show="(tx.type == 'buy' || (tx.to && tx.type == 'send')) && tx.status == 'completed'">
|
||||
<img src="img/sold-pending.svg" alt="sold" width="24" ng-show="tx.from && tx.type == 'send'">
|
||||
<img src="img/sold.svg" alt="sold" width="30" ng-show="!tx.from && tx.type == 'sell' && tx.status == 'completed'">
|
||||
</div>
|
||||
|
||||
<div class="large-5 medium-5 small-5 columns">
|
||||
<div class="size-12 m5t">
|
||||
<span ng-show="tx.type == 'sell' && tx.status == 'completed'">Sold</span>
|
||||
<span ng-show="tx.type == 'buy' && tx.status == 'completed'">Bought</span>
|
||||
<span class="text-bold">
|
||||
<span ng-if="tx.type == 'sell' || (tx.type == 'send' && tx.from)">-</span>{{tx.amount.amount.replace('-','')}}
|
||||
{{tx.amount.currency}}
|
||||
</span>
|
||||
<div class="list settings-input-group">
|
||||
<label class="item item-input item-stacked-label">
|
||||
<span class="input-label">OAuth Code</span>
|
||||
<input type="text"
|
||||
ng-model="code"
|
||||
ng-attr-placeholder="{{'Paste the authorization code here'}}" required>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="large-4 medium-4 small-4 columns text-right">
|
||||
<div ng-show="tx.error" class="m5t size-12 text-warning">
|
||||
<input
|
||||
class="button button-standard button-primary"
|
||||
type="submit" value="Connect Coinbase Account" ng-disabled="oauthCodeForm.$invalid">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-if="accessToken && !error">
|
||||
|
||||
<div class="m20t text-center" ng-click="updateTransactions()">
|
||||
<img src="img/coinbase-logo.png" width="200">
|
||||
</div>
|
||||
|
||||
<div class="m10t size-12 text-center text-gray">
|
||||
<span ng-show="!buyPrice || !sellPrice">...</span>
|
||||
<span ng-show="buyPrice && sellPrice">
|
||||
{{buyPrice.amount}} {{buyPrice.currency}}
|
||||
|
|
||||
{{sellPrice.amount}} {{sellPrice.currency}}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="list card">
|
||||
<a class="item item-icon-right"
|
||||
href ui-sref="tabs.buyandsell.coinbase.amount({nextStep: 'tabs.buyandsell.coinbase.buy', currency: currency})">
|
||||
<img src="img/buy-bitcoin.svg" alt="buy bitcoin" width="30" class="item-img-buy" style="vertical-align:
|
||||
text-bottom;">
|
||||
Buy Bitcoin
|
||||
<i class="icon bp-arrow-right"></i>
|
||||
</a>
|
||||
<a class="item item-icon-right"
|
||||
href ui-sref="tabs.buyandsell.coinbase.amount({nextStep: 'tabs.buyandsell.coinbase.sell', currency: currency})">
|
||||
<img src="img/sell-bitcoin.svg" alt="sell bitcoin" width="30" class="item-img-sell" style="vertical-align:
|
||||
text-bottom;">
|
||||
Sell Bitcoin
|
||||
<i class="icon bp-arrow-right"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="list card">
|
||||
<div class="item item-heading" ng-click="updateTransactions()">
|
||||
Activity
|
||||
</div>
|
||||
<a class="item"
|
||||
ng-if="pendingTransactions.data && !error"
|
||||
ng-repeat="(id, tx) in pendingTransactions.data | orderObjectBy:'updated_at':true track by $index"
|
||||
ng-click="coinbase.openTxModal(tx)">
|
||||
|
||||
<span class="item-note">
|
||||
<div class="assertive" ng-show="tx.error || tx.status == 'error'">
|
||||
Error
|
||||
</div>
|
||||
<div ng-show="!tx.error" class="m5t size-12 text-gray">
|
||||
<div ng-show="!tx.error">
|
||||
<div ng-show="tx.status == 'completed'">
|
||||
<time ng-if="tx.created_at">{{tx.created_at | amTimeAgo}}</time>
|
||||
</div>
|
||||
<div ng-show="tx.status == 'pending'">
|
||||
<span class="label outline gray radius text-gray text-info" ng-if="tx.status == 'pending'">Pending</span>
|
||||
<span ng-if="tx.status == 'pending'">Pending</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="large-1 medium-1 small-1 columns text-right">
|
||||
<i class="icon-arrow-right3 size-18"></i>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
|
||||
<img class="left m10r" src="img/bought-pending.svg" alt="bought" width="24" ng-show="(tx.type == 'buy' || (tx.to && tx.type == 'send')) && tx.status != 'completed'">
|
||||
<img class="left m10r" src="img/bought.svg" alt="bought" width="30" ng-show="(tx.type == 'buy' || (tx.to && tx.type == 'send')) && tx.status == 'completed'">
|
||||
<img class="left m10r" src="img/sold-pending.svg" alt="sold" width="24" ng-show="tx.from && tx.type == 'send'">
|
||||
<img class="left m10r" src="img/sold.svg" alt="sold" width="30" ng-show="!tx.from && tx.type == 'sell' && tx.status == 'completed'">
|
||||
|
||||
<h2>
|
||||
<span ng-show="tx.type == 'sell' && tx.status == 'completed'">Sold</span>
|
||||
<span ng-show="tx.type == 'send' && tx.to && tx.status == 'completed'">Bought</span>
|
||||
</h2>
|
||||
<p>
|
||||
<span ng-if="tx.type == 'sell' || (tx.type == 'send' && tx.from)">-</span>{{tx.amount.amount.replace('-','')}}
|
||||
{{tx.amount.currency}}
|
||||
</p>
|
||||
</a>
|
||||
</div>
|
||||
<div class="m10t text-center" ng-if="loading">
|
||||
<ion-spinner class="spinner-dark" icon="lines"></ion-spinner>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="extra-margin-bottom"></div>
|
||||
</div>
|
||||
</ion-content>
|
||||
</ion-view>
|
||||
|
|
|
|||
|
|
@ -1,22 +0,0 @@
|
|||
<div
|
||||
class="topbar-container"
|
||||
ng-include="'views/includes/topbar.html'"
|
||||
ng-init="titleSection='Coinbase'; closeToHome = true">
|
||||
</div>
|
||||
|
||||
<div class="content coinbase" ng-controller="coinbaseUriController as coinbase" ng-init="coinbase.checkCode()">
|
||||
|
||||
<div class="row m20t">
|
||||
<div class="large-12 columns">
|
||||
<div class="text-center">
|
||||
<img src="img/coinbase-logo.png"
|
||||
ng-click="index.updateCoinbase()" width="100">
|
||||
</div>
|
||||
|
||||
<div class="m10t text-center" ng-show="coinbase.error">
|
||||
<div class="notification m10b size-12 text-warning">{{coinbase.error}}</div>
|
||||
<button class="outline dark-gray tiny round" ng-click="coinbase.submitOauthCode(coinbase.code)">Try again</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -29,6 +29,7 @@
|
|||
<span class="item-note" ng-if="!paymentExpired.value">{{remainingTimeStr.value}}</span>
|
||||
<span class="item-note" ng-if="paymentExpired.value" ng-style="{'color': 'red'}" translate>Expired</span>
|
||||
</div>
|
||||
|
||||
<div class="item">
|
||||
<span class="label" ng-if="!isGlidera" translate>To</span>
|
||||
<span class="label" ng-if="isGlidera == 'buy'">From</span>
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
<ion-modal-view ng-controller="coinbaseConfirmationController">
|
||||
<div class="m20tp text-center">
|
||||
<div class="row">
|
||||
<h1 class="text-center m20b p20h">Are you sure you would like to log out of your Coinbase account?</h1>
|
||||
<p class="text-gray p20h">You will need to log back in to buy or sell bitcoin in Copay.</p>
|
||||
<div class="large-6 medium-6 small-6 columns">
|
||||
<button class="button light-gray expand outline round" ng-click="cancel()">
|
||||
<i class="fi-arrow-left"></i> <span class="tu">Back</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="large-6 medium-6 small-6 columns">
|
||||
<button class="button warning expand round" ng-click="ok()">
|
||||
<span>Log out</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ion-modal-view>
|
||||
|
|
@ -1,104 +1,88 @@
|
|||
<ion-modal-view ng-controller="coinbaseTxDetailsController">
|
||||
<ion-header-bar align-title="center" class="tab-bar" ng-style="{'background-color': '#2b71b1'}">
|
||||
<div class="left-small">
|
||||
<a ng-click="cancel()">
|
||||
<i class="icon-arrow-left3 icon-back"></i>
|
||||
<span class="text-back">Back</span>
|
||||
</a>
|
||||
<ion-header-bar align-title="center" class="bar-royal">
|
||||
<button class="button button-clear" ng-click="close()">
|
||||
Close
|
||||
</button>
|
||||
<div class="title">
|
||||
Details
|
||||
</div>
|
||||
<h1 class="title ellipsis" translate>Details</h1>
|
||||
</ion-header-bar>
|
||||
|
||||
<ion-content>
|
||||
<div class="fix-modals-touch">
|
||||
<div class="header-modal bg-gray text-center">
|
||||
<div class="p20">
|
||||
<img src="img/bought.svg" alt="bought" width="65" ng-show="(tx.type == 'buy' || (tx.type == 'send' && tx.to)) && tx.status == 'completed'">
|
||||
<img src="img/bought-pending.svg" alt="bought" width="65"
|
||||
ng-show="(tx.type == 'buy' || (tx.type == 'send' && tx.to)) && tx.status != 'completed'">
|
||||
<img src="img/sold.svg" alt="bought" width="65" ng-show="tx.type == 'sell' && tx.status == 'completed'">
|
||||
<img src="img/sold-pending.svg" alt="bought" width="65"
|
||||
ng-show="(tx.type == 'sell' || (tx.type == 'send' && tx.from)) && tx.status != 'completed'">
|
||||
</div>
|
||||
<div ng-show="tx.status == 'completed'">
|
||||
<span ng-show="tx.type == 'buy' || tx.type == 'send'">Bought</span>
|
||||
<span ng-show="tx.type == 'sell'">Sold</span>
|
||||
</div>
|
||||
<div ng-show="tx.type == 'send' && (tx.to || tx.from) && tx.status != 'completed'">
|
||||
<span ng-show="tx.to">Receiving purchased bitcoin</span>
|
||||
<span ng-show="tx.from">Sending bitcoin to sell</span>
|
||||
</div>
|
||||
<div ng-show="(tx.type == 'sell' || tx.type == 'buy') && tx.status != 'completed'">
|
||||
<span ng-show="tx.type == 'buy'">Buying bitcoin</span>
|
||||
<span ng-show="tx.type == 'sell'">Selling bitcoin</span>
|
||||
</div>
|
||||
<div class="size-24 text-bold">
|
||||
<span ng-if="tx.type == 'sell' || (tx.type == 'send' && tx.from)">-</span>{{tx.amount.amount.replace('-','')}}
|
||||
{{tx.amount.currency}}
|
||||
</div>
|
||||
<div class="label gray radius m10b">
|
||||
<span ng-if="tx.type == 'sell' || (tx.type == 'send' && tx.from)">-</span>{{tx.native_amount.amount.replace('-','')}}
|
||||
{{tx.native_amount.currency}}
|
||||
</div>
|
||||
<div class="text-center m20v">
|
||||
<div>
|
||||
<img src="img/bought.svg" alt="bought" width="65" ng-show="(tx.type == 'buy' || (tx.type == 'send' && tx.to)) && tx.status == 'completed'">
|
||||
<img src="img/bought-pending.svg" alt="bought" width="65"
|
||||
ng-show="(tx.type == 'buy' || (tx.type == 'send' && tx.to)) && tx.status != 'completed'">
|
||||
<img src="img/sold.svg" alt="bought" width="65" ng-show="tx.type == 'sell' && tx.status == 'completed'">
|
||||
<img src="img/sold-pending.svg" alt="bought" width="65"
|
||||
ng-show="(tx.type == 'sell' || (tx.type == 'send' && tx.from)) && tx.status != 'completed'">
|
||||
</div>
|
||||
|
||||
|
||||
<div class="m20b box-notification" ng-show="tx.error">
|
||||
<ul class="no-bullet m0 text-warning size-12">
|
||||
<li ng-repeat="err in tx.error.errors" ng-bind-html="err.message"></li>
|
||||
</ul>
|
||||
<div ng-show="tx.status == 'completed'">
|
||||
<span ng-show="tx.type == 'buy' || tx.type == 'send'">Bought</span>
|
||||
<span ng-show="tx.type == 'sell'">Sold</span>
|
||||
</div>
|
||||
|
||||
<ul class="no-bullet size-14">
|
||||
|
||||
<li ng-show="tx.details && tx.status != 'pending'" class="line-b p10 oh">
|
||||
<span class="text-gray">{{tx.details.title}}</span>
|
||||
<span class="right">{{tx.details.subtitle}}</span>
|
||||
</li>
|
||||
|
||||
<li class="line-b p10 oh">
|
||||
<span class="text-gray">Status</span>
|
||||
<span class="text-success right" ng-if="tx.status == 'completed'">Completed</span>
|
||||
<span class="text-info right" ng-if="tx.status == 'pending'">Pending</span>
|
||||
<span class="text-warning right" ng-if="tx.status == 'error'">Error</span>
|
||||
</li>
|
||||
|
||||
<li ng-show="tx.created_at" class="line-b p10 oh">
|
||||
<span class="text-gray">Date</span>
|
||||
<span class="right">{{tx.created_at | amCalendar}}</span>
|
||||
</li>
|
||||
|
||||
<li ng-show="tx.price_sensitivity" class="line-b p10 oh">
|
||||
<span class="text-gray">Price Sensitivity</span>
|
||||
<span class="right">{{tx.price_sensitivity.name}}</span>
|
||||
</li>
|
||||
|
||||
<li ng-show="tx.sell_price_amount" class="line-b p10 oh">
|
||||
<span class="text-gray">Sell Price</span>
|
||||
<span class="right">{{tx.sell_price_amount}} {{tx.sell_price_currency}}</span>
|
||||
</li>
|
||||
|
||||
<li ng-show="tx.description" class="line-b p10 oh">
|
||||
<span class="text-gray" ng-show="tx.from && tx.type == 'send'">Sent bitcoin from</span>
|
||||
<span class="text-gray" ng-show="tx.to && tx.type == 'send'">Receive bitcoin in</span>
|
||||
<span class="right text-bold">{{tx.description}}</span>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="row m20t" ng-show="tx.status == 'error'">
|
||||
<div class="columns">
|
||||
<p class="text-center size-12 text-gray">
|
||||
This action will remove the transaction.
|
||||
</p>
|
||||
<button class="button outline round dark-gray expand tiny"
|
||||
ng-click="remove()">
|
||||
<i class="fi-x"></i>
|
||||
Remove
|
||||
</button>
|
||||
</div>
|
||||
<div ng-show="tx.type == 'send' && (tx.to || tx.from) && tx.status != 'completed'">
|
||||
<span ng-show="tx.to">Receiving purchased bitcoin</span>
|
||||
<span ng-show="tx.from">Sending bitcoin to sell</span>
|
||||
</div>
|
||||
<div ng-show="(tx.type == 'sell' || tx.type == 'buy') && tx.status != 'completed'">
|
||||
<span ng-show="tx.type == 'buy'">Buying bitcoin</span>
|
||||
<span ng-show="tx.type == 'sell'">Selling bitcoin</span>
|
||||
</div>
|
||||
<div class="size-24 text-bold">
|
||||
<span ng-if="tx.type == 'sell' || (tx.type == 'send' && tx.from)">-</span>{{tx.amount.amount.replace('-','')}}
|
||||
{{tx.amount.currency}}
|
||||
</div>
|
||||
<div class="size-12">
|
||||
<span ng-if="tx.type == 'sell' || (tx.type == 'send' && tx.from)">-</span>{{tx.native_amount.amount.replace('-','')}}
|
||||
{{tx.native_amount.currency}}
|
||||
</div>
|
||||
|
||||
<div class="extra-margin-bottom"></div>
|
||||
</div>
|
||||
|
||||
<ul class="card list" ng-show="tx.error">
|
||||
<li class="item" ng-repeat="err in tx.error.errors" ng-bind-html="err.message"></li>
|
||||
</ul>
|
||||
|
||||
<ul class="list">
|
||||
<li ng-show="tx.details && tx.status != 'pending'" class="item">
|
||||
{{tx.details.title}}
|
||||
<span class="item-note">{{tx.details.subtitle}}</span>
|
||||
</li>
|
||||
|
||||
<li class="item">
|
||||
Status
|
||||
<span class="item-note">
|
||||
<span class="balanced" ng-if="tx.status == 'completed'">Completed</span>
|
||||
<span class="dark" ng-if="tx.status == 'pending'">Pending</span>
|
||||
<span class="assertive" ng-if="tx.status == 'error'">Error</span>
|
||||
</span>
|
||||
</li>
|
||||
|
||||
<li ng-show="tx.created_at" class="item">
|
||||
Date
|
||||
<span class="item-note">{{tx.created_at | amCalendar}}</span>
|
||||
</li>
|
||||
|
||||
<li ng-show="tx.price_sensitivity" class="item">
|
||||
Price Sensitivity
|
||||
<span class="item-note">{{tx.price_sensitivity.name}}</span>
|
||||
</li>
|
||||
|
||||
<li ng-show="tx.sell_price_amount" class="item">
|
||||
Sell Price
|
||||
<span class="item-note">{{tx.sell_price_amount}} {{tx.sell_price_currency}}</span>
|
||||
</li>
|
||||
|
||||
<li ng-show="tx.description" class="item">
|
||||
<span ng-show="tx.from && tx.type == 'send'">Sent bitcoin from</span>
|
||||
<span ng-show="tx.to && tx.type == 'send'">Receive bitcoin in</span>
|
||||
<span class="item-note">{{tx.description}}</span>
|
||||
</li>
|
||||
<div ng-show="tx.status == 'error'" class="item item-divider"></div>
|
||||
<div ng-show="tx.status == 'error'" class="item assertive" ng-click="remove()">
|
||||
Remove transaction
|
||||
</div>
|
||||
</ul>
|
||||
</ion-content>
|
||||
</ion-modal-view>
|
||||
|
|
|
|||
|
|
@ -1,60 +1,62 @@
|
|||
<div
|
||||
class="topbar-container"
|
||||
ng-include="'views/includes/topbar.html'"
|
||||
ng-init="titleSection='Preferences'; goBackToState = 'coinbase'; noColor = true">
|
||||
</div>
|
||||
<ion-view>
|
||||
<ion-nav-bar class="bar-royal">
|
||||
<ion-nav-back-button>
|
||||
</ion-nav-back-button>
|
||||
<ion-nav-title>Preferences</ion-nav-title>
|
||||
</ion-nav-bar>
|
||||
|
||||
<div class="content coinbase-preferences" ng-controller="preferencesCoinbaseController as coinbase">
|
||||
<ion-content>
|
||||
|
||||
<ul ng-if="index.coinbaseAccount && !index.coinbaseError" class="no-bullet m0">
|
||||
<h4 class="title m0">Account</h4>
|
||||
<li>
|
||||
<span>ID</span>
|
||||
<span class="right text-gray enable_text_select">
|
||||
{{index.coinbaseAccount.id}}
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<span>Name</span>
|
||||
<span class="right text-gray">
|
||||
{{index.coinbaseAccount.name}}
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<span>Balance</span>
|
||||
<span class="right text-gray">
|
||||
{{index.coinbaseAccount.balance.amount}} {{index.coinbaseAccount.balance.currency}}
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<span>Native Balance</span>
|
||||
<span class="right text-gray">
|
||||
{{index.coinbaseAccount.native_balance.amount}} {{index.coinbaseAccount.native_balance.currency}}
|
||||
</span>
|
||||
</li>
|
||||
<ul ng-if="coinbaseAccount && !error" class="list">
|
||||
<div class="item item-divider">
|
||||
Account
|
||||
</div>
|
||||
<li class="item">
|
||||
<span>ID</span>
|
||||
<span class="item-note">
|
||||
{{coinbaseAccount.id}}
|
||||
</span>
|
||||
</li>
|
||||
<li class="item">
|
||||
<span>Name</span>
|
||||
<span class="item-note">
|
||||
{{coinbaseAccount.name}}
|
||||
</span>
|
||||
</li>
|
||||
<li class="item">
|
||||
<span>Balance</span>
|
||||
<span class="item-note">
|
||||
{{coinbaseAccount.balance.amount}} {{coinbaseAccount.balance.currency}}
|
||||
</span>
|
||||
</li>
|
||||
<li class="item">
|
||||
<span>Native Balance</span>
|
||||
<span class="item-note">
|
||||
{{coinbaseAccount.native_balance.amount}} {{coinbaseAccount.native_balance.currency}}
|
||||
</span>
|
||||
</li>
|
||||
|
||||
<h4 class="title m0">User Information</h4>
|
||||
<li>
|
||||
<span>ID</span>
|
||||
<span class="right text-gray enable_text_select">
|
||||
{{index.coinbaseUser.id}}
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<span>Email</span>
|
||||
<span class="right text-gray">
|
||||
{{index.coinbaseUser.email}}
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="no-bullet m0">
|
||||
<h4></h4>
|
||||
<li ng-click="coinbase.revokeToken(index.coinbaseTestnet)">
|
||||
<i class="icon-arrow-right3 size-24 right text-gray"></i>
|
||||
<span class="text-warning">Log out</span>
|
||||
</li>
|
||||
</ul>
|
||||
<h4></h4>
|
||||
<div class="item item-divider">
|
||||
User Information
|
||||
</div>
|
||||
<li class="item">
|
||||
<span>ID</span>
|
||||
<span class="item-note">
|
||||
{{coinbaseUser.id}}
|
||||
</span>
|
||||
</li>
|
||||
<li class="item">
|
||||
<span>Email</span>
|
||||
<span class="item-note">
|
||||
{{coinbaseUser.email}}
|
||||
</span>
|
||||
</li>
|
||||
|
||||
</div>
|
||||
<div class="extra-margin-bottom"></div>
|
||||
<div class="item item-divider"></div>
|
||||
<li class="item" ng-click="revokeToken()">
|
||||
<span class="assertive">Log out</span>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</ion-content>
|
||||
</ion-view>
|
||||
|
|
|
|||
|
|
@ -1,202 +1,146 @@
|
|||
<div
|
||||
class="topbar-container"
|
||||
ng-include="'views/includes/topbar.html'"
|
||||
ng-init="titleSection='Sell'; goBackToState = 'coinbase'; noColor = true">
|
||||
</div>
|
||||
<ion-view id="coinbase" hide-tabs>
|
||||
<ion-nav-bar class="bar-royal">
|
||||
<ion-nav-back-button>
|
||||
</ion-nav-back-button>
|
||||
<ion-nav-title>Sell bitcoin</ion-nav-title>
|
||||
</ion-nav-bar>
|
||||
|
||||
<ion-content class="add-bottom-for-cta">
|
||||
<!-- SELL -->
|
||||
<div class="list" ng-if="sellRequestInfo">
|
||||
|
||||
<div class="content coinbase" ng-controller="sellCoinbaseController as sell">
|
||||
|
||||
<div class="row m20t" ng-show="sell.error || index.coinbaseError" ng-click="sell.error = null">
|
||||
<div class="columns">
|
||||
<div class="box-notification">
|
||||
<ul class="no-bullet m0 size-12 text-warning">
|
||||
<li ng-repeat="err in (sell.error.errors || index.coinbaseError.errors)" ng-bind-html="err.message"></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row m20ti"
|
||||
ng-show="index.coinbaseAccount && !sell.sellInfo && !sell.sendInfo">
|
||||
<div class="columns">
|
||||
<form
|
||||
name="sellCoinbaseForm"
|
||||
ng-submit="sell.depositFunds(index.coinbaseToken, index.coinbaseAccount)"
|
||||
novalidate>
|
||||
|
||||
|
||||
<div ng-show="!showPriceSensitivity">
|
||||
|
||||
<div
|
||||
ng-if="index.coinbaseToken"
|
||||
ng-init="sell.init(index.coinbaseTestnet)"
|
||||
ng-click="openWalletsModal(sell.allWallets)">
|
||||
<label>Copay Wallet</label>
|
||||
<div class="input">
|
||||
<input type="text" id="address" name="address" ng-disabled="sell.selectedWalletId"
|
||||
ng-attr-placeholder="{{'Choose your source wallet'}}"
|
||||
ng-model="sell.selectedWalletName" required>
|
||||
<a class="postfix size-12 m0 text-gray">
|
||||
<i class="icon-wallet size-18"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label>
|
||||
Amount
|
||||
<span
|
||||
ng-if="index.coinbaseToken"
|
||||
ng-init="sell.getPrice(index.coinbaseToken)"
|
||||
ng-show="sell.sellPrice"
|
||||
class="size-11 text-light right">
|
||||
1 BTC <i class="icon-arrow-right"></i> {{sell.sellPrice.amount}} {{sell.sellPrice.currency}}
|
||||
</span>
|
||||
</label>
|
||||
<div class="input">
|
||||
<input ng-show="!showAlternative" type="number" id="amount" ignore-mouse-wheel
|
||||
name="amount" ng-attr-placeholder="{{'Amount in ' + (showAlternative ? 'USD' : 'BTC')}}"
|
||||
ng-minlength="0.00000001" ng-maxlength="10000000000"
|
||||
ng-model="amount" autocomplete="off">
|
||||
|
||||
<input ng-show="showAlternative" type="number" id="fiat" ignore-mouse-wheel
|
||||
name="fiat" ng-attr-placeholder="{{'Amount in ' + (showAlternative ? 'USD' : 'BTC')}}"
|
||||
ng-model="fiat" autocomplete="off">
|
||||
|
||||
<a ng-show="!showAlternative" class="postfix button"
|
||||
ng-click="showAlternative = true; amount = null">BTC</a>
|
||||
<a ng-show="showAlternative" class="postfix button black"
|
||||
ng-click="showAlternative = false; fiat = null">USD</a>
|
||||
</div>
|
||||
|
||||
<div class="text-center text-gray size-12 m10b">
|
||||
<span ng-show="!(amount || fiat)">
|
||||
Enter the amount to get the exchange rate
|
||||
</span>
|
||||
<span ng-show="!sell.sellPrice && (amount || fiat)">
|
||||
Not available
|
||||
</span>
|
||||
<span ng-show="sell.sellPrice && amount && !fiat">
|
||||
~ {{sell.sellPrice.amount * amount | currency : 'USD ' : 2}}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="text-center">
|
||||
<i class="db fi-arrow-down size-24 m10v"></i>
|
||||
</div>
|
||||
|
||||
<div ng-if="index.coinbaseToken" ng-init="sell.getPaymentMethods(index.coinbaseToken)">
|
||||
<label>Deposit into</label>
|
||||
<select
|
||||
ng-model="selectedPaymentMethod.id"
|
||||
ng-options="item.id as item.name for item in sell.paymentMethods">
|
||||
</select>
|
||||
</div>
|
||||
<div class="input m20t">
|
||||
<a href class="button black expand round"
|
||||
ng-disabled=" (!amount && !fiat) || !sell.sellPrice.amount"
|
||||
ng-style="{'background-color': '#2b71b1'}"
|
||||
ng-click="showPriceSensitivity = true">Continue</a>
|
||||
<div class="item head">
|
||||
<div class="sending-label">
|
||||
<img src="img/sell-bitcoin.svg" alt="sell bitcoin" width="35" class="item-img-sell">
|
||||
<span>Selling</span>
|
||||
</div>
|
||||
<div class="amount-label">
|
||||
<div class="amount">{{amountUnitStr}}</div>
|
||||
<div class="alternative" ng-if="sellPrice">
|
||||
<span ng-show="isFiat">{{sellRequestInfo.amount.amount}} {{sellRequestInfo.amount.currency}}</span>
|
||||
@ ${{sellPrice.amount}} per BTC
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-show="showPriceSensitivity">
|
||||
<h1>Price Sensitivity</h1>
|
||||
<p class="size-14 text-gray">
|
||||
<div class="info">
|
||||
|
||||
<div class="item item-icon-right" ng-click="showWalletSelector()">
|
||||
<div class="label">From</div>
|
||||
<div class="wallet">
|
||||
<i class="icon big-icon-svg">
|
||||
<img src="img/icon-wallet.svg" ng-style="{'background-color': wallet.color}" class="bg">
|
||||
</i>
|
||||
{{wallet ? wallet.name : '...'}}
|
||||
</div>
|
||||
<i class="icon bp-arrow-right"></i>
|
||||
</div>
|
||||
|
||||
<label class="item item-input item-select">
|
||||
<div class="input-label">
|
||||
Deposit into
|
||||
</div>
|
||||
<select ng-model="selectedPaymentMethodId.value"
|
||||
ng-options="item.id as item.name for item in paymentMethods"
|
||||
ng-change="sellRequest()">
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<div class="item item-divider">
|
||||
At what percentage lower price would you accept to sell?
|
||||
</div>
|
||||
<label class="item item-input item-select" ng-if="priceSensitivity">
|
||||
<div class="input-label">Price Sensitivity</div>
|
||||
<select
|
||||
ng-model="selectedPriceSensitivity.data"
|
||||
ng-options="item as item.name for item in priceSensitivity track by item.value">
|
||||
</select>
|
||||
</label>
|
||||
<div class="item size-12" ng-if="selectedPriceSensitivity">
|
||||
<div class="m10b">
|
||||
Coinbase has not yet implemented an immediate method to sell bitcoin from a wallet. To make this sale, funds
|
||||
will be sent to your Coinbase account, and sold when Coinbase accepts the transaction (usually one
|
||||
hour).
|
||||
</p>
|
||||
<label>At what percentage lower price would you accept to sell?</label>
|
||||
<select
|
||||
ng-model="selectedPriceSensitivity"
|
||||
ng-options="item as item.name for item in priceSensitivity track by item.value">
|
||||
</select>
|
||||
<p class="size-12 text-gray">
|
||||
Estimated sale value: {{sell.sellPrice.amount * amount | currency : 'USD ' : 2}} <br>
|
||||
Still sell if price fall until:
|
||||
{{(sell.sellPrice.amount - (selectedPriceSensitivity.value / 100) * sell.sellPrice.amount) * amount | currency : 'USD ' : 2}}
|
||||
</p>
|
||||
|
||||
<div class="input m20t row">
|
||||
<div class="columns large-6 medium-6 small-6">
|
||||
<a href class="button outline dark-gray expand round" ng-click="showPriceSensitivity = false">Back</a>
|
||||
</div>
|
||||
<div class="columns large-6 medium-6 small-6">
|
||||
<input class="button black expand round"
|
||||
ng-disabled="(!amount && !fiat) || !sell.sellPrice.amount"
|
||||
ng-style="{'background-color': '#2b71b1'}"
|
||||
type="submit" value="Confirm">
|
||||
</div>
|
||||
</div>
|
||||
<div class="label" ng-if="sellRequestInfo">Estimated sale value:
|
||||
<strong>
|
||||
{{sellRequestInfo.total.amount | currency : '' : 2}}
|
||||
{{sellRequestInfo.total.currency}}
|
||||
</strong>
|
||||
</div>
|
||||
<div class="label" ng-if="sellRequestInfo">Still sell if price fall until:
|
||||
<strong>
|
||||
{{(sellRequestInfo.total.amount -
|
||||
(selectedPriceSensitivity.data.value / 100) * sellRequestInfo.total.amount) | currency : '' : 2}}
|
||||
{{sellRequestInfo.total.currency}}
|
||||
</strong>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="m20ti row" ng-show="sell.sendInfo && !sell.sellInfo && !sell.success">
|
||||
<div class="columns">
|
||||
<h1>Funds sent to Coinbase Account</h1>
|
||||
<p class="size-12 text-gray">
|
||||
The transaction is not yet confirmed, and will show as "Processing" in your Activity. The bitcoin sale will be completed automatically once it is confirmed by Coinbase.
|
||||
</p>
|
||||
<button class="m20t outline black round expand"
|
||||
ng-style="{'background-color': '#2b71b1'}"
|
||||
ng-click="$root.go('coinbase')">OK</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-show="sell.sellInfo && !sell.sendInfo && !sell.success">
|
||||
<h4 class="title">Confirm transaction</h4>
|
||||
|
||||
<ul class="no-bullet m10t size-12 white">
|
||||
<li class="line-b line-t p15">
|
||||
<span class="m10 text-normal text-bold">Amount</span>
|
||||
<span class="right text-gray">{{sell.sellInfo.amount.amount}} {{sell.sellInfo.amount.currency}}</span>
|
||||
</li>
|
||||
<li class="line-b oh p15">
|
||||
<span class="m10 text-normal text-bold">Fees</span>
|
||||
<span class="right text-gray">
|
||||
<div ng-repeat="fee in sell.sellInfo.fees">
|
||||
<b>{{fee.type}}</b> {{fee.amount.amount}} {{fee.amount.currency}}
|
||||
</div>
|
||||
</span>
|
||||
</li>
|
||||
<li class="line-b p15">
|
||||
<span class="m10 text-normal text-bold">Subtotal</span>
|
||||
<span class="right text-gray">{{sell.sellInfo.subtotal.amount}} {{sell.sellInfo.subtotal.currency}}</span>
|
||||
</li>
|
||||
<li class="line-b p15">
|
||||
<span class="m10 text-normal text-bold">Total</span>
|
||||
<span class="right text-gray">{{sell.sellInfo.total.amount}} {{sell.sellInfo.total.currency}}</span>
|
||||
</li>
|
||||
<li class="line-b p15">
|
||||
<span class="m10 text-normal text-bold">Payout at</span>
|
||||
<span class="right text-gray">{{sell.sellInfo.payout_at | amCalendar}}</span>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="row">
|
||||
<div class="columns">
|
||||
<button class="button black round expand"
|
||||
ng-style="{'background-color': '#2b71b1'}"
|
||||
ng-click="sell.confirmSell(index.coinbaseToken, index.coinbaseAccount, sell.sellInfo)"
|
||||
>
|
||||
Sell
|
||||
</button>
|
||||
<div class="item item-divider">
|
||||
Transaction details
|
||||
</div>
|
||||
<div class="item">
|
||||
Amount
|
||||
<span class="item-note">
|
||||
{{sellRequestInfo.subtotal.amount}} {{sellRequestInfo.subtotal.currency}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="item" ng-repeat="fee in sellRequestInfo.fees">
|
||||
<span class="capitalized">
|
||||
{{fee.type}} fee
|
||||
</span>
|
||||
<span class="item-note">
|
||||
<span ng-if="fee.amount.amount != '0.00'">-</span>
|
||||
{{fee.amount.amount}} {{fee.amount.currency}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="item">
|
||||
Total to receive
|
||||
<span class="item-note total-amount">
|
||||
{{sellRequestInfo.total.amount}} {{sellRequestInfo.total.currency}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="m20t row text-center" ng-show="sell.success">
|
||||
<div class="columns">
|
||||
<h1>Sale initiated</h1>
|
||||
<p class="text-gray">
|
||||
A transfer has been initiated to your bank account and should arrive at {{sell.success.payout_at | amCalendar}}.
|
||||
</p>
|
||||
|
||||
<button class="outline dark-gray round expand"
|
||||
ng-click="$root.go('coinbase')">OK</button>
|
||||
</ion-content>
|
||||
|
||||
<click-to-accept
|
||||
ng-disabled="!selectedPaymentMethodId.value || !sellRequestInfo || !wallet"
|
||||
ng-click="sellConfirm()"
|
||||
ng-if="!isCordova && sellRequestInfo"
|
||||
click-send-status="sendStatus"
|
||||
has-wallet-chosen="wallet"
|
||||
insufficient-funds="!selectedPaymentMethodId.value"
|
||||
no-matching-wallet="!sellRequestInfo">
|
||||
Confirm sale
|
||||
</click-to-accept>
|
||||
<slide-to-accept
|
||||
ng-disabled="!selectedPaymentMethodId.value || !sellRequestInfo || !wallet"
|
||||
ng-if="isCordova && sellRequestInfo"
|
||||
slide-on-confirm="sellConfirm()"
|
||||
slide-send-status="sendStatus"
|
||||
has-wallet-chosen="wallet"
|
||||
insufficient-funds="!selectedPaymentMethodId.value"
|
||||
no-matching-wallet="!sellRequestInfo">
|
||||
Slide to sell
|
||||
</slide-to-accept>
|
||||
<slide-to-accept-success
|
||||
slide-success-show="sendStatus === 'success'"
|
||||
slide-success-on-confirm="goBackHome()"
|
||||
slide-success-hide-on-confirm="true">
|
||||
<span>Funds sent to Coinbase Account</span>
|
||||
<div class="m10 size-14">
|
||||
The transaction is not yet confirmed, and will show as "Pending" in your Activity. The bitcoin sale will be completed automatically once it is confirmed by Coinbase.
|
||||
</div>
|
||||
</div>
|
||||
</slide-to-accept-success>
|
||||
|
||||
</div>
|
||||
<div class="extra-margin-bottom"></div>
|
||||
<wallet-selector
|
||||
wallet-selector-title="walletSelectorTitle"
|
||||
wallet-selector-wallets="wallets"
|
||||
wallet-selector-selected-wallet="wallet"
|
||||
wallet-selector-show="showWallets"
|
||||
wallet-selector-on-select="onWalletSelect">
|
||||
</wallet-selector>
|
||||
</ion-view>
|
||||
|
|
|
|||
|
|
@ -124,10 +124,10 @@
|
|||
<img src="img/glidera-logo.png" width="90"/>
|
||||
<i class="icon bp-arrow-right"></i>
|
||||
</a>
|
||||
<!-- disable coinbase for this release -->
|
||||
<!-- <a ng-if="coinbaseEnabled" ui-sref="exchange.coinbase" class="item">
|
||||
<img src="img/coinbase-logo.png" width="90"> TODO
|
||||
</a> -->
|
||||
<a ng-if="coinbaseEnabled" ui-sref="tabs.buyandsell.coinbase" class="item item-extra-padding item-sub item-icon-right">
|
||||
<img src="img/coinbase-logo.png" width="90">
|
||||
<i class="icon bp-arrow-right"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -156,7 +156,7 @@
|
|||
<span translate>Add BitPay Visa® Card</span>
|
||||
<i class="icon bp-arrow-right"></i>
|
||||
</a>
|
||||
<a ng-if="!externalServices.BuyAndSell && (coinbaseEnabled || glideraEnabled)" ui-sref="tabs.buyandsell.glidera" class="item item-sub item-icon-left item-big-icon-left item-icon-right next-step">
|
||||
<a ng-if="!externalServices.BuyAndSell && (coinbaseEnabled || glideraEnabled)" ui-sref="tabs.buyandsell" class="item item-sub item-icon-left item-big-icon-left item-icon-right next-step">
|
||||
<i class="icon big-icon-svg">
|
||||
<div class="bg icon-buy-bitcoin"></div>
|
||||
</i>
|
||||
|
|
|
|||
|
|
@ -133,6 +133,13 @@
|
|||
<i class="icon bp-arrow-right"></i>
|
||||
</a>
|
||||
|
||||
<a class="item item-icon-right"
|
||||
ng-if="coinbaseEnabled && coinbaseToken"
|
||||
ui-sref="tabs.preferences.coinbase">
|
||||
<img src="img/coinbase-logo.png" width="90"/>
|
||||
<i class="icon bp-arrow-right"></i>
|
||||
</a>
|
||||
|
||||
<div class="item item-divider"></div>
|
||||
|
||||
<a class="item item-icon-right item-icon-left" href ui-sref="tabs.advanced">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue