WIP
This commit is contained in:
parent
35cbb46688
commit
0140e01c9f
5 changed files with 38 additions and 39 deletions
|
|
@ -3,6 +3,7 @@
|
||||||
var fs = require('fs')
|
var fs = require('fs')
|
||||||
var R = require('ramda')
|
var R = require('ramda')
|
||||||
var async = require('async')
|
var async = require('async')
|
||||||
|
var HKDF = require('node-hkdf-sync')
|
||||||
var BigNumber = require('bignumber.js')
|
var BigNumber = require('bignumber.js')
|
||||||
BigNumber.config({CRYPTO: true})
|
BigNumber.config({CRYPTO: true})
|
||||||
|
|
||||||
|
|
@ -34,7 +35,7 @@ var idVerifierPlugin = null
|
||||||
var infoPlugin = null
|
var infoPlugin = null
|
||||||
var emailPlugin = null
|
var emailPlugin = null
|
||||||
var smsPlugin = null
|
var smsPlugin = null
|
||||||
var masterSeed = null
|
var hkdf = null
|
||||||
|
|
||||||
var currentlyUsedPlugins = {}
|
var currentlyUsedPlugins = {}
|
||||||
|
|
||||||
|
|
@ -54,9 +55,9 @@ var coins = {
|
||||||
var alertFingerprint = null
|
var alertFingerprint = null
|
||||||
var lastAlertTime = null
|
var lastAlertTime = null
|
||||||
|
|
||||||
// that's basically a constructor
|
|
||||||
exports.init = function init () {
|
exports.init = function init () {
|
||||||
fs.readFileSync('seeds/seed.txt')
|
const masterSeed = fs.readFileSync('seeds/seed.txt').trim()
|
||||||
|
hkdf = new HKDF('sha256', 'lamassu-server-salt', masterSeed)
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadPlugin (name, config) {
|
function loadPlugin (name, config) {
|
||||||
|
|
@ -175,15 +176,15 @@ exports.configure = function configure (config) {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// WALLET [required] configure (or load)
|
// Give each crypto a different derived seed so as not to allow any
|
||||||
|
// plugin to spend another plugin's funds
|
||||||
|
const cryptoSeed = hkdf.derive(cryptoCode, 32)
|
||||||
|
|
||||||
loadOrConfigPlugin(
|
loadOrConfigPlugin(
|
||||||
walletPlugins[cryptoCode],
|
walletPlugins[cryptoCode],
|
||||||
'transfer',
|
'transfer',
|
||||||
cryptoCode,
|
cryptoCode,
|
||||||
{
|
{masterSeed: cryptoSeed},
|
||||||
nextCashOutSerialHD: db.nextCashOutSerialHD(cryptoCode),
|
|
||||||
masterSeed: masterSeed
|
|
||||||
},
|
|
||||||
function onWalletChange (newWallet) {
|
function onWalletChange (newWallet) {
|
||||||
walletPlugins[cryptoCode] = newWallet
|
walletPlugins[cryptoCode] = newWallet
|
||||||
pollBalance(cryptoCode)
|
pollBalance(cryptoCode)
|
||||||
|
|
@ -348,27 +349,25 @@ exports.sendCoins = function sendCoins (session, rawTx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.cashOut = function cashOut (session, tx) {
|
exports.cashOut = function cashOut (session, tx) {
|
||||||
var tmpInfo = {
|
|
||||||
label: 'TX ' + Date.now(),
|
|
||||||
account: 'deposit'
|
|
||||||
}
|
|
||||||
|
|
||||||
var cryptoCode = tx.cryptoCode || 'BTC'
|
var cryptoCode = tx.cryptoCode || 'BTC'
|
||||||
var walletPlugin = walletPlugins[cryptoCode]
|
var walletPlugin = walletPlugins[cryptoCode]
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return db.nextCashOutSerialHD(tx.sessionId, cryptoCode)
|
||||||
|
.then(serialNumber => new Promise((resolve, reject) => {
|
||||||
|
const tmpInfo = {
|
||||||
|
label: 'TX ' + Date.now(),
|
||||||
|
account: 'deposit',
|
||||||
|
serialNumber: serialNumber
|
||||||
|
}
|
||||||
|
|
||||||
walletPlugin.newAddress(tmpInfo, function (err, address) {
|
walletPlugin.newAddress(tmpInfo, function (err, address) {
|
||||||
if (err) return reject(err)
|
if (err) return reject(err)
|
||||||
|
|
||||||
const addressRec = R.is(String, address)
|
const newTx = R.assoc('toAddress', address, tx)
|
||||||
? {address: address}
|
return db.addInitialIncoming(session, newTx, address)
|
||||||
: address
|
|
||||||
|
|
||||||
const newTx = R.assoc('toAddress', addressRec.address, tx)
|
|
||||||
return db.addInitialIncoming(session, newTx, addressRec)
|
|
||||||
.then(() => resolve(address))
|
.then(() => resolve(address))
|
||||||
})
|
})
|
||||||
})
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.dispenseAck = function dispenseAck (session, rec) {
|
exports.dispenseAck = function dispenseAck (session, rec) {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
const BigNumber = require('bignumber.js')
|
const BigNumber = require('bignumber.js')
|
||||||
const pgp = require('pg-promise')()
|
const pgp = require('pg-promise')()
|
||||||
|
const backoff = require('u-promised').backoff
|
||||||
|
|
||||||
const logger = require('./logger')
|
const logger = require('./logger')
|
||||||
|
|
||||||
|
|
@ -113,7 +114,7 @@ exports.sentCoins = function sentCoins (session, tx, toSend, fee, error, txHash)
|
||||||
return db.none(sql, [txHash, error, session.id])
|
return db.none(sql, [txHash, error, session.id])
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.addInitialIncoming = function addInitialIncoming (session, tx, addressRec) {
|
exports.addInitialIncoming = function addInitialIncoming (session, tx) {
|
||||||
const fields = ['session_id', 'device_fingerprint', 'to_address',
|
const fields = ['session_id', 'device_fingerprint', 'to_address',
|
||||||
'crypto_atoms', 'crypto_code', 'currency_code', 'fiat', 'tx_hash',
|
'crypto_atoms', 'crypto_code', 'currency_code', 'fiat', 'tx_hash',
|
||||||
'phone', 'error'
|
'phone', 'error'
|
||||||
|
|
@ -133,15 +134,6 @@ exports.addInitialIncoming = function addInitialIncoming (session, tx, addressRe
|
||||||
]
|
]
|
||||||
|
|
||||||
return db.none(getInsertQuery('cash_out_txs', fields), values)
|
return db.none(getInsertQuery('cash_out_txs', fields), values)
|
||||||
.then(() => {
|
|
||||||
const hd = addressRec.hd
|
|
||||||
if (hd) {
|
|
||||||
const fields2 = ['session_id', 'to_address', 'crypto_code',
|
|
||||||
'hd_path_prefix', 'hd_serial']
|
|
||||||
const values2 = [tx.sessionId, tx.toAddress, tx.cryptoCode, hd.pathPrefix, hd.serial]
|
|
||||||
return db.none(getInsertQuery('cash_out_hds', fields2), values2)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function insertDispense (session, tx, cartridges) {
|
function insertDispense (session, tx, cartridges) {
|
||||||
|
|
@ -434,9 +426,18 @@ exports.cacheResponse = function (session, path, method, body) {
|
||||||
return db.none(sql, values)
|
return db.none(sql, values)
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.nextCashOutSerialHD = function nextCashOutSerialHD (cryptoCode) {
|
exports.nextCashOutSerialHD = function nextCashOutSerialHD (sessionId, cryptoCode) {
|
||||||
const sql = `select hd_serial from cash_out_hds
|
const sql = `select hd_serial from cash_out_hds
|
||||||
where crypto_code=$1 order by hd_serial desc limit 1`
|
where crypto_code=$1 order by hd_serial desc limit 1`
|
||||||
return db.oneOrNone(sql, [cryptoCode])
|
const attempt = db.oneOrNone(sql, [cryptoCode])
|
||||||
.then(row => row ? row.hd_serial + 1 : 0)
|
.then(row => {
|
||||||
|
const serialNumber = row ? row.hd_serial + 1 : 0
|
||||||
|
const fields2 = ['session_id', 'crypto_code', 'hd_serial']
|
||||||
|
const sql2 = getInsertQuery('cash_out_hds', fields2)
|
||||||
|
const values2 = [sessionId, cryptoCode, serialNumber]
|
||||||
|
return db.none(sql2, values2)
|
||||||
|
.then(() => serialNumber)
|
||||||
|
})
|
||||||
|
|
||||||
|
return backoff(100, 0, 5, attempt)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,10 @@ exports.up = function (next) {
|
||||||
var sql = [
|
var sql = [
|
||||||
`create table cash_out_hds (
|
`create table cash_out_hds (
|
||||||
session_id uuid PRIMARY KEY,
|
session_id uuid PRIMARY KEY,
|
||||||
to_address text NOT NULL,
|
|
||||||
crypto_code text NOT NULL,
|
crypto_code text NOT NULL,
|
||||||
hd_path_prefix text NOT NULL,
|
|
||||||
hd_serial integer NOT NULL,
|
hd_serial integer NOT NULL,
|
||||||
created timestamptz NOT NULL default now(),
|
created timestamptz NOT NULL default now(),
|
||||||
unique (crypto_code, hd_serial)
|
unique (crypto_code, hd_serial),
|
||||||
)`
|
)`
|
||||||
]
|
]
|
||||||
db.multi(sql, next)
|
db.multi(sql, next)
|
||||||
|
|
|
||||||
|
|
@ -31,12 +31,14 @@
|
||||||
"lamassu-smtp2go": "^1.0.3",
|
"lamassu-smtp2go": "^1.0.3",
|
||||||
"lamassu-twilio": "^1.1.0",
|
"lamassu-twilio": "^1.1.0",
|
||||||
"minimist": "0.0.8",
|
"minimist": "0.0.8",
|
||||||
|
"node-hkdf-sync": "^1.0.0",
|
||||||
"node-uuid": "^1.4.2",
|
"node-uuid": "^1.4.2",
|
||||||
"numeral": "^1.5.3",
|
"numeral": "^1.5.3",
|
||||||
"pg": "^4.5.5",
|
"pg": "^4.5.5",
|
||||||
"pg-promise": "^4.3.3",
|
"pg-promise": "^4.3.3",
|
||||||
"pretty-ms": "^2.1.0",
|
"pretty-ms": "^2.1.0",
|
||||||
"ramda": "^0.21.0",
|
"ramda": "^0.21.0",
|
||||||
|
"u-promised": "^0.2.4",
|
||||||
"wreck": "5.1.0"
|
"wreck": "5.1.0"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
||||||
3
todo.txt
3
todo.txt
|
|
@ -1,4 +1,3 @@
|
||||||
- l-m shouldn't keep polling l-s when not on pending screen (low priority)
|
- l-m shouldn't keep polling l-s when not on pending screen (low priority)
|
||||||
|
|
||||||
- need more bulletproof way to ensure only unique serials for each coin
|
- scrutinize hkdf, maybe use own simplified version
|
||||||
- use tx to read last, then insert new row
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue