WIP
This commit is contained in:
parent
0a8021691a
commit
3d9814398d
4 changed files with 683 additions and 253 deletions
|
|
@ -71,7 +71,7 @@ function loadPlugin (name, config) {
|
||||||
const moduleMethods = {
|
const moduleMethods = {
|
||||||
ticker: ['ticker'],
|
ticker: ['ticker'],
|
||||||
trader: ['purchase', 'sell'],
|
trader: ['purchase', 'sell'],
|
||||||
wallet: ['balance', 'sendBitcoins', 'newAddress'],
|
wallet: ['balance', 'sendCoins', 'newAddress'],
|
||||||
idVerifier: ['verifyUser', 'verifyTransaction'],
|
idVerifier: ['verifyUser', 'verifyTransaction'],
|
||||||
info: ['checkAddress'],
|
info: ['checkAddress'],
|
||||||
email: ['sendMessage']
|
email: ['sendMessage']
|
||||||
|
|
@ -290,19 +290,8 @@ exports.pollQueries = function pollQueries (deviceId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function _sendCoins (toAddress, cryptoAtoms, cryptoCode) {
|
function _sendCoins (toAddress, cryptoAtoms, cryptoCode) {
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
_sendCoinsCb(toAddress, cryptoAtoms, cryptoCode, (err, txHash) => {
|
|
||||||
if (err) return reject(err)
|
|
||||||
return resolve(txHash)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function _sendCoinsCb (toAddress, cryptoAtoms, cryptoCode, cb) {
|
|
||||||
const walletPlugin = walletPlugins[cryptoCode]
|
const walletPlugin = walletPlugins[cryptoCode]
|
||||||
const transactionFee = null
|
return walletPlugin.sendCoins(toAddress, cryptoAtoms.toNumber(), cryptoCode)
|
||||||
|
|
||||||
walletPlugin.sendBitcoins(toAddress, cryptoAtoms, cryptoCode, transactionFee, cb)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: This will fail if we have already sent coins because there will be
|
// NOTE: This will fail if we have already sent coins because there will be
|
||||||
|
|
@ -379,21 +368,21 @@ exports.cashOut = function cashOut (deviceId, tx) {
|
||||||
: Promise.resolve()
|
: Promise.resolve()
|
||||||
|
|
||||||
return serialPromise
|
return serialPromise
|
||||||
.then(serialNumber => new Promise((resolve, reject) => {
|
.then(serialNumber => {
|
||||||
const tmpInfo = {
|
const tmpInfo = {
|
||||||
label: 'TX ' + Date.now(),
|
label: 'TX ' + Date.now(),
|
||||||
account: 'deposit',
|
account: 'deposit',
|
||||||
serialNumber
|
serialNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
walletPlugin.newAddress(tmpInfo, (err, address) => {
|
return walletPlugin.newAddress(tmpInfo)
|
||||||
if (err) return reject(err)
|
.then(address => {
|
||||||
|
|
||||||
const newTx = R.assoc('toAddress', address, tx)
|
const newTx = R.assoc('toAddress', address, tx)
|
||||||
|
|
||||||
return db.addInitialIncoming(deviceId, newTx, address)
|
return db.addInitialIncoming(deviceId, newTx, address)
|
||||||
.then(() => resolve(address))
|
.then(() => address)
|
||||||
})
|
})
|
||||||
}))
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.dispenseAck = function (deviceId, tx) {
|
exports.dispenseAck = function (deviceId, tx) {
|
||||||
|
|
@ -531,24 +520,24 @@ function stopTrader (cryptoCode) {
|
||||||
tradesQueues[cryptoCode] = []
|
tradesQueues[cryptoCode] = []
|
||||||
}
|
}
|
||||||
|
|
||||||
function pollBalance (cryptoCode, cb) {
|
function pollBalance (cryptoCode) {
|
||||||
logger.debug('[%s] collecting balance', cryptoCode)
|
logger.debug('[%s] collecting balance', cryptoCode)
|
||||||
|
|
||||||
const walletPlugin = walletPlugins[cryptoCode]
|
const walletPlugin = walletPlugins[cryptoCode]
|
||||||
|
|
||||||
walletPlugin.balance((err, balance) => {
|
return walletPlugin.balance()
|
||||||
if (err) {
|
.then(balance => {
|
||||||
logger.error('[%s] Error loading balance: %s', cryptoCode, err.message)
|
|
||||||
return cb && cb(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
const unitScale = new BigNumber(10).pow(coins[cryptoCode].unitScale)
|
const unitScale = new BigNumber(10).pow(coins[cryptoCode].unitScale)
|
||||||
const coinBalance = new BigNumber(balance[cryptoCode])
|
const coinBalance = new BigNumber(balance[cryptoCode])
|
||||||
const scaledCoinBalance = coinBalance.div(unitScale)
|
const scaledCoinBalance = coinBalance.div(unitScale)
|
||||||
logger.debug('[%s] Balance update: %s', cryptoCode, scaledCoinBalance.toString())
|
logger.debug('[%s] Balance update: %s', cryptoCode, scaledCoinBalance.toString())
|
||||||
lastBalances[cryptoCode] = {timestamp: Date.now(), balance: coinBalance}
|
lastBalances[cryptoCode] = {timestamp: Date.now(), balance: coinBalance}
|
||||||
|
|
||||||
return cb && cb(null, lastBalances)
|
return lastBalances
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
logger.error('[%s] Error loading balance: %s', cryptoCode, err.message)
|
||||||
|
return lastBalances
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,7 @@ const pairing = require('./pairing')
|
||||||
let plugins
|
let plugins
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
init,
|
init
|
||||||
getDeviceId
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const STALE_TICKER = 3 * 60 * 1000
|
const STALE_TICKER = 3 * 60 * 1000
|
||||||
|
|
@ -62,8 +61,8 @@ function buildBalances (deviceId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function poll (req, res) {
|
function poll (req, res) {
|
||||||
const deviceId = getDeviceId(req)
|
const deviceId = req.deviceId
|
||||||
const deviceTime = getDeviceTime(req)
|
const deviceTime = req.deviceTime
|
||||||
const pid = req.query.pid
|
const pid = req.query.pid
|
||||||
|
|
||||||
pids[deviceId] = {pid, ts: Date.now()}
|
pids[deviceId] = {pid, ts: Date.now()}
|
||||||
|
|
@ -123,24 +122,25 @@ function trade (req, res, next) {
|
||||||
const tx = req.body
|
const tx = req.body
|
||||||
tx.cryptoAtoms = new BigNumber(tx.cryptoAtoms)
|
tx.cryptoAtoms = new BigNumber(tx.cryptoAtoms)
|
||||||
|
|
||||||
plugins.trade(getDeviceId(req), tx)
|
plugins.trade(req.deviceId, tx)
|
||||||
.then(() => cacheAndRespond(req, res))
|
.then(() => cacheAndRespond(req, res))
|
||||||
}
|
}
|
||||||
|
|
||||||
function stateChange (req, res) {
|
function stateChange (req, res) {
|
||||||
plugins.stateChange(getDeviceId(req), getDeviceTime(req), req.body)
|
plugins.stateChange(req.deviceId, req.deviceTime, req.body)
|
||||||
.then(() => cacheAndRespond(req, res))
|
.then(() => cacheAndRespond(req, res))
|
||||||
}
|
}
|
||||||
|
|
||||||
function send (req, res) {
|
function send (req, res, next) {
|
||||||
const tx = req.body
|
const tx = req.body
|
||||||
tx.cryptoAtoms = new BigNumber(tx.cryptoAtoms)
|
tx.cryptoAtoms = new BigNumber(tx.cryptoAtoms)
|
||||||
|
|
||||||
return plugins.sendCoins(getDeviceId(req), tx)
|
return plugins.sendCoins(req.deviceId, tx)
|
||||||
.then(status => {
|
.then(status => {
|
||||||
const body = {txId: status && status.txId}
|
const body = {txId: status && status.txId}
|
||||||
return cacheAndRespond(req, res, body)
|
return cacheAndRespond(req, res, body)
|
||||||
})
|
})
|
||||||
|
.catch(next)
|
||||||
}
|
}
|
||||||
|
|
||||||
function cashOut (req, res) {
|
function cashOut (req, res) {
|
||||||
|
|
@ -148,17 +148,17 @@ function cashOut (req, res) {
|
||||||
const tx = req.body
|
const tx = req.body
|
||||||
tx.cryptoAtoms = new BigNumber(tx.cryptoAtoms)
|
tx.cryptoAtoms = new BigNumber(tx.cryptoAtoms)
|
||||||
|
|
||||||
return plugins.cashOut(getDeviceId(req), tx)
|
return plugins.cashOut(req.deviceId, tx)
|
||||||
.then(cryptoAddress => cacheAndRespond(req, res, {toAddress: cryptoAddress}))
|
.then(cryptoAddress => cacheAndRespond(req, res, {toAddress: cryptoAddress}))
|
||||||
}
|
}
|
||||||
|
|
||||||
function dispenseAck (req, res) {
|
function dispenseAck (req, res) {
|
||||||
plugins.dispenseAck(getDeviceId(req), req.body.tx)
|
plugins.dispenseAck(req.deviceId, req.body.tx)
|
||||||
.then(() => cacheAndRespond(req, res))
|
.then(() => cacheAndRespond(req, res))
|
||||||
}
|
}
|
||||||
|
|
||||||
function deviceEvent (req, res) {
|
function deviceEvent (req, res) {
|
||||||
plugins.logEvent(getDeviceId(req), req.body)
|
plugins.logEvent(req.deviceId, req.body)
|
||||||
.then(() => cacheAndRespond(req, res))
|
.then(() => cacheAndRespond(req, res))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -182,7 +182,7 @@ function ca (req, res) {
|
||||||
|
|
||||||
function pair (req, res, next) {
|
function pair (req, res, next) {
|
||||||
const token = req.query.token
|
const token = req.query.token
|
||||||
const deviceId = getDeviceId(req)
|
const deviceId = req.deviceId
|
||||||
|
|
||||||
return pairing.pair(token, deviceId)
|
return pairing.pair(token, deviceId)
|
||||||
.then(valid => {
|
.then(valid => {
|
||||||
|
|
@ -255,7 +255,7 @@ function cacheAction (req, res, next) {
|
||||||
const sql = `insert into idempotents (request_id, device_id, body, status, pending)
|
const sql = `insert into idempotents (request_id, device_id, body, status, pending)
|
||||||
values ($1, $2, $3, $4, $5)`
|
values ($1, $2, $3, $4, $5)`
|
||||||
|
|
||||||
const deviceId = getDeviceId(req)
|
const deviceId = req.deviceId
|
||||||
|
|
||||||
db.none(sql, [requestId, deviceId, {}, 204, true])
|
db.none(sql, [requestId, deviceId, {}, 204, true])
|
||||||
.then(() => next())
|
.then(() => next())
|
||||||
|
|
@ -278,7 +278,7 @@ function updateCachedAction (req, body, status) {
|
||||||
const sql = `update idempotents set body=$1, status=$2, pending=$3
|
const sql = `update idempotents set body=$1, status=$2, pending=$3
|
||||||
where request_id=$4 and device_id=$5 and pending=$6`
|
where request_id=$4 and device_id=$5 and pending=$6`
|
||||||
|
|
||||||
const deviceId = getDeviceId(req)
|
const deviceId = req.deviceId
|
||||||
|
|
||||||
return db.none(sql, [body, status, false, requestId, deviceId, true])
|
return db.none(sql, [body, status, false, requestId, deviceId, true])
|
||||||
}
|
}
|
||||||
|
|
@ -316,7 +316,7 @@ function httpError (msg, code) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterOldRequests (req, res, next) {
|
function filterOldRequests (req, res, next) {
|
||||||
const deviceTime = getDeviceTime(req)
|
const deviceTime = req.deviceTime
|
||||||
const delta = Date.now() - deviceTime
|
const delta = Date.now() - deviceTime
|
||||||
|
|
||||||
if (delta > CLOCK_SKEW) {
|
if (delta > CLOCK_SKEW) {
|
||||||
|
|
@ -328,7 +328,7 @@ function filterOldRequests (req, res, next) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function authorize (req, res, next) {
|
function authorize (req, res, next) {
|
||||||
const deviceId = req.connection.getPeerCertificate().fingerprint
|
const deviceId = req.deviceId
|
||||||
|
|
||||||
return pairing.isPaired(deviceId)
|
return pairing.isPaired(deviceId)
|
||||||
.then(r => {
|
.then(r => {
|
||||||
|
|
@ -354,6 +354,7 @@ function init (opts) {
|
||||||
|
|
||||||
app.use(morgan('dev'))
|
app.use(morgan('dev'))
|
||||||
app.use(helmet())
|
app.use(helmet())
|
||||||
|
app.use(populateDeviceId)
|
||||||
app.use(bodyParser.json())
|
app.use(bodyParser.json())
|
||||||
app.use(filterOldRequests)
|
app.use(filterOldRequests)
|
||||||
app.post('*', cacheAction)
|
app.post('*', cacheAction)
|
||||||
|
|
@ -414,12 +415,12 @@ function init (opts) {
|
||||||
return app
|
return app
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDeviceTime (req) {
|
function populateDeviceId (req, res, next) {
|
||||||
return Date.parse(req.get('date'))
|
const deviceId = ((typeof req.connection.getPeerCertificate === 'function' &&
|
||||||
}
|
req.connection.getPeerCertificate().fingerprint)) || null
|
||||||
|
|
||||||
function getDeviceId (req) {
|
req.deviceId = deviceId
|
||||||
return (typeof req.connection.getPeerCertificate === 'function' &&
|
req.deviceTime = Date.parse(req.get('date'))
|
||||||
req.connection.getPeerCertificate().fingerprint) || 'unknown'
|
|
||||||
}
|
|
||||||
|
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
|
|
||||||
11
package.json
11
package.json
|
|
@ -13,19 +13,14 @@
|
||||||
"express": "^4.13.4",
|
"express": "^4.13.4",
|
||||||
"express-limiter": "^1.6.0",
|
"express-limiter": "^1.6.0",
|
||||||
"helmet": "^3.1.0",
|
"helmet": "^3.1.0",
|
||||||
"lamassu-bitcoind": "lamassu/lamassu-bitcoind",
|
"lamassu-bitcoind": "lamassu/lamassu-bitcoind#alpha",
|
||||||
|
"lamassu-bitgo": "lamassu/lamassu-bitgo#alpha",
|
||||||
"lamassu-bitpay": "~1.0.0",
|
"lamassu-bitpay": "~1.0.0",
|
||||||
"lamassu-bitstamp": "^1.0.4",
|
|
||||||
"lamassu-blockcypher": "~0.1.0",
|
|
||||||
"lamassu-coinbase": "^1.0.5",
|
|
||||||
"lamassu-coindesk": "^1.0.4",
|
"lamassu-coindesk": "^1.0.4",
|
||||||
"lamassu-config": "lamassu/lamassu-config#alpha",
|
"lamassu-mailjet": "^1.0.0",
|
||||||
"lamassu-identitymind": "^1.2.9",
|
|
||||||
"lamassu-kraken": "^1.0.3",
|
|
||||||
"lamassu-mock-id-verify": "^1.0.1",
|
"lamassu-mock-id-verify": "^1.0.1",
|
||||||
"lamassu-mock-sms": "^1.0.1",
|
"lamassu-mock-sms": "^1.0.1",
|
||||||
"lamassu-mock-wallet": "^1.0.3",
|
"lamassu-mock-wallet": "^1.0.3",
|
||||||
"lamassu-smtp2go": "^1.0.3",
|
|
||||||
"lamassu-twilio": "^1.1.1",
|
"lamassu-twilio": "^1.1.1",
|
||||||
"migrate": "^0.2.2",
|
"migrate": "^0.2.2",
|
||||||
"minimist": "^1.2.0",
|
"minimist": "^1.2.0",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue