WIP -- refactoring
This commit is contained in:
parent
8d44c1d383
commit
f55e9355ef
3 changed files with 84 additions and 82 deletions
141
lib/plugins.js
141
lib/plugins.js
|
|
@ -11,18 +11,10 @@ var argv = require('minimist')(process.argv.slice(2))
|
|||
|
||||
var tradeInterval = null
|
||||
|
||||
var SATOSHI_FACTOR = 1e8
|
||||
var POLLING_RATE = 60 * 1000 // poll each minute
|
||||
var REAP_RATE = 2 * 1000
|
||||
var PENDING_TIMEOUT = 70 * 1000
|
||||
|
||||
var BTC_COIN = {
|
||||
unitCode: 'BTC',
|
||||
displayCode: 'mBTC',
|
||||
unitScale: 8,
|
||||
displayScale: 5
|
||||
}
|
||||
|
||||
if (argv.timeout) PENDING_TIMEOUT = argv.timeout / 1000
|
||||
|
||||
// TODO: might have to update this if user is allowed to extend monitoring time
|
||||
|
|
@ -30,10 +22,10 @@ var DEPOSIT_TIMEOUT = 130 * 1000
|
|||
|
||||
var db = null
|
||||
|
||||
var cryptoCoins = null
|
||||
var cryptoCodes = null
|
||||
|
||||
var tickerPlugins = {}
|
||||
var traderPlugin = null
|
||||
var traderPlugins = {}
|
||||
var walletPlugins = {}
|
||||
var idVerifierPlugin = null
|
||||
var infoPlugin = null
|
||||
|
|
@ -46,7 +38,7 @@ var deviceCurrency = 'USD'
|
|||
var lastBalances = {}
|
||||
var lastRates = {}
|
||||
|
||||
var tradesQueue = []
|
||||
var tradesQueues = {}
|
||||
|
||||
// that's basically a constructor
|
||||
exports.init = function init (databaseHandle) {
|
||||
|
|
@ -119,9 +111,9 @@ function loadPlugin (name, config) {
|
|||
return plugin
|
||||
}
|
||||
|
||||
function loadOrConfigPlugin (pluginHandle, pluginType, cryptoCoin, currency,
|
||||
function loadOrConfigPlugin (pluginHandle, pluginType, cryptoCode, currency,
|
||||
onChangeCallback) {
|
||||
var cryptoCode = cryptoCoin ? cryptoCoin.unitCode : 'any'
|
||||
cryptoCode = cryptoCode || 'BTC'
|
||||
|
||||
var currentName = cryptoCode === 'any' || cryptoCode === 'BTC'
|
||||
? cachedConfig.exchanges.plugins.current[pluginType]
|
||||
|
|
@ -157,19 +149,18 @@ exports.configure = function configure (config) {
|
|||
|
||||
cachedConfig = config
|
||||
deviceCurrency = config.exchanges.settings.currency
|
||||
cryptoCoins = config.exchanges.settings.coins || [BTC_COIN]
|
||||
cryptoCodes = config.exchanges.settings.coins || 'BTC'
|
||||
|
||||
cryptoCoins.forEach(function (cryptoCoin) {
|
||||
cryptoCodes.forEach(function (cryptoCode) {
|
||||
// TICKER [required] configure (or load)
|
||||
var cryptoCode = cryptoCoin.unitCode
|
||||
loadOrConfigPlugin(
|
||||
tickerPlugins[cryptoCode],
|
||||
'ticker',
|
||||
cryptoCoin,
|
||||
cryptoCode,
|
||||
deviceCurrency, // device currency
|
||||
function onTickerChange (newTicker) {
|
||||
tickerPlugins[cryptoCode] = newTicker
|
||||
pollRate(cryptoCoin)
|
||||
pollRate(cryptoCode)
|
||||
}
|
||||
)
|
||||
|
||||
|
|
@ -177,28 +168,29 @@ exports.configure = function configure (config) {
|
|||
loadOrConfigPlugin(
|
||||
walletPlugins[cryptoCode],
|
||||
'transfer',
|
||||
cryptoCoin,
|
||||
cryptoCode,
|
||||
null,
|
||||
function onWalletChange (newWallet) {
|
||||
walletPlugins[cryptoCode] = newWallet
|
||||
pollBalance(cryptoCoin)
|
||||
pollBalance(cryptoCode)
|
||||
}
|
||||
)
|
||||
|
||||
tradesQueues[cryptoCode] = []
|
||||
|
||||
loadOrConfigPlugin(
|
||||
traderPlugins[cryptoCode],
|
||||
'trade',
|
||||
cryptoCode,
|
||||
null,
|
||||
function onTraderChange (newTrader) {
|
||||
traderPlugins[cryptoCode] = newTrader
|
||||
if (newTrader === null) stopTrader(cryptoCode)
|
||||
else startTrader(cryptoCode)
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
// TRADER [optional] configure (or load)
|
||||
traderPlugin = loadOrConfigPlugin(
|
||||
traderPlugin,
|
||||
'trade',
|
||||
null,
|
||||
null,
|
||||
function onTraderChange (newTrader) {
|
||||
traderPlugin = newTrader
|
||||
if (newTrader === null) stopTrader()
|
||||
else startTrader()
|
||||
}
|
||||
)
|
||||
|
||||
// ID VERIFIER [optional] configure (or load)
|
||||
idVerifierPlugin = loadOrConfigPlugin(
|
||||
idVerifierPlugin,
|
||||
|
|
@ -248,14 +240,13 @@ exports.pollQueries = function pollQueries (session, cb) {
|
|||
})
|
||||
}
|
||||
|
||||
function _sendCoins (toAddress, cryptoAtoms, cryptoCoin, cb) {
|
||||
var cryptoCode = cryptoCoin.unitCode
|
||||
function _sendCoins (toAddress, cryptoAtoms, cryptoCode, cb) {
|
||||
var walletPlugin = walletPlugins[cryptoCode]
|
||||
var transactionFee = cachedConfig.exchanges.settings.transactionFee
|
||||
if (cryptoCode === 'BTC') {
|
||||
walletPlugin.sendBitcoins(toAddress, cryptoAtoms, transactionFee, cb)
|
||||
} else {
|
||||
walletPlugin.sendCoins(toAddress, cryptoAtoms, cryptoCoin, transactionFee, cb)
|
||||
walletPlugin.sendCoins(toAddress, cryptoAtoms, cryptoCode, transactionFee, cb)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -323,10 +314,15 @@ function reapTxs () {
|
|||
exports.trade = function trade (session, rawTrade, cb) {
|
||||
// TODO: move this to DB, too
|
||||
// add bill to trader queue (if trader is enabled)
|
||||
var cryptoCode = rawTrade.cryptoCode || 'BTC'
|
||||
var traderPlugin = traderPlugins[cryptoCode]
|
||||
var tradesQueue = tradesQueues[cryptoCode]
|
||||
|
||||
if (traderPlugin) {
|
||||
tradesQueue.push({
|
||||
currency: rawTrade.currency,
|
||||
satoshis: rawTrade.satoshis
|
||||
cryptoAtoms: rawTrade.cryptoAtoms,
|
||||
cryptoCode: rawTrade.cryptoCode
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -360,9 +356,7 @@ exports.cashOut = function cashOut (session, tx, cb) {
|
|||
account: 'deposit'
|
||||
}
|
||||
|
||||
var cryptoCoin = tx.coin || BTC_COIN
|
||||
var cryptoCode = cryptoCoin.unitCode
|
||||
|
||||
var cryptoCode = tx.cryptoCode || 'BTC'
|
||||
var walletPlugin = walletPlugins[cryptoCode]
|
||||
|
||||
walletPlugin.newAddress(tmpInfo, function (err, address) {
|
||||
|
|
@ -380,9 +374,8 @@ exports.dispenseAck = function dispenseAck (session, rec) {
|
|||
db.addDispense(session, rec.tx, rec.cartridges)
|
||||
}
|
||||
|
||||
exports.fiatBalance = function fiatBalance (cryptoCoin) {
|
||||
var cryptoCode = cryptoCoin.unitCode
|
||||
var rawRate = exports.getDeviceRate(cryptoCoin).rates.ask
|
||||
exports.fiatBalance = function fiatBalance (cryptoCode) {
|
||||
var rawRate = exports.getDeviceRate(cryptoCode).rates.ask
|
||||
var commission = cachedConfig.exchanges.settings.commission
|
||||
var lastBalance = lastBalances[cryptoCode]
|
||||
|
||||
|
|
@ -410,9 +403,9 @@ exports.fiatBalance = function fiatBalance (cryptoCoin) {
|
|||
exports.startPolling = function startPolling () {
|
||||
executeTrades()
|
||||
|
||||
cryptoCoins.forEach(function (coin) {
|
||||
setInterval(async.apply(pollBalance, coin), POLLING_RATE)
|
||||
setInterval(async.apply(pollRate, coin), POLLING_RATE)
|
||||
cryptoCodes.forEach(function (cryptoCode) {
|
||||
setInterval(async.apply(pollBalance, cryptoCode), POLLING_RATE)
|
||||
setInterval(async.apply(pollRate, cryptoCode), POLLING_RATE)
|
||||
})
|
||||
|
||||
setInterval(reapTxs, REAP_RATE)
|
||||
|
|
@ -420,29 +413,30 @@ exports.startPolling = function startPolling () {
|
|||
startTrader()
|
||||
}
|
||||
|
||||
function startTrader () {
|
||||
function startTrader (cryptoCode) {
|
||||
// Always start trading, even if we don't have a trade exchange configured,
|
||||
// since configuration can always change in `Trader#configure`.
|
||||
// `Trader#executeTrades` returns early if we don't have a trade exchange
|
||||
// configured at the moment.
|
||||
var traderPlugin = traderPlugins[cryptoCode]
|
||||
|
||||
if (traderPlugin && !tradeInterval) {
|
||||
tradeInterval = setInterval(
|
||||
executeTrades,
|
||||
function () { executeTrades(cryptoCode) },
|
||||
cachedConfig.exchanges.settings.tradeInterval
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function stopTrader () {
|
||||
function stopTrader (cryptoCode) {
|
||||
if (tradeInterval) {
|
||||
clearInterval(tradeInterval)
|
||||
tradeInterval = null
|
||||
tradesQueue = []
|
||||
tradesQueues[cryptoCode] = []
|
||||
}
|
||||
}
|
||||
|
||||
function pollBalance (cryptoCoin, cb) {
|
||||
var cryptoCode = cryptoCoin.unitCode
|
||||
function pollBalance (cryptoCode, cb) {
|
||||
logger.debug('[%s] collecting balance', cryptoCode)
|
||||
|
||||
var walletPlugin = walletPlugins[cryptoCode]
|
||||
|
|
@ -461,8 +455,7 @@ function pollBalance (cryptoCoin, cb) {
|
|||
})
|
||||
}
|
||||
|
||||
function pollRate (cryptoCoin, cb) {
|
||||
var cryptoCode = cryptoCoin.unitCode
|
||||
function pollRate (cryptoCode, cb) {
|
||||
logger.debug('[%s] polling for rates (%s)', cryptoCode, tickerPlugin.NAME)
|
||||
var tickerPlugin = tickerPlugins[cryptoCode]
|
||||
|
||||
|
|
@ -471,7 +464,7 @@ function pollRate (cryptoCoin, cb) {
|
|||
|
||||
var tickerF = cryptoCode === 'BTC'
|
||||
? async.apply(tickerPlugin.ticker, currencies)
|
||||
: async.apply(tickerPlugin.ticker, currencies, cryptoCoin)
|
||||
: async.apply(tickerPlugin.ticker, currencies, cryptoCode)
|
||||
|
||||
tickerF(function (err, resRates) {
|
||||
if (err) {
|
||||
|
|
@ -491,8 +484,7 @@ function pollRate (cryptoCoin, cb) {
|
|||
* Getters | Helpers
|
||||
*/
|
||||
|
||||
exports.getDeviceRate = function getDeviceRate (cryptoCoin) {
|
||||
var cryptoCode = cryptoCoin.unitCode
|
||||
exports.getDeviceRate = function getDeviceRate (cryptoCode) {
|
||||
if (!lastRates[cryptoCode]) return null
|
||||
|
||||
var lastRate = lastRates[cryptoCode]
|
||||
|
|
@ -501,8 +493,7 @@ exports.getDeviceRate = function getDeviceRate (cryptoCoin) {
|
|||
return lastRate[deviceCurrency]
|
||||
}
|
||||
|
||||
exports.getBalance = function getBalance (cryptoCoin) {
|
||||
var cryptoCode = cryptoCoin.unitCode
|
||||
exports.getBalance = function getBalance (cryptoCode) {
|
||||
var lastBalance = lastBalances[cryptoCode]
|
||||
if (!lastBalance) return null
|
||||
|
||||
|
|
@ -513,44 +504,50 @@ exports.getBalance = function getBalance (cryptoCoin) {
|
|||
* Trader functions
|
||||
*/
|
||||
function purchase (trade, cb) {
|
||||
var cryptoCode = trade.cryptoCode
|
||||
var traderPlugin = traderPlugins[cryptoCode]
|
||||
traderPlugin.purchase(trade.satoshis, null, function (err) {
|
||||
if (err) return cb(err)
|
||||
pollBalance('BTC')
|
||||
pollBalance(cryptoCode)
|
||||
if (typeof cb === 'function') cb()
|
||||
})
|
||||
}
|
||||
|
||||
function consolidateTrades () {
|
||||
function consolidateTrades (cryptoCode) {
|
||||
// NOTE: value in satoshis stays the same no matter the currency
|
||||
var cryptoAtoms = tradesQueues[cryptoCode].reduce(function (prev, current) {
|
||||
return current.cryptoAtoms.plus(prev)
|
||||
}, new BigNumber(0))
|
||||
|
||||
var consolidatedTrade = {
|
||||
currency: deviceCurrency,
|
||||
satoshis: tradesQueue.reduce(function (prev, current) {
|
||||
return prev + current.satoshis
|
||||
}, 0)
|
||||
cryptoAtoms: cryptoAtoms,
|
||||
cryptoCode: cryptoCode
|
||||
}
|
||||
|
||||
tradesQueue = []
|
||||
tradesQueues[cryptoCode] = []
|
||||
|
||||
logger.debug('consolidated: ', JSON.stringify(consolidatedTrade))
|
||||
return consolidatedTrade
|
||||
}
|
||||
|
||||
function executeTrades () {
|
||||
function executeTrades (cryptoCode) {
|
||||
var traderPlugin = traderPlugins[cryptoCode]
|
||||
if (!traderPlugin) return
|
||||
|
||||
logger.debug('checking for trades')
|
||||
|
||||
var trade = consolidateTrades()
|
||||
var trade = consolidateTrades(cryptoCode)
|
||||
|
||||
if (trade.satoshis === 0) {
|
||||
if (trade.cryptoAtoms.eq(0)) {
|
||||
logger.debug('rejecting 0 trade')
|
||||
return
|
||||
}
|
||||
|
||||
logger.debug('making a trade: %d', trade.satoshis / SATOSHI_FACTOR)
|
||||
logger.debug('making a trade: %d', trade.cryptoAtoms.toString())
|
||||
purchase(trade, function (err) {
|
||||
if (err) {
|
||||
tradesQueue.push(trade)
|
||||
tradesQueues[cryptoCode].push(trade)
|
||||
if (err.name !== 'orderTooSmall') logger.error(err)
|
||||
}
|
||||
})
|
||||
|
|
@ -567,6 +564,6 @@ exports.verifyTx = function verifyTx (data, cb) {
|
|||
idVerifierPlugin.verifyTransaction(data, cb)
|
||||
}
|
||||
|
||||
exports.getCryptoCoins = function getCryptoCoins () {
|
||||
return cryptoCoins
|
||||
exports.getcryptoCodes = function getcryptoCodes () {
|
||||
return cryptoCodes
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ var pids = {}
|
|||
var reboots = {}
|
||||
|
||||
function buildRates () {
|
||||
var cryptoCoins = plugins.getCryptoCoins()
|
||||
var cryptoCodes = plugins.getcryptoCodes()
|
||||
var config = plugins.getConfig()
|
||||
var settings = config.exchanges.settings
|
||||
|
||||
|
|
@ -31,9 +31,8 @@ function buildRates () {
|
|||
var cashOutCommission = settings.fiatCommission || cashInCommission
|
||||
|
||||
var rates = {}
|
||||
cryptoCoins.forEach(function (coin) {
|
||||
var cryptoCode = coin.unitCode
|
||||
var rate = plugins.getDeviceRate(coin).rates
|
||||
cryptoCodes.forEach(function (cryptoCode) {
|
||||
var rate = plugins.getDeviceRate(cryptoCode).rates
|
||||
rates[cryptoCode] = {
|
||||
cashIn: rate.ask.times(cashInCommission),
|
||||
cashOut: rate.bid.div(cashOutCommission)
|
||||
|
|
@ -44,12 +43,12 @@ function buildRates () {
|
|||
}
|
||||
|
||||
function buildBalances () {
|
||||
var cryptoCoins = plugins.getCryptoCoins()
|
||||
var cryptoCodes = plugins.getcryptoCodes()
|
||||
|
||||
var balances = {}
|
||||
cryptoCoins.forEach(function (coin) {
|
||||
var balance = plugins.fiatBalance(coin)
|
||||
balances[coin] = balance
|
||||
cryptoCodes.forEach(function (cryptoCode) {
|
||||
var balance = plugins.fiatBalance(cryptoCode)
|
||||
balances[cryptoCode] = balance
|
||||
})
|
||||
|
||||
return balances
|
||||
|
|
|
|||
10
todo.txt
10
todo.txt
|
|
@ -1,5 +1,11 @@
|
|||
- rethink scale names: is unit satoshi or btc? cryptoAtom, cryptoAtom
|
||||
- cryptoCoin is record, not code
|
||||
- specify crypto and fiat for trades
|
||||
- make sure ticker is in full coins
|
||||
- getDeviceRate should return bignumber
|
||||
- test with l-m
|
||||
|
||||
backwards compatibility:
|
||||
|
||||
- new l-m must be backwards compatible with old l-s
|
||||
|
||||
- parse out bignumber when loading in routes
|
||||
- making a trade -- convert to units
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue