Fix buy and sell

This commit is contained in:
Gustavo Maximiliano Cortez 2016-12-30 19:08:51 -03:00
commit 1a586f6fcc
No known key found for this signature in database
GPG key ID: 15EDAD8D9F2EB1AF
8 changed files with 268 additions and 228 deletions

View file

@ -72,6 +72,7 @@ angular.module('copayApp.controllers').controller('amountController', function($
} }
$scope.coinbasePaymentMethods = []; $scope.coinbasePaymentMethods = [];
$scope.coinbaseSelectedPaymentMethodId = { value : null };
coinbaseService.getPaymentMethods(data.accessToken, function(err, p) { coinbaseService.getPaymentMethods(data.accessToken, function(err, p) {
lodash.each(p.data, function(pm) { lodash.each(p.data, function(pm) {
if ($scope.isCoinbase == 'sell') { if ($scope.isCoinbase == 'sell') {
@ -79,14 +80,14 @@ angular.module('copayApp.controllers').controller('amountController', function($
$scope.coinbasePaymentMethods.push(pm); $scope.coinbasePaymentMethods.push(pm);
} }
if (pm.allow_sell && pm.primary_sell) { if (pm.allow_sell && pm.primary_sell) {
$scope.coinbaseSelectedPaymentMethod = pm; $scope.coinbaseSelectedPaymentMethodId.value = pm.id;
} }
} else { } else {
if (pm.allow_buy) { if (pm.allow_buy) {
$scope.coinbasePaymentMethods.push(pm); $scope.coinbasePaymentMethods.push(pm);
} }
if (pm.allow_buy && pm.primary_buy) { if (pm.allow_buy && pm.primary_buy) {
$scope.coinbaseSelectedPaymentMethod = pm; $scope.coinbaseSelectedPaymentMethodId.value = pm.id;
} }
} }
}); });
@ -398,7 +399,7 @@ angular.module('copayApp.controllers').controller('amountController', function($
glideraAccessToken: $scope.glideraAccessToken glideraAccessToken: $scope.glideraAccessToken
}); });
} else if ($scope.isCoinbase) { } else if ($scope.isCoinbase) {
if (lodash.isEmpty($scope.coinbaseSelectedPaymentMethod)) { if (lodash.isEmpty($scope.coinbaseSelectedPaymentMethodId.value)) {
popupService.showAlert(gettextCatalog.getString('Error'), 'No Payment Method Selected'); popupService.showAlert(gettextCatalog.getString('Error'), 'No Payment Method Selected');
return; return;
} }
@ -407,12 +408,17 @@ angular.module('copayApp.controllers').controller('amountController', function($
return; return;
} }
var amountUSD = $scope.showAlternativeAmount ? _amount : $filter('formatFiatAmount')(toFiat(_amount)); var amountUSD = $scope.showAlternativeAmount ? _amount : $filter('formatFiatAmount')(toFiat(_amount));
if (amountUSD < 1) {
popupService.showAlert(gettextCatalog.getString('Error'), 'Amount must be at least 1.00 USD');
return;
}
var amount = $scope.showAlternativeAmount ? fromFiat(_amount) : _amount; var amount = $scope.showAlternativeAmount ? fromFiat(_amount) : _amount;
$state.transitionTo('tabs.buyandsell.coinbase.confirm', { $state.transitionTo('tabs.buyandsell.coinbase.confirm', {
toAmount: (amount * unitToSatoshi).toFixed(0), toAmount: (amount * unitToSatoshi).toFixed(0),
toAddress: $scope.toAddress, toAddress: $scope.toAddress,
isCoinbase: $scope.isCoinbase, isCoinbase: $scope.isCoinbase,
coinbasePaymentMethodId: $scope.coinbaseSelectedPaymentMethod.id, coinbasePaymentMethodId: $scope.coinbaseSelectedPaymentMethodId.value,
coinbaseAmount: amountUSD, coinbaseAmount: amountUSD,
coinbaseAmountCurrency: 'USD' coinbaseAmountCurrency: 'USD'
}); });

View file

@ -26,10 +26,8 @@ angular.module('copayApp.controllers').controller('coinbaseController', function
$scope.updateTransactions = function() { $scope.updateTransactions = function() {
$log.debug('Getting transactions...'); $log.debug('Getting transactions...');
coinbaseService.getPendingTransactions($scope.accessToken, $scope.accountId, function(err, txs) { $scope.pendingTransactions = { data: {} };
$scope.pendingTransactions = txs; coinbaseService.getPendingTransactions($scope.pendingTransactions);
});
}; };
this.openAuthenticateWindow = function() { this.openAuthenticateWindow = function() {

View file

@ -159,7 +159,7 @@ angular.module('copayApp.controllers').controller('confirmController', function(
if ($scope.paypro) _paymentTimeControl($scope.paypro.expires); if ($scope.paypro) _paymentTimeControl($scope.paypro.expires);
displayValues(); displayValues();
if ($scope.wallets.length > 1) $scope.showWalletSelector(); if ($scope.wallets.length > 1 && $scope.isCoinbase != 'buy') $scope.showWalletSelector();
else setWallet($scope.wallets[0]); else setWallet($scope.wallets[0]);
$timeout(function() { $timeout(function() {
$scope.$apply(); $scope.$apply();
@ -175,6 +175,8 @@ angular.module('copayApp.controllers').controller('confirmController', function(
$scope.alternativeAmountStr = $filter('formatFiatAmount')($scope.cardAmountUSD) + ' USD'; $scope.alternativeAmountStr = $filter('formatFiatAmount')($scope.cardAmountUSD) + ' USD';
} else if ($scope.giftCardAmountUSD) { } else if ($scope.giftCardAmountUSD) {
$scope.alternativeAmountStr = $filter('formatFiatAmount')($scope.giftCardAmountUSD) + ' USD'; $scope.alternativeAmountStr = $filter('formatFiatAmount')($scope.giftCardAmountUSD) + ' USD';
} else if ($scope.coinbaseAmount) {
$scope.alternativeAmountStr = $filter('formatFiatAmount')($scope.coinbaseAmount) + ' ' + $scope.coinbaseAmountCurrency;
} else { } else {
txFormatService.formatAlternativeStr(toAmount, function(v) { txFormatService.formatAlternativeStr(toAmount, function(v) {
$scope.alternativeAmountStr = v; $scope.alternativeAmountStr = v;
@ -197,6 +199,10 @@ angular.module('copayApp.controllers').controller('confirmController', function(
coinbaseService.sellPrice(data.accessToken, $scope.coinbaseAmountCurrency, function(err, sell) { coinbaseService.sellPrice(data.accessToken, $scope.coinbaseAmountCurrency, function(err, sell) {
$scope.coinbaseSellPrice = sell.data; $scope.coinbaseSellPrice = sell.data;
}); });
coinbaseService.getPaymentMethod(data.accessToken, $scope.coinbasePaymentMethodId, function(err, data) {
if (err) $log.error(err);
$scope.coinbasePaymentMethodInfo = data.data;
});
}); });
} }
}; };
@ -567,30 +573,45 @@ angular.module('copayApp.controllers').controller('confirmController', function(
var accountId = res.accountId; var accountId = res.accountId;
coinbaseService.buyCommit(token, accountId, $scope.coinbaseBuyRequest.id, function(err, b) { coinbaseService.buyCommit(token, accountId, $scope.coinbaseBuyRequest.id, function(err, b) {
if (err) { if (err) {
$log.error(err); ongoingProcess.set('buyingBitcoin', false, onSendStatusChange);
popupService.showAlert(gettextCatalog.getString('Error'), 'Could not complete purchase');
return; return;
} }
var tx = b.data.transaction; var tx = b.data.transaction;
if (!tx) return; if (!tx) {
ongoingProcess.set('buyingBitcoin', false, onSendStatusChange);
popupService.showAlert(gettextCatalog.getString('Error'), 'Transaction not found');
return;
}
coinbaseService.getTransaction(token, accountId, tx.id, function(err, updatedTx) { $timeout(function() {
if (err) $log.debug(err); coinbaseService.getTransaction(token, accountId, tx.id, function(err, updatedTx) {
walletService.getAddress($scope.wallet, false, function(err, walletAddr) {
if (err) { if (err) {
ongoingProcess.set('buyingBitcoin', false, onSendStatusChange);
popupService.showAlert(gettextCatalog.getString('Error'), 'Transaction error');
return; return;
} }
updatedTx.data['toAddr'] = walletAddr; walletService.getAddress($scope.wallet, false, function(err, walletAddr) {
coinbaseService.savePendingTransaction(updatedTx.data, {}, function(err) { if (err) {
if (err) $log.debug(err); ongoingProcess.set('buyingBitcoin', false, onSendStatusChange);
if (updatedTx.data.status == 'completed') { popupService.showAlert(gettextCatalog.getString('Error'), err);
coinbaseSendToCopay(token, accountId, updatedTx.data, onSendStatusChange); return;
} else { }
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) {
if (err) $log.debug(err);
ongoingProcess.set('buyingBitcoin', false, onSendStatusChange); ongoingProcess.set('buyingBitcoin', false, onSendStatusChange);
$scope.coinbaseBuySuccess = updatedTx.data; $scope.coinbaseBuySuccess = updatedTx.data;
} $timeout(function() {
$scope.$apply();
});
});
}); });
}); });
}); }, 8000);
}); });
}); });
} }
@ -610,7 +631,6 @@ angular.module('copayApp.controllers').controller('confirmController', function(
popupService.showConfirm(null, message, okText, cancelText, function(ok) { popupService.showConfirm(null, message, okText, cancelText, function(ok) {
if (!ok) { if (!ok) {
$scope.sendStatus = '';
$timeout(function() { $timeout(function() {
$scope.$apply(); $scope.$apply();
}); });
@ -618,56 +638,13 @@ angular.module('copayApp.controllers').controller('confirmController', function(
} }
// SIMULATE publishAndSign // SIMULATE publishAndSign
//$log.warn('Simulating publishAndSign...'); //$log.warn('Simulating publishAndSign...');
publishAndSign(wallet, txp, onSendStatusChange); $log.debug('Plublish and Sign...');
publishAndSign(wallet, txp, function() {}, function(err) {
$timeout(function() { if (err) return setSendError(err);
$log.debug('Finished publish and sign. Trying to sell...');
coinbaseService.init(function(err, res) { var count = 0;
if (err) { checkTransaction(count, txp, onSendStatusChange);
$log.error(err); });
return;
}
var token = res.accessToken;
var accountId = res.accountId;
coinbaseService.getAddressTransactions(token, accountId, $scope.toAddress, function(err, ctxs) {
if (err) {
ongoingProcess.clear();
$log.debug(err);
return;
}
var coinbaseTransactions = ctxs.data;
var txFound = false;
var ctx;
for(var i = 0; i < coinbaseTransactions.length; i++) {
ctx = coinbaseTransactions[i];
if (ctx.type == 'send' && ctx.from) {
txFound = true;
if (ctx.status == 'completed') {
coinbaseSellRequest(token, accountId, ctx, onSendStatusChange);
} else {
$log.debug('Saving transaction to process later');
ctx['price_sensitivity'] = $scope.selectedPriceSensitivity.data;
ctx['sell_price_amount'] = $scope.coinbaseSellPrice ? $scope.coinbaseSellPrice.amount : '';
ctx['sell_price_currency'] = $scope.coinbaseSellPrice ? $scope.coinbaseSellPrice.currency : 'USD';
ctx['description'] = $window.appConfig.nameCase + ' Wallet: ' + $scope.wallet.name;
$scope.coinbaseSendInfo = ctx;
coinbaseService.savePendingTransaction(ctx, null, function(err) {
ongoingProcess.set('sellingBitcoin', false, onSendStatusChange);
if (err) $log.debug(err);
});
}
}
}
if (!txFound) {
// Transaction sent, but can not verify it on Coinbase.com
// TODO: improve error message
ongoingProcess.clear();
return setSendError('Transaction not found. Please, verify if transaction exists on Coinbase.com');
}
});
});
}, 5000);
}); });
}); });
} }
@ -727,7 +704,7 @@ angular.module('copayApp.controllers').controller('confirmController', function(
((processName === 'signingTx') && $scope.wallet.m > 1) || ((processName === 'signingTx') && $scope.wallet.m > 1) ||
(processName == 'sendingTx' && !$scope.wallet.canSign() && !$scope.wallet.isPrivKeyExternal()) || (processName == 'sendingTx' && !$scope.wallet.canSign() && !$scope.wallet.isPrivKeyExternal()) ||
(processName == 'buyingBitcoin') || (processName == 'buyingBitcoin') ||
(processName == 'sellingBitcoin' && ($scope.coinbaseSellRequest || $scope.coinbaseSendInfo)) (processName == 'sellingBitcoin')
) && !isOn) { ) && !isOn) {
$scope.sendStatus = 'success'; $scope.sendStatus = 'success';
$timeout(function() { $timeout(function() {
@ -960,18 +937,26 @@ angular.module('copayApp.controllers').controller('confirmController', function(
}); });
}; };
function publishAndSign(wallet, txp, onSendStatusChange) { function publishAndSign(wallet, txp, onSendStatusChange, cb) {
if (!wallet.canSign() && !wallet.isPrivKeyExternal()) { if (!wallet.canSign() && !wallet.isPrivKeyExternal()) {
$log.info('No signing proposal: No private key'); $log.info('No signing proposal: No private key');
return walletService.onlyPublish(wallet, txp, function(err) { walletService.onlyPublish(wallet, txp, function(err) {
if (err) setSendError(err); if (err) {
if (cb) return cb(err);
else return setSendError(err);
}
if (cb) return cb();
else return;
}, onSendStatusChange); }, onSendStatusChange);
} }
walletService.publishAndSign(wallet, txp, function(err, txp) { walletService.publishAndSign(wallet, txp, function(err, txp) {
if (err) return setSendError(err); if (err) {
if (cb) return cb(err);
else return setSendError(err);
}
var previousView = $ionicHistory.viewHistory().backView && $ionicHistory.viewHistory().backView.stateName; var previousView = $ionicHistory.viewHistory().backView && $ionicHistory.viewHistory().backView.stateName;
var fromAmazon = previousView.match(/tabs.giftcards.amazon/) ? true : false; var fromAmazon = previousView.match(/tabs.giftcards.amazon/) ? true : false;
@ -990,8 +975,72 @@ angular.module('copayApp.controllers').controller('confirmController', function(
ongoingProcess.set('creatingGiftCard', true); ongoingProcess.set('creatingGiftCard', true);
debounceCreate(count, dataSrc, onSendStatusChange); debounceCreate(count, dataSrc, onSendStatusChange);
} }
if (cb) return cb();
}, onSendStatusChange); }, onSendStatusChange);
} };
var checkTransaction = lodash.throttle(function(count, txp, onSendStatusChange) {
$log.warn('Check if transaction has been received by Coinbase. Try ' + count + '/5');
coinbaseService.init(function(err, res) {
if (err) {
ongoingProcess.set('sellingBitcoin', false, onSendStatusChange);
$log.error(err);
checkTransaction(count, txp, onSendStatusChange);
return;
}
var token = res.accessToken;
var accountId = res.accountId;
coinbaseService.getTransactions(token, accountId, function(err, ctxs) {
if (err) {
ongoingProcess.set('sellingBitcoin', false, onSendStatusChange);
$log.debug(err);
checkTransaction(count, txp, onSendStatusChange);
return;
}
// TX amount in BTC
var satToBtc = 1 / 100000000;
var amountBTC = (txp.amount * satToBtc).toFixed(8);
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.coinbasePaymentMethodId;
ctx['status'] = 'pending'; // Forcing "pending" status to process later
ctx['price_sensitivity'] = $scope.selectedPriceSensitivity.data;
ctx['sell_price_amount'] = $scope.coinbaseSellPrice ? $scope.coinbaseSellPrice.amount : '';
ctx['sell_price_currency'] = $scope.coinbaseSellPrice ? $scope.coinbaseSellPrice.currency : 'USD';
ctx['description'] = $window.appConfig.nameCase + ' Wallet: ' + $scope.wallet.name;
coinbaseService.savePendingTransaction(ctx, null, function(err) {
ongoingProcess.set('sellingBitcoin', false, onSendStatusChange);
if (err) $log.debug(err);
$scope.coinbaseSendInfo = ctx;
$timeout(function() {
$scope.$apply();
});
});
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, onSendStatusChange);
}
}
});
});
}, 8000, {
'leading': true
});
var debounceCreate = lodash.throttle(function(count, dataSrc) { var debounceCreate = lodash.throttle(function(count, dataSrc) {
debounceCreateGiftCard(count, dataSrc); debounceCreateGiftCard(count, dataSrc);
@ -1067,12 +1116,25 @@ angular.module('copayApp.controllers').controller('confirmController', function(
}; };
coinbaseService.init(function(err, res) { coinbaseService.init(function(err, res) {
if (err) { if (err) {
$scope.showWallets = null;
$log.error(err); $log.error(err);
popupService.showAlert(gettextCatalog.getString('Error'), 'Could not connect to Coinbase', function() {
$ionicHistory.goBack();
});
return; return;
} }
coinbaseService.getPaymentMethod(res.accessToken, paymentMethodId, function(err, data) {
if (err) $log.error(err);
$scope.coinbasePaymentMethodInfo = data.data;
});
coinbaseService.buyRequest(res.accessToken, res.accountId, dataSrc, function(err, data) { coinbaseService.buyRequest(res.accessToken, res.accountId, dataSrc, function(err, data) {
if (err) { if (err) {
$scope.showWallets = null;
$log.error(err); $log.error(err);
popupService.showAlert(gettextCatalog.getString('Error'), 'Could not create a buy request', function() {
$ionicHistory.goBack();
});
return; return;
} }
$scope.coinbaseBuyRequest = data.data; $scope.coinbaseBuyRequest = data.data;
@ -1080,48 +1142,4 @@ angular.module('copayApp.controllers').controller('confirmController', function(
}); });
}; };
var coinbaseSellRequest = function(accessToken, accountId, ctx, onSendStatusChange) {
var dataSrc = ctx.amount;
dataSrc['payment_method'] = $scope.coinbasePaymentMethodId || null;
dataSrc['commit'] = true;
coinbaseService.sellRequest(accessToken, accountId, dataSrc, function(err, data) {
if (err) {
ongoingProcess.clear();
$log.error(err);
return;
}
$scope.coinbaseSellRequest = data.data;
coinbaseService.savePendingTransaction($scope.coinbaseSellRequest, null, function(err) {
ongoingProcess.set('sellingBitcoin', false, onSendStatusChange);
if (err) $log.debug(err);
});
});
};
var coinbaseSendToCopay = function(token, accountId, tx, onSendStatusChange) {
var data = {
to: tx.toAddr,
amount: tx.amount.amount,
currency: tx.amount.currency,
description: 'Copay Wallet: ' + $scope.wallet.name
};
coinbaseService.sendTo(token, accountId, data, function(err, res) {
if (err) {
return;
}
$scope.coinbaseReceiveInfo = 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) {
ongoingProcess.set('buyingBitcoin', false, onSendStatusChange);
// TODO
});
});
});
});
};
}); });

View file

@ -476,74 +476,90 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $
}); });
}; };
root.getPendingTransactions = function(accessToken, accountId, cb) { root.getPendingTransactions = function(coinbasePendingTransactions) {
var coinbasePendingTransactions; root.init(function(err, data) {
storageService.getCoinbaseTxs(credentials.NETWORK, function(err, txs) { var accessToken = data.accessToken;
txs = txs ? JSON.parse(txs) : {}; var accountId = data.accountId;
coinbasePendingTransactions = lodash.isEmpty(txs) ? null : txs; storageService.getCoinbaseTxs(credentials.NETWORK, function(err, txs) {
lodash.forEach(coinbasePendingTransactions, function(dataFromStorage, txId) { txs = txs ? JSON.parse(txs) : {};
if ((dataFromStorage.type == 'sell' && dataFromStorage.status == 'completed') || console.log('[coinbaseService.js:484] getCoinbaseTxs',err, txs); //TODO
(dataFromStorage.type == 'buy' && dataFromStorage.status == 'completed') || coinbasePendingTransactions.data = lodash.isEmpty(txs) ? null : txs;
dataFromStorage.status == 'error' ||
(dataFromStorage.type == 'send' && dataFromStorage.status == 'completed')) lodash.forEach(coinbasePendingTransactions.data, function(dataFromStorage, txId) {
return cb(null, coinbasePendingTransactions); if ((dataFromStorage.type == 'sell' && dataFromStorage.status == 'completed') ||
root.getTransaction(accessToken, accountId, txId, function(err, tx) { (dataFromStorage.type == 'buy' && dataFromStorage.status == 'completed') ||
if (err || lodash.isEmpty(tx)) { dataFromStorage.status == 'error' ||
_savePendingTransaction(dataFromStorage, { (dataFromStorage.type == 'send' && dataFromStorage.status == 'completed'))
status: 'error', return;
error: err root.getTransaction(accessToken, accountId, txId, function(err, tx) {
}, function(err) { console.log('[coinbaseService.js:494] getTransaction to UPDATE from Coinbase',err, tx); //TODO
if (err) $log.debug(err); if (err || lodash.isEmpty(tx) || (tx.data && tx.data.error)) {
}); _savePendingTransaction(dataFromStorage, {
return cb(err); status: 'error',
} error: (tx.data && tx.data.error) ? tx.data.error : err
_updateCoinbasePendingTransactions(dataFromStorage, tx.data); }, function(err) {
coinbasePendingTransactions[txId] = dataFromStorage; if (err) $log.debug(err);
if (tx.data.type == 'send' && tx.data.status == 'completed' && tx.data.from) { _updateTxs(coinbasePendingTransactions);
root.sellPrice(accessToken, dataFromStorage.sell_price_currency, function(err, s) { });
if (err) { return;
_savePendingTransaction(dataFromStorage, { }
status: 'error', _updateCoinbasePendingTransactions(dataFromStorage, tx.data);
error: err coinbasePendingTransactions.data[txId] = dataFromStorage;
}, function(err) { if (tx.data.type == 'send' && tx.data.status == 'completed' && tx.data.from) {
if (err) $log.debug(err); root.sellPrice(accessToken, dataFromStorage.sell_price_currency, function(err, s) {
}); if (err) {
return cb(err); _savePendingTransaction(dataFromStorage, {
} status: 'error',
var newSellPrice = s.data.amount; error: err
var variance = Math.abs((newSellPrice - dataFromStorage.sell_price_amount) / dataFromStorage.sell_price_amount * 100); }, function(err) {
if (variance < dataFromStorage.price_sensitivity.value) { if (err) $log.debug(err);
_sellPending(tx.data, accessToken, accountId); _updateTxs(coinbasePendingTransactions);
} else { });
var error = { return;
errors: [{ }
message: 'Price falls over the selected percentage' 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) {
_savePendingTransaction(dataFromStorage, { _sellPending(dataFromStorage, accessToken, accountId, coinbasePendingTransactions);
status: 'error', } else {
error: error var error = {
}, function(err) { errors: [{
if (err) $log.debug(err); message: 'Price falls over the selected percentage'
}); }]
} };
}); _savePendingTransaction(dataFromStorage, {
} else if (tx.data.type == 'buy' && tx.data.status == 'completed' && tx.data.buy) { status: 'error',
_sendToCopay(dataFromStorage, accessToken, accountId); error: error
} else { }, function(err) {
_savePendingTransaction(dataFromStorage, {}, function(err) { if (err) $log.debug(err);
if (err) $log.debug(err); _updateTxs(coinbasePendingTransactions);
}); });
} }
return cb(null, 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);
});
}
});
}); });
}); });
}); });
}; };
var _sellPending = function(tx, accessToken, accountId) { var _updateTxs = function(coinbasePendingTransactions) {
if (!tx) return; 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; var data = tx.amount;
data['payment_method'] = tx.payment_method || null;
data['commit'] = true; data['commit'] = true;
root.sellRequest(accessToken, accountId, data, function(err, res) { root.sellRequest(accessToken, accountId, data, function(err, res) {
if (err) { if (err) {
@ -552,14 +568,16 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $
error: err error: err
}, function(err) { }, function(err) {
if (err) $log.debug(err); if (err) $log.debug(err);
_updateTxs(coinbasePendingTransactions);
}); });
} else { } else {
if (!res.data.transaction) { if (res.data && !res.data.transaction) {
_savePendingTransaction(tx, { _savePendingTransaction(tx, {
status: 'error', status: 'error',
error: err error: err
}, function(err) { }, function(err) {
if (err) $log.debug(err); if (err) $log.debug(err);
_updateTxs(coinbasePendingTransactions);
}); });
return; return;
} }
@ -569,6 +587,7 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $
root.getTransaction(accessToken, accountId, res.data.transaction.id, function(err, updatedTx) { root.getTransaction(accessToken, accountId, res.data.transaction.id, function(err, updatedTx) {
_savePendingTransaction(updatedTx.data, {}, function(err) { _savePendingTransaction(updatedTx.data, {}, function(err) {
if (err) $log.debug(err); if (err) $log.debug(err);
_updateTxs(coinbasePendingTransactions);
}); });
}); });
}); });
@ -576,38 +595,43 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $
}); });
}; };
var _sendToCopay = function(tx, accessToken, accountId) { var _sendToWallet = function(tx, accessToken, accountId, coinbasePendingTransactions) {
if (!tx) return; if (!tx) return;
var data = { var data = {
to: tx.toAddr, to: tx.toAddr,
amount: tx.amount.amount, amount: tx.amount.amount,
currency: tx.amount.currency, currency: tx.amount.currency,
description: 'To Copay Wallet' description: 'To Wallet'
}; };
root.sendTo(accessToken, accountId, data, function(err, res) { root.sendTo(accessToken, accountId, data, function(err, res) {
console.log('[coinbaseService.js:591] SEND TO COPAY',err, res); //TODO
if (err) { if (err) {
_savePendingTransaction(tx, { _savePendingTransaction(tx, {
status: 'error', status: 'error',
error: err error: err
}, function(err) { }, function(err) {
if (err) $log.debug(err); if (err) $log.debug(err);
_updateTxs(coinbasePendingTransactions);
}); });
} else { } else {
if (!res.data.id) { if (res.data && !res.data.id) {
_savePendingTransaction(tx, { _savePendingTransaction(tx, {
status: 'error', status: 'error',
error: err error: err
}, function(err) { }, function(err) {
if (err) $log.debug(err); if (err) $log.debug(err);
_updateTxs(coinbasePendingTransactions);
}); });
return; return;
} }
root.getTransaction(accessToken, accountId, res.data.id, function(err, sendTx) { root.getTransaction(accessToken, accountId, res.data.id, function(err, sendTx) {
console.log('[coinbaseService.js:633] GET UPDATED TX', err, sendTx); //TODO
_savePendingTransaction(tx, { _savePendingTransaction(tx, {
remove: true remove: true
}, function(err) { }, function(err) {
_savePendingTransaction(sendTx.data, {}, function(err) { _savePendingTransaction(sendTx.data, {}, function(err) {
// TODO if (err) $log.debug(err);
_updateTxs(coinbasePendingTransactions);
}); });
}); });
}); });

View file

@ -74,7 +74,7 @@
<span ng-show="isCoinbase == 'buy'">Payment Method</span> <span ng-show="isCoinbase == 'buy'">Payment Method</span>
<span ng-show="isCoinbase == 'sell'">Deposit into</span> <span ng-show="isCoinbase == 'sell'">Deposit into</span>
</div> </div>
<select ng-model="coinbaseSelectedPaymentMethod.id" <select ng-model="coinbaseSelectedPaymentMethodId.value"
ng-options="item.id as item.name for item in coinbasePaymentMethods"> ng-options="item.id as item.name for item in coinbasePaymentMethods">
</select> </select>
</label> </label>

View file

@ -86,8 +86,8 @@
Activity Activity
</div> </div>
<a class="item" <a class="item"
ng-if="pendingTransactions && !error" ng-if="pendingTransactions.data && !error"
ng-repeat="(id, tx) in pendingTransactions | orderObjectBy:'updated_at':true track by $index" ng-repeat="(id, tx) in pendingTransactions.data | orderObjectBy:'updated_at':true track by $index"
ng-click="coinbase.openTxModal(tx)"> ng-click="coinbase.openTxModal(tx)">
<span class="item-note"> <span class="item-note">

View file

@ -46,19 +46,18 @@
will be sent to your Coinbase account, and sold when Coinbase accepts the transaction (usually one will be sent to your Coinbase account, and sold when Coinbase accepts the transaction (usually one
hour). hour).
</div> </div>
<div> <span class="label" ng-if="coinbaseSellPrice">Estimated sale value:
<div> {{coinbaseSellPrice.amount * coinbaseAmountBTC | currency : 'USD ' : 2}}
Estimated sale value: </span>
<span ng-if="coinbaseSellPrice"> <span class="label" ng-if="coinbaseSellPrice">Still sell if price fall until:
{{coinbaseSellPrice.amount * coinbaseAmountBTC | currency : 'USD ' : 2}} {{(coinbaseSellPrice.amount - (selectedPriceSensitivity.data.value / 100) *
</span> coinbaseSellPrice.amount) * coinbaseAmountBTC | currency : 'USD ' : 2}}
</div> </span>
Still sell if price fall until: </div>
<span ng-if="coinbaseSellPrice"> <div class="item single-line" ng-if="isCoinbase && coinbasePaymentMethodInfo">
{{(coinbaseSellPrice.amount - (selectedPriceSensitivity.data.value / 100) * <span class="label" ng-show="isCoinbase == 'buy'">Payment Method</span>
coinbaseSellPrice.amount) * coinbaseAmountBTC | currency : 'USD ' : 2}} <span class="label" ng-show="isCoinbase == 'sell'">Deposit into</span>
</span> <span class="item-note">{{coinbasePaymentMethodInfo.name}}</span>
</div>
</div> </div>
<div class="item"> <div class="item">
<span class="label" ng-if="!(isGlidera || isCoinbase)" translate>To</span> <span class="label" ng-if="!(isGlidera || isCoinbase)" translate>To</span>
@ -147,15 +146,19 @@
</div> </div>
</div> </div>
</div> </div>
<div class="size-12 m10" ng-show="isCoinbase == 'buy'"> <div ng-show="isCoinbase == 'buy'">
<div> <div class="item single-line">
Subtotal: {{coinbaseBuyRequest.subtotal.amount}} {{coinbaseBuyRequest.subtotal.currency}} <span class="label">Subtotal</span>
<span class="item-note">{{coinbaseBuyRequest.subtotal.amount}}
{{coinbaseBuyRequest.subtotal.currency}}</span>
</div> </div>
<div> <div class="item single-line">
Total: {{coinbaseBuyRequest.total.amount}} {{coinbaseBuyRequest.total.currency}} <span class="label">Total</span>
<span class="item-note">{{coinbaseBuyRequest.total.amount}} {{coinbaseBuyRequest.total.currency}}</span>
</div> </div>
<div> <div class="item single-line">
Payout at: {{coinbaseBuyRequest.payout_at | amCalendar}} <span class="label">Payout at</span>
<span class="item-note">{{coinbaseBuyRequest.payout_at | amCalendar}}</span>
</div> </div>
</div> </div>
<div class="text-center" ng-show="noMatchingWallet"> <div class="text-center" ng-show="noMatchingWallet">
@ -191,7 +194,6 @@
slide-success-hide-on-confirm="true"> slide-success-hide-on-confirm="true">
<span ng-show="isCoinbase == 'buy'">Bought</span> <span ng-show="isCoinbase == 'buy'">Bought</span>
<span ng-show="isCoinbase == 'sell' && coinbaseSendInfo">Funds sent to Coinbase Account</span> <span ng-show="isCoinbase == 'sell' && coinbaseSendInfo">Funds sent to Coinbase Account</span>
<span ng-show="isCoinbase == 'sell' && coinbaseSellRequest">Sale initiated</span>
<div ng-show="!isCoinbase"> <div ng-show="!isCoinbase">
<span ng-show="wallet.m == 1 && (wallet.canSign() || wallet.isPrivKeyExternal())" translate>Payment Sent</span> <span ng-show="wallet.m == 1 && (wallet.canSign() || wallet.isPrivKeyExternal())" translate>Payment Sent</span>
<span ng-show="wallet.m > 1 && (wallet.canSign() || wallet.isPrivKeyExternal())" translate>Proposal Created</span> <span ng-show="wallet.m > 1 && (wallet.canSign() || wallet.isPrivKeyExternal())" translate>Proposal Created</span>
@ -204,18 +206,12 @@
<div ng-show="isCoinbase" class="glidera-success"> <div ng-show="isCoinbase" class="glidera-success">
<span ng-show="isCoinbase == 'buy'"> <span ng-show="isCoinbase == 'buy'">
<span ng-show="coinbaseBuySuccess"> <span ng-show="coinbaseBuySuccess">
Bitcoin purchase completed. Coinbase has queued the transfer to your selected Copay wallet Bitcoin purchase completed. Coinbase has queued the transfer to your selected wallet
</span>
<span ng-show="coinbaseReceiveInfo">
Buy confirmed. Funds will be send soon to your selected wallet
</span> </span>
</span> </span>
<span ng-show="isCoinbase == 'sell'"> <span ng-show="isCoinbase == 'sell'">
<span ng-show="coinbaseSendInfo"> <span ng-show="coinbaseSendInfo">
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. 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.
</span>
<span ng-show="coinbaseSellRequest">
A transfer has been initiated to your bank account and should arrive at {{coinbaseSellRequest.payout_at | amCalendar}}.
</span> </span>
</span> </span>
</div> </div>

View file

@ -40,11 +40,9 @@
</div> </div>
</div> </div>
<div class="box-notification error" ng-show="tx.error"> <ul class="card list" ng-show="tx.error">
<ul class="card list"> <li class="item" ng-repeat="err in tx.error.errors" ng-bind-html="err.message"></li>
<li class="item" ng-repeat="err in tx.error.errors" ng-bind-html="err.message"></li> </ul>
</ul>
</div>
<ul class="list"> <ul class="list">
<li ng-show="tx.details && tx.status != 'pending'" class="item"> <li ng-show="tx.details && tx.status != 'pending'" class="item">