WIP
This commit is contained in:
parent
d6ec60db55
commit
184d30209a
4 changed files with 74 additions and 29 deletions
|
|
@ -40,6 +40,11 @@ var lastRates = {}
|
||||||
|
|
||||||
var tradesQueues = {}
|
var tradesQueues = {}
|
||||||
|
|
||||||
|
var coins = {
|
||||||
|
BTC: {unitScale: 8},
|
||||||
|
ETH: {unitScale: 18}
|
||||||
|
}
|
||||||
|
|
||||||
// that's basically a constructor
|
// that's basically a constructor
|
||||||
exports.init = function init (databaseHandle) {
|
exports.init = function init (databaseHandle) {
|
||||||
if (!databaseHandle) {
|
if (!databaseHandle) {
|
||||||
|
|
@ -53,7 +58,7 @@ function loadPlugin (name, config) {
|
||||||
// plugins definitions
|
// plugins definitions
|
||||||
var moduleMethods = {
|
var moduleMethods = {
|
||||||
ticker: ['ticker'],
|
ticker: ['ticker'],
|
||||||
trader: ['balance', 'purchase', 'sell'],
|
trader: ['purchase', 'sell'],
|
||||||
wallet: ['balance', 'sendBitcoins', 'newAddress'],
|
wallet: ['balance', 'sendBitcoins', 'newAddress'],
|
||||||
idVerifier: ['verifyUser', 'verifyTransaction'],
|
idVerifier: ['verifyUser', 'verifyTransaction'],
|
||||||
info: ['checkAddress']
|
info: ['checkAddress']
|
||||||
|
|
@ -151,7 +156,7 @@ exports.configure = function configure (config) {
|
||||||
|
|
||||||
cachedConfig = config
|
cachedConfig = config
|
||||||
deviceCurrency = config.exchanges.settings.currency
|
deviceCurrency = config.exchanges.settings.currency
|
||||||
cryptoCodes = config.exchanges.settings.coins || ['BTC']
|
cryptoCodes = config.exchanges.settings.coins || ['BTC', 'ETH']
|
||||||
|
|
||||||
cryptoCodes.forEach(function (cryptoCode) {
|
cryptoCodes.forEach(function (cryptoCode) {
|
||||||
// TICKER [required] configure (or load)
|
// TICKER [required] configure (or load)
|
||||||
|
|
@ -248,21 +253,29 @@ function _sendCoins (toAddress, cryptoAtoms, cryptoCode, cb) {
|
||||||
if (cryptoCode === 'BTC') {
|
if (cryptoCode === 'BTC') {
|
||||||
walletPlugin.sendBitcoins(toAddress, cryptoAtoms, transactionFee, cb)
|
walletPlugin.sendBitcoins(toAddress, cryptoAtoms, transactionFee, cb)
|
||||||
} else {
|
} else {
|
||||||
walletPlugin.sendCoins(toAddress, cryptoAtoms, cryptoCode, transactionFee, cb)
|
walletPlugin.sendBitcoins(toAddress, cryptoAtoms, cryptoCode, transactionFee, cb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function executeTx (session, tx, authority, cb) {
|
function executeTx (session, tx, authority, cb) {
|
||||||
db.addOutgoingTx(session, tx, function (err, toSend) {
|
db.addOutgoingTx(session, tx, function (err, toSend) {
|
||||||
if (err) return cb(err)
|
if (err) {
|
||||||
var cryptoAtomsToSend = toSend.cryptoAtoms
|
logger.error(err)
|
||||||
|
return cb(err)
|
||||||
|
}
|
||||||
|
var cryptoAtomsToSend = toSend.satoshis
|
||||||
if (cryptoAtomsToSend === 0) {
|
if (cryptoAtomsToSend === 0) {
|
||||||
|
logger.debug('No cryptoAtoms to send')
|
||||||
return cb(null, {statusCode: 204, txId: tx.txId, txHash: null})
|
return cb(null, {statusCode: 204, txId: tx.txId, txHash: null})
|
||||||
}
|
}
|
||||||
|
|
||||||
_sendCoins(tx.toAddress, cryptoAtomsToSend, function (_err, txHash) {
|
var cryptoCode = tx.cryptoCode
|
||||||
|
_sendCoins(tx.toAddress, cryptoAtomsToSend, cryptoCode, function (_err, txHash) {
|
||||||
var fee = null // Need to fill this out in plugins
|
var fee = null // Need to fill this out in plugins
|
||||||
if (_err) toSend = {cryptoAtoms: new BigNumber(0), fiat: 0}
|
if (_err) {
|
||||||
|
logger.error(_err)
|
||||||
|
toSend = {cryptoAtoms: new BigNumber(0), fiat: 0}
|
||||||
|
}
|
||||||
db.sentCoins(session, tx, authority, toSend, fee, _err, txHash)
|
db.sentCoins(session, tx, authority, toSend, fee, _err, txHash)
|
||||||
|
|
||||||
if (_err) return cb(_err)
|
if (_err) return cb(_err)
|
||||||
|
|
@ -291,6 +304,7 @@ function reapTx (row) {
|
||||||
satoshis: row.satoshis,
|
satoshis: row.satoshis,
|
||||||
toAddress: row.to_address,
|
toAddress: row.to_address,
|
||||||
currencyCode: row.currency_code,
|
currencyCode: row.currency_code,
|
||||||
|
cryptoCode: row.crypto_code,
|
||||||
incoming: row.incoming
|
incoming: row.incoming
|
||||||
}
|
}
|
||||||
if (!row.incoming) reapOutgoingTx(session, tx)
|
if (!row.incoming) reapOutgoingTx(session, tx)
|
||||||
|
|
@ -314,6 +328,8 @@ function reapTxs () {
|
||||||
|
|
||||||
// TODO: Run these in parallel and return success
|
// TODO: Run these in parallel and return success
|
||||||
exports.trade = function trade (session, rawTrade, cb) {
|
exports.trade = function trade (session, rawTrade, cb) {
|
||||||
|
logger.debug('DEBUG2')
|
||||||
|
|
||||||
// TODO: move this to DB, too
|
// TODO: move this to DB, too
|
||||||
// add bill to trader queue (if trader is enabled)
|
// add bill to trader queue (if trader is enabled)
|
||||||
var cryptoCode = rawTrade.cryptoCode || 'BTC'
|
var cryptoCode = rawTrade.cryptoCode || 'BTC'
|
||||||
|
|
@ -328,14 +344,18 @@ exports.trade = function trade (session, rawTrade, cb) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.debug('DEBUG3')
|
||||||
|
|
||||||
if (!rawTrade.toAddress) {
|
if (!rawTrade.toAddress) {
|
||||||
var newRawTrade = _.cloneDeep(rawTrade)
|
var newRawTrade = _.cloneDeep(rawTrade)
|
||||||
newRawTrade.toAddress = 'remit'
|
newRawTrade.toAddress = 'remit'
|
||||||
return db.recordBill(session, newRawTrade, cb)
|
return db.recordBill(session, newRawTrade, cb)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.debug('DEBUG1')
|
||||||
|
|
||||||
async.parallel([
|
async.parallel([
|
||||||
async.apply(db.addOutgoingPending, session, rawTrade.currency, rawTrade.toAddress),
|
async.apply(db.addOutgoingPending, session, rawTrade.currency, rawTrade.cryptoCode, rawTrade.toAddress),
|
||||||
async.apply(db.recordBill, session, rawTrade)
|
async.apply(db.recordBill, session, rawTrade)
|
||||||
], cb)
|
], cb)
|
||||||
}
|
}
|
||||||
|
|
@ -376,17 +396,14 @@ exports.fiatBalance = function fiatBalance (cryptoCode) {
|
||||||
if (!rawRate || !lastBalance) return null
|
if (!rawRate || !lastBalance) return null
|
||||||
|
|
||||||
// The rate is actually our commission times real rate.
|
// The rate is actually our commission times real rate.
|
||||||
var rate = commission * rawRate
|
var rate = rawRate.times(commission)
|
||||||
|
|
||||||
// `lowBalanceMargin` is our safety net. It's a number > 1, and we divide
|
// `lowBalanceMargin` is our safety net. It's a number > 1, and we divide
|
||||||
// all our balances by it to provide a safety margin.
|
// all our balances by it to provide a safety margin.
|
||||||
var lowBalanceMargin = cachedConfig.exchanges.settings.lowBalanceMargin
|
var lowBalanceMargin = cachedConfig.exchanges.settings.lowBalanceMargin
|
||||||
|
|
||||||
// `balance.transferBalance` is the balance of our transfer account (the one
|
var unitScale = new BigNumber(10).pow(coins[cryptoCode].unitScale)
|
||||||
// we use to send Bitcoins to clients) in satoshis.
|
var fiatTransferBalance = lastBalance.div(unitScale).times(rate).div(lowBalanceMargin)
|
||||||
var transferBalance = lastBalance.transferBalance
|
|
||||||
|
|
||||||
var fiatTransferBalance = (transferBalance * rate) / lowBalanceMargin
|
|
||||||
|
|
||||||
return fiatTransferBalance
|
return fiatTransferBalance
|
||||||
}
|
}
|
||||||
|
|
@ -441,9 +458,9 @@ function pollBalance (cryptoCode, cb) {
|
||||||
return cb && cb(err)
|
return cb && cb(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug('[%s] Balance update:', cryptoCode, balance)
|
logger.debug('[%s] Balance update: %j', cryptoCode, balance)
|
||||||
balance.timestamp = Date.now()
|
balance.timestamp = Date.now()
|
||||||
lastBalances[cryptoCode] = balance
|
lastBalances[cryptoCode] = new BigNumber(balance[cryptoCode])
|
||||||
|
|
||||||
return cb && cb(null, lastBalances)
|
return cb && cb(null, lastBalances)
|
||||||
})
|
})
|
||||||
|
|
@ -472,7 +489,7 @@ function pollRate (cryptoCode, cb) {
|
||||||
rates.ask = rates.ask && new BigNumber(rates.ask)
|
rates.ask = rates.ask && new BigNumber(rates.ask)
|
||||||
rates.bid = rates.bid && new BigNumber(rates.bid)
|
rates.bid = rates.bid && new BigNumber(rates.bid)
|
||||||
}
|
}
|
||||||
logger.debug('got rates: %j', resRates)
|
logger.debug('[%s] got rates: %j', cryptoCode, resRates)
|
||||||
|
|
||||||
lastRates[cryptoCode] = resRates
|
lastRates[cryptoCode] = resRates
|
||||||
|
|
||||||
|
|
@ -495,9 +512,8 @@ exports.getDeviceRate = function getDeviceRate (cryptoCode) {
|
||||||
|
|
||||||
exports.getBalance = function getBalance (cryptoCode) {
|
exports.getBalance = function getBalance (cryptoCode) {
|
||||||
var lastBalance = lastBalances[cryptoCode]
|
var lastBalance = lastBalances[cryptoCode]
|
||||||
if (!lastBalance) return null
|
|
||||||
|
|
||||||
return lastBalance.transferBalance
|
return lastBalance
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -284,6 +284,7 @@ function insertTx(client, session, incoming, tx, satoshis, fiat, stage,
|
||||||
'to_address',
|
'to_address',
|
||||||
'satoshis',
|
'satoshis',
|
||||||
'currency_code',
|
'currency_code',
|
||||||
|
'crypto_code',
|
||||||
'fiat',
|
'fiat',
|
||||||
'tx_hash',
|
'tx_hash',
|
||||||
'error'
|
'error'
|
||||||
|
|
@ -298,6 +299,7 @@ function insertTx(client, session, incoming, tx, satoshis, fiat, stage,
|
||||||
tx.toAddress,
|
tx.toAddress,
|
||||||
satoshis,
|
satoshis,
|
||||||
tx.currencyCode,
|
tx.currencyCode,
|
||||||
|
tx.cryptoCode,
|
||||||
fiat,
|
fiat,
|
||||||
tx.txHash,
|
tx.txHash,
|
||||||
tx.error
|
tx.error
|
||||||
|
|
@ -322,13 +324,13 @@ function refreshPendingTx(client, session, cb) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function addPendingTx(client, session, incoming, currencyCode, toAddress,
|
function addPendingTx(client, session, incoming, currencyCode, cryptoCode, toAddress,
|
||||||
satoshis, cb) {
|
satoshis, cb) {
|
||||||
var fields = ['device_fingerprint', 'session_id', 'incoming',
|
var fields = ['device_fingerprint', 'session_id', 'incoming',
|
||||||
'currency_code', 'to_address', 'satoshis'];
|
'currency_code', 'crypto_code', 'to_address', 'satoshis'];
|
||||||
var sql = getInsertQuery('pending_transactions', fields, false);
|
var sql = getInsertQuery('pending_transactions', fields, false);
|
||||||
var values = [session.fingerprint, session.id, incoming, currencyCode,
|
var values = [session.fingerprint, session.id, incoming, currencyCode,
|
||||||
toAddress, satoshis];
|
cryptoCode, toAddress, satoshis];
|
||||||
query(client, sql, values, function(err) {
|
query(client, sql, values, function(err) {
|
||||||
cb(err);
|
cb(err);
|
||||||
});
|
});
|
||||||
|
|
@ -402,14 +404,14 @@ function ensureNotFinal(client, session, cb) {
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.addOutgoingPending = function addOutgoingPending(session, currencyCode,
|
exports.addOutgoingPending = function addOutgoingPending(session, currencyCode,
|
||||||
toAddress, cb) {
|
cryptoCode, toAddress, cb) {
|
||||||
connect(function(cerr, client, done) {
|
connect(function(cerr, client, done) {
|
||||||
if (cerr) return cb(cerr);
|
if (cerr) return cb(cerr);
|
||||||
|
|
||||||
async.series([
|
async.series([
|
||||||
async.apply(silentQuery, client, 'BEGIN', null),
|
async.apply(silentQuery, client, 'BEGIN', null),
|
||||||
async.apply(ensureNotFinal, client, session),
|
async.apply(ensureNotFinal, client, session),
|
||||||
async.apply(addPendingTx, client, session, false, currencyCode, toAddress,
|
async.apply(addPendingTx, client, session, false, currencyCode, cryptoCode, toAddress,
|
||||||
0)
|
0)
|
||||||
], function(err) {
|
], function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|
@ -442,7 +444,7 @@ exports.addInitialIncoming = function addInitialIncoming(session, tx, cb) {
|
||||||
async.series([
|
async.series([
|
||||||
async.apply(silentQuery, client, 'BEGIN', null),
|
async.apply(silentQuery, client, 'BEGIN', null),
|
||||||
async.apply(addPendingTx, client, session, true, tx.currencyCode,
|
async.apply(addPendingTx, client, session, true, tx.currencyCode,
|
||||||
tx.toAddress, tx.satoshis),
|
tx.cryptoCode, tx.toAddress, tx.satoshis),
|
||||||
async.apply(insertIncoming, client, session, tx, tx.satoshis, tx.fiat,
|
async.apply(insertIncoming, client, session, tx, tx.satoshis, tx.fiat,
|
||||||
'initial_request', 'pending')
|
'initial_request', 'pending')
|
||||||
], function(err) {
|
], function(err) {
|
||||||
|
|
|
||||||
|
|
@ -46,13 +46,13 @@ function buildRates () {
|
||||||
function buildBalances () {
|
function buildBalances () {
|
||||||
var cryptoCodes = plugins.getcryptoCodes()
|
var cryptoCodes = plugins.getcryptoCodes()
|
||||||
|
|
||||||
var balances = {}
|
var _balances = {}
|
||||||
cryptoCodes.forEach(function (cryptoCode) {
|
cryptoCodes.forEach(function (cryptoCode) {
|
||||||
var balance = plugins.fiatBalance(cryptoCode)
|
var balance = plugins.fiatBalance(cryptoCode)
|
||||||
balances[cryptoCode] = balance
|
_balances[cryptoCode] = balance
|
||||||
})
|
})
|
||||||
|
|
||||||
return balances
|
return _balances
|
||||||
}
|
}
|
||||||
|
|
||||||
function poll (req, res) {
|
function poll (req, res) {
|
||||||
|
|
@ -106,6 +106,7 @@ function trade (req, res) {
|
||||||
tx.cryptoAtoms = new BigNumber(tx.cryptoAtoms)
|
tx.cryptoAtoms = new BigNumber(tx.cryptoAtoms)
|
||||||
|
|
||||||
plugins.trade(session(req), tx, function (err) {
|
plugins.trade(session(req), tx, function (err) {
|
||||||
|
if (err) logger.error(err)
|
||||||
var statusCode = err ? 500 : 201
|
var statusCode = err ? 500 : 201
|
||||||
res.json(statusCode, {err: err})
|
res.json(statusCode, {err: err})
|
||||||
})
|
})
|
||||||
|
|
@ -235,7 +236,6 @@ function init (localConfig) {
|
||||||
})
|
})
|
||||||
|
|
||||||
localApp.post('/reboot', function (req, res) {
|
localApp.post('/reboot', function (req, res) {
|
||||||
console.log('DEBUG1')
|
|
||||||
var pid = req.body.pid
|
var pid = req.body.pid
|
||||||
var fingerprint = req.body.fingerprint
|
var fingerprint = req.body.fingerprint
|
||||||
console.log('pid: %s, fingerprint: %s', pid, fingerprint)
|
console.log('pid: %s, fingerprint: %s', pid, fingerprint)
|
||||||
|
|
|
||||||
27
todo.txt
27
todo.txt
|
|
@ -7,3 +7,30 @@ backwards compatibility:
|
||||||
|
|
||||||
- clean up db stuff satoshis/cryptoAtoms
|
- clean up db stuff satoshis/cryptoAtoms
|
||||||
- clean up other stuff
|
- clean up other stuff
|
||||||
|
|
||||||
|
- add 'ETH' to config in ssu crypto: config.exchanges.settings.coins
|
||||||
|
|
||||||
|
[2016-04-06T19:58:17.827Z] ERROR: lamassu-server/39374 on MacBook-Pro: null value in column "satoshis" violates not-null constraint
|
||||||
|
error: null value in column "satoshis" violates not-null constraint
|
||||||
|
at Connection.parseE (/Users/josh/projects/lamassu-server/node_modules/pg/lib/connection.js:539:11)
|
||||||
|
at Connection.parseMessage (/Users/josh/projects/lamassu-server/node_modules/pg/lib/connection.js:366:17)
|
||||||
|
at Socket.<anonymous> (/Users/josh/projects/lamassu-server/node_modules/pg/lib/connection.js:105:22)
|
||||||
|
at Socket.emit (events.js:95:17)
|
||||||
|
at Socket.<anonymous> (_stream_readable.js:765:14)
|
||||||
|
at Socket.emit (events.js:92:17)
|
||||||
|
at emitReadable_ (_stream_readable.js:427:10)
|
||||||
|
at emitReadable (_stream_readable.js:423:5)
|
||||||
|
at readableAddChunk (_stream_readable.js:166:9)
|
||||||
|
at Socket.Readable.push (_stream_readable.js:128:10)
|
||||||
|
|
||||||
|
alter table transactions alter satoshis TYPE bigint;
|
||||||
|
alter table transactions add crypto_code text default 'BTC';
|
||||||
|
alter table pending_transactions add crypto_code text default 'BTC';
|
||||||
|
alter table pending_transactions alter satoshis TYPE bigint;
|
||||||
|
alter table bills add crypto_code text default 'BTC';
|
||||||
|
alter table bills alter satoshis TYPE bigint;
|
||||||
|
|
||||||
|
- get cryptoCode from pending tx
|
||||||
|
- update cryptoCode for bills insert
|
||||||
|
- insert correct satoshis in pending tx -- actually this is supposed to be 0
|
||||||
|
- fix satoshi math in postgres module by moving to bignumber math
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue