diff --git a/lib/postgresql_interface.js b/lib/postgresql_interface.js index ce746556..72e30c71 100644 --- a/lib/postgresql_interface.js +++ b/lib/postgresql_interface.js @@ -34,14 +34,14 @@ PostgresqlInterface.prototype.summonTransaction = if (err && PG_ERRORS[err.code] === 'uniqueViolation') return self._fetchTransaction(tx.txId, cb); if (err) return cb(err); - cb(null, true); + cb(); }); }; PostgresqlInterface.prototype.reportTransactionError = - function reportTransactionError(tx, err) { + function reportTransactionError(tx, errString, status) { this.client.query('UPDATE transactions SET status=$1, error=$2 WHERE id=$3', - ['failed', err.message, tx.txId]); + [status, errString, tx.txId]); }; PostgresqlInterface.prototype.completeTransaction = @@ -56,7 +56,7 @@ PostgresqlInterface.prototype.completeTransaction = PostgresqlInterface.prototype._fetchTransaction = function _fetchTransaction(txId, cb) { - this.client.query('SELECT status, tx_hash FROM transactions WHERE id=$1', + this.client.query('SELECT status, tx_hash, error FROM transactions WHERE id=$1', [txId], function (err, results) { if (err) return cb(err); @@ -64,6 +64,6 @@ PostgresqlInterface.prototype._fetchTransaction = if (results.rows.length === 0) return cb(new Error('Couldn\'t find transaction.')); var result = results.rows[0]; - cb(null, false, result.tx_hash); + cb(null, {txHash: result.tx_hash, err: result.error, status: result.status}); }); }; diff --git a/lib/routes.js b/lib/routes.js index 0ac54dbe..9bdfd491 100644 --- a/lib/routes.js +++ b/lib/routes.js @@ -57,7 +57,11 @@ var trade = function (req, res) { var send = function(req, res) { var fingerprint = req.connection.getPeerCertificate().fingerprint; _trader.sendBitcoins(fingerprint, req.body, function(err, txHash) { - res.json({err: err, txHash: txHash}); + res.json({ + err: err && err.message, + txHash: txHash, + errType: err && err.name + }); }); }; diff --git a/lib/trader.js b/lib/trader.js index 0dc269af..9cda76c0 100644 --- a/lib/trader.js +++ b/lib/trader.js @@ -55,13 +55,6 @@ Trader.prototype._findWallet = function (name) { return exchange.wallet || exchange; }; -Trader.prototype._tradeQueueFiatBalance = function (exchangeRate) { - var satoshis = this._tradeQueue.reduce(function (memo, rec) { - return memo + rec.satoshis; - }, 0); - return (satoshis / SATOSHI_FACTOR) * exchangeRate; -}; - Trader.prototype._consolidateTrades = function () { var queue = this._tradeQueue; @@ -176,20 +169,23 @@ Trader.prototype._clearSession = function (deviceFingerprint) { Trader.prototype.sendBitcoins = function (deviceFingerprint, tx, cb) { var self = this; - self.db.summonTransaction(deviceFingerprint, tx, function (err, isNew, txHash) { + self.db.summonTransaction(deviceFingerprint, tx, function (err, txRec) { if (err) { return cb(err); } - if (isNew) { - this._clearSession(deviceFingerprint); + if (!txRec) { + self._clearSession(deviceFingerprint); return self.transferExchange.sendBitcoins( tx.toAddress, tx.satoshis, self.config.exchanges.settings.transactionFee, function(err, txHash) { if (err) { - self.db.reportTransactionError(tx, err); + var status = err.name === 'InsufficientFunds' ? + 'insufficientFunds' : + 'failed'; + self.db.reportTransactionError(tx, err.message, status); return cb(err); } @@ -200,9 +196,17 @@ Trader.prototype.sendBitcoins = function (deviceFingerprint, tx, cb) { ); } + // Out of bitcoins: special case + var txErr = null; + if (txRec.err) { + txErr = new Error(txRec.err); + if (txRec.status === 'insufficientFunds') txErr.name = 'InsufficientFunds'; + } + // transaction exists, but txHash might be null, - // in which case ATM should continue polling - cb(null, txHash); + // in which case ATM should continue polling + self.pollBalance(); + cb(txErr, txRec.txHash); }); }; @@ -251,8 +255,6 @@ Trader.prototype.executeTrades = function () { }; Trader.prototype.startPolling = function () { - this.pollBalance(); - this.pollRate(); this.executeTrades(); this.balanceInterval = setInterval(this.pollBalance.bind(this), 60 * 1000);