feat(txs): support for partial txs and full bill logging

This commit is contained in:
Damian Mee 2014-09-18 02:37:46 +02:00
parent bb4336b78f
commit 55abaa1bb9
3 changed files with 172 additions and 109 deletions

View file

@ -173,29 +173,93 @@ exports.logEvent = function event(rawEvent, deviceFingerprint) {
db.recordDeviceEvent(deviceFingerprint, rawEvent);
};
// Just prompts plugin to send BTC
function _sendBitcoins(tx, callback) {
logger.debug('executing tx: %j', tx);
db.changeTxStatus(tx.txId, 'executing');
walletPlugin.sendBitcoins(
tx.toAddress,
tx.satoshis,
cachedConfig.exchanges.settings.transactionFee,
function(err, txHash) {
if (err) {
var status = err.name === 'InsufficientFunds' ?
'insufficientFunds' :
'failed';
// report insufficient funds error
db.changeTxStatus(tx.txId, status, {error: err.message});
return callback(err);
}
if (txHash) db.changeTxStatus(tx.txId, 'completed', {hash: txHash});
else db.changeTxStatus(tx.txId, 'failed', {error: 'No txHash received'});
pollBalance();
callback(null, txHash);
}
);
}
function executeTransaction(deviceFingerprint, txId, autoTriggered, cb) {
cb = typeof cb === 'function' ? cb : function() {};
clearSession(deviceFingerprint);
// get remaining amount to be sent
db.getPendingAmount(txId, function(err, tx) {
if (err) {
logger.error(err);
return cb(err);
}
if (!tx) {
logger.info('Nothing to send (%s)', txId);
return cb(null, {statusCode: 304}); // Not Modified
}
db.summonTransaction(deviceFingerprint, tx, function(err, txInfo) {
if (err) return cb(err);
// actual sending
if (!txInfo) {
return _sendBitcoins(tx, function(err, txHash) {
cb(null, {
statusCode: 201, // Created
txHash: txHash
});
});
}
// Out of bitcoins: special case
var txErr = null;
if (txInfo.err) {
txErr = new Error(txInfo.err);
if (txInfo.status === 'insufficientFunds') {
txErr.name = 'InsufficientFunds';
}
}
pollBalance();
cb(txErr, txInfo.txHash);
});
});
}
// This is where we record starting trade balance at the beginning
// of the user session
exports.trade = function trade(rawTrade, deviceFingerprint) {
var sessionInfo = sessions[deviceFingerprint];
if (!sessionInfo) {
exports.trade = function trade(rawTrade, deviceFingerprint, cb) {
if (!sessions[deviceFingerprint]) {
sessions[deviceFingerprint] = {
timestamp: Date.now(),
reaper: setTimeout(function() {
// NOTE: at this point we either have bills ONLY *or a partial tx*
// TODO: deal with #1 from ^
db.getPendingTransactions(rawTrade.txId, function(err, txs) {
// NOTE: returns ARRAY of txs
_sendBitcoins(txs[0], function() { });
delete sessions[deviceFingerprint];
});
executeTransaction(deviceFingerprint, rawTrade.txId, true);
}, SESSION_TIMEOUT)
};
}
// record (vel log) inserted bill
db.recordBill(deviceFingerprint, rawTrade);
// add bill to trader queue (if trader is enabled)
if (traderPlugin) {
tradesQueue.push({
@ -203,8 +267,16 @@ exports.trade = function trade(rawTrade, deviceFingerprint) {
satoshis: rawTrade.satoshis
});
}
// record (vel log) inserted bill
db.recordBill(deviceFingerprint, rawTrade, cb);
};
exports.sendBitcoins = function sendBitcoins(deviceFingerprint, rawTx, callback) {
executeTransaction(deviceFingerprint, rawTx.txId, false, callback);
};
exports.fiatBalance = function fiatBalance() {
var rawRate = exports.getDeviceRate().rates.ask;
var commission = cachedConfig.exchanges.settings.commission;
@ -233,84 +305,6 @@ exports.fiatBalance = function fiatBalance() {
return fiatTransferBalance;
};
function _sendBitcoins(tx, callback) {
logger.debug('executing tx: %j', tx);
walletPlugin.sendBitcoins(
tx.toAddress,
tx.satoshis,
cachedConfig.exchanges.settings.transactionFee,
function(err, txHash) {
if (err) {
var status = err.name === 'InsufficientFunds' ?
'insufficientFunds' :
'failed';
// report insufficient funds error
db.changeTxStatus(tx.txId, status, {error: err.message});
return callback(err);
}
if (txHash) db.changeTxStatus(tx.txId, 'completed', {hash: txHash});
else db.changeTxStatus(tx.txId, 'failed', {error: 'No txHash received'});
pollBalance();
callback(null, txHash);
}
);
}
exports.sendBitcoins = function sendBitcoins(deviceFingerprint, tx, callback) {
db.summonTransaction(deviceFingerprint, tx, function(err, txInfo) {
if (err) return callback(err);
if (!txInfo || txInfo.status === 'partial') {
// TODO: make sure session exists, to prevent sending coins twice
clearSession(deviceFingerprint);
return _sendBitcoins(tx, callback);
}
// Out of bitcoins: special case
var txErr = null;
if (txInfo.err) {
txErr = new Error(txInfo.err);
if (txInfo.status === 'insufficientFunds') {
txErr.name = 'InsufficientFunds';
}
}
// transaction exists, but txHash might be null,
// in which case ATM should continue polling
pollBalance();
callback(txErr, txInfo.txHash);
});
};
// NOTE: temporarily here
exports.sendBitcoinians = function(deviceFingerprint, tx, callback) {
db.summonTransaction(deviceFingerprint, tx, function(err, txInfo) {
if (err) return callback(err);
if (txInfo) {
if (txInfo.status === 'insufficientFunds') {
}
if (txInfo.status === 'executing') {
}
// TODO: check `part` and what has already been sent
}
// no error & no tx record exists
// TODO: should it be confirmed with bills?
});
};
/*
* Polling livecycle
@ -472,6 +466,7 @@ function executeTrades() {
});
}
/*
* ID Verifier functions
*/