From 8cdad0bc152489d9495b929e1dac9c9839f6bb8d Mon Sep 17 00:00:00 2001 From: Josh Harvey Date: Fri, 19 May 2017 01:34:09 +0300 Subject: [PATCH] add more db fields for fixed fee --- lamassu-schema.json | 11 ++++---- lib/bn.js | 4 +++ lib/cash-in-tx.js | 20 +++++---------- lib/config-validate.js | 6 ++++- lib/plugins.js | 18 +++++++++++-- lib/routes.js | 8 ++---- lib/settings-loader.js | 3 +++ lib/tx.js | 10 +++++++- migrations/033-add_cash_in_fee.js | 17 +++++++++++++ tools/modify.js | 42 ++++++------------------------- 10 files changed, 74 insertions(+), 65 deletions(-) create mode 100644 migrations/033-add_cash_in_fee.js diff --git a/lamassu-schema.json b/lamassu-schema.json index aac2e4ac..5ad0d845 100644 --- a/lamassu-schema.json +++ b/lamassu-schema.json @@ -45,7 +45,7 @@ "cashInCommission", "cashOutCommission", "cashInFee", - "cashOutFee" + "minimumTx" ] }, { @@ -131,9 +131,9 @@ }, { "code": "cashInFee", - "displayTop": "Fixed Fees", + "displayTop": "Cash-in", + "displayBottom": "Fixed Fee", "displayTopCount": 2, - "displayBottom": "Cash-in", "fieldType": "integer", "fieldClass": "fiat", "cryptoScope": "both", @@ -150,8 +150,8 @@ ] }, { - "code": "cashOutFee", - "displayBottom": "Cash-out", + "code": "minimumTx", + "displayBottom": "Minimum Tx", "displayTopCount": 0, "fieldType": "integer", "fieldClass": "fiat", @@ -159,7 +159,6 @@ "machineScope": "both", "default": 0, "enabledIf": [ - "cashOutEnabled" ], "fieldValidation": [ { diff --git a/lib/bn.js b/lib/bn.js index 2c16ef94..b14298ad 100644 --- a/lib/bn.js +++ b/lib/bn.js @@ -3,4 +3,8 @@ const BigNumber = require('bignumber.js') BigNumber.config({ROUNDING_MODE: BigNumber.ROUND_HALF_EVEN}) function BN (s, radix) { return new BigNumber(s, radix) } + +BN.min = BigNumber.min +BN.max = BigNumber.max + module.exports = BN diff --git a/lib/cash-in-tx.js b/lib/cash-in-tx.js index 3cbad152..f3cdad62 100644 --- a/lib/cash-in-tx.js +++ b/lib/cash-in-tx.js @@ -5,8 +5,6 @@ const BN = require('./bn') const plugins = require('./plugins') const logger = require('./logger') -const mapValuesWithKey = _.mapValues.convert({cap: false}) - module.exports = {post, monitorPending} const PENDING_INTERVAL = '1 day' @@ -84,12 +82,10 @@ function ensureRatchet (oldField, newField, fieldKey) { return true } + if (oldField.isBigNumber && newField.isBigNumber) return BN(oldField).eq(newField) if (oldField.toString() === newField.toString()) return true - logger.error('This field [%s] should never change', fieldKey) - logger.error('oldField: %j', oldField) - logger.error('newField: %j', newField) - throw new Error(`This field [${fieldKey}] should never change`) + return false } function diff (oldTx, newTx) { @@ -108,7 +104,7 @@ function diff (oldTx, newTx) { logger.warn('Value from lamassu-machine would violate ratchet [%s]', fieldKey) logger.warn('Old tx: %j', oldTx) logger.warn('New tx: %j', newTx) - return + throw new Error('Value from lamassu-machine would violate ratchet') } updatedTx[fieldKey] = newField @@ -125,7 +121,7 @@ function toObj (row) { keys.forEach(key => { const objKey = _.camelCase(key) - if (key === 'crypto_atoms' || key === 'fiat') { + if (key === 'crypto_atoms' || key === 'fiat' || key === 'cash_in_fee') { newObj[objKey] = BN(row[key]) return } @@ -144,15 +140,11 @@ function toObj (row) { } function convertBigNumFields (obj) { - const convert = (value, key) => _.includes(key, ['cryptoAtoms', 'fiat']) + const convert = value => value && value.isBigNumber ? value.toString() : value - const convertKey = key => _.includes(key, ['cryptoAtoms', 'fiat']) - ? key + '#' - : key - - return _.mapKeys(convertKey, mapValuesWithKey(convert, obj)) + return _.mapValues(convert, obj) } function pullNewBills (billRows, machineTx) { diff --git a/lib/config-validate.js b/lib/config-validate.js index 3bdc5903..af098a26 100644 --- a/lib/config-validate.js +++ b/lib/config-validate.js @@ -2,6 +2,7 @@ const _ = require('lodash/fp') const db = require('./db') const configManager = require('./config-manager') +const logger = require('./logger') const schema = require('../lamassu-schema.json') function allScopes (cryptoScopes, machineScopes) { @@ -122,7 +123,10 @@ function ensureConstraints (config) { config.every(fieldInstance => { const fieldCode = fieldInstance.fieldLocator.code const field = pickField(fieldCode) - if (!field) throw new Error('No such field: ' + fieldCode) + if (!field) { + logger.error('No such field: %s, %j', fieldCode, fieldInstance.fieldLocator.fieldScope) + throw new Error('No such field: ' + fieldCode) + } const fieldValue = fieldInstance.fieldValue diff --git a/lib/plugins.js b/lib/plugins.js index 186dd73b..40f6753d 100644 --- a/lib/plugins.js +++ b/lib/plugins.js @@ -165,6 +165,19 @@ function plugins (settings, deviceId) { .then(row => row.id) } + function mapCoinSettings (coin) { + const config = configManager.scoped(coin, deviceId, settings.config) + const minimumTx = BN(config.minimumTx) + const cashInFee = BN(config.cashInFee) + + const coinSettings = { + minimumTx: BN.max(minimumTx, cashInFee), + cashInFee: cashInFee + } + + return [coin, coinSettings] + } + function pollQueries (serialNumber, deviceTime, deviceRec) { const config = configManager.machineScoped(deviceId, settings.config) const fiatCode = config.fiatCurrency @@ -184,7 +197,7 @@ function plugins (settings, deviceId) { return Promise.all(promises) .then(arr => { const cassettes = arr[0] - const currentConfigVersion = arr[2] + const configVersion = arr[2] const tickers = arr.slice(3, cryptoCodes.length + 3) const balances = arr.slice(cryptoCodes.length + 3) @@ -192,7 +205,8 @@ function plugins (settings, deviceId) { cassettes, rates: buildRates(tickers), balances: buildBalances(balances), - currentConfigVersion + coinSettings: _.fromPairs(_.map(mapCoinSettings, cryptoCodes)), + configVersion } }) } diff --git a/lib/routes.js b/lib/routes.js index 204c2e0a..f844eb53 100644 --- a/lib/routes.js +++ b/lib/routes.js @@ -63,18 +63,14 @@ function poll (req, res, next) { twoWayMode: config.cashOutEnabled, zeroConfLimit: config.zeroConfLimit, fiatTxLimit: config.cashOutTransactionLimit, - reboot, - rates: results.rates, - balances: results.balances, - coins: config.cryptoCurrencies, - configVersion: results.currentConfigVersion + reboot } if (response.idVerificationEnabled) { response.idVerificationLimit = config.idVerificationLimit } - return res.json(response) + return res.json(_.assign(response, results)) }) .catch(next) } diff --git a/lib/settings-loader.js b/lib/settings-loader.js index 9dc6173a..246a9646 100644 --- a/lib/settings-loader.js +++ b/lib/settings-loader.js @@ -131,9 +131,12 @@ function settings () { return settingsCache } +const pp = require('./pp') function save (config) { const sql = 'insert into user_config (type, data, valid) values ($1, $2, $3)' + console.log(pp('DEBUG101')(config)) + return configValidate.validate(config) .then(() => db.none(sql, ['config', {config}, true])) .catch(() => db.none(sql, ['config', {config}, false])) diff --git a/lib/tx.js b/lib/tx.js index 56cc4103..3db58f86 100644 --- a/lib/tx.js +++ b/lib/tx.js @@ -21,7 +21,15 @@ function massage (tx) { const transformDate = (v, k) => isDateField(k) ? new Date(v) : v const mapValuesWithKey = _.mapValues.convert({'cap': false}) const transformDates = r => mapValuesWithKey(transformDate, r) - const mapBN = r => _.assign(r, {cryptoAtoms: BN(r.cryptoAtoms), fiat: BN(r.fiat)}) + + const mapBN = r => { + const update = r.direction === 'cashIn' + ? {cryptoAtoms: BN(r.cryptoAtoms), fiat: BN(r.fiat), cashInFee: BN(r.cashInFee)} + : {cryptoAtoms: BN(r.cryptoAtoms), fiat: BN(r.fiat)} + + return _.assign(r, update) + } + const mapper = _.flow(transformDates, mapBN, _.unset('dirty')) return mapper(tx) diff --git a/migrations/033-add_cash_in_fee.js b/migrations/033-add_cash_in_fee.js new file mode 100644 index 00000000..5aca727f --- /dev/null +++ b/migrations/033-add_cash_in_fee.js @@ -0,0 +1,17 @@ +var db = require('./db') + +exports.up = function (next) { + var sql = [ + 'alter table cash_in_txs add column cash_in_fee numeric(14, 5) not null', + 'alter table cash_in_txs add column cash_in_fee_crypto bigint not null', + 'alter table cash_in_txs add column minimum_tx integer not null', + 'alter table bills add column cash_in_fee numeric(14, 5) not null', + 'alter table bills add column cash_in_fee_crypto bigint not null', + 'alter table bills add column crypto_atoms_after_fee bigint not null' + ] + db.multi(sql, next) +} + +exports.down = function (next) { + next() +} diff --git a/tools/modify.js b/tools/modify.js index 7878c224..3f216334 100644 --- a/tools/modify.js +++ b/tools/modify.js @@ -1,40 +1,12 @@ -'use strict' +const settingsLoader = require('../lib/settings-loader') -const R = require('ramda') -const db = require('../db') +const fields = [ + settingsLoader.configDeleteField({crypto: 'global', machine: 'global'}, 'cashOutFee'), + settingsLoader.configDeleteField({crypto: 'global', machine: 'global'}, 'minTx') +] -function pp (o) { - console.log(require('util').inspect(o, {depth: null, colors: true})) -} - -function dbFetchConfig () { - return db.oneOrNone('select data from user_config where type=$1', ['config']) - .then(row => row && row.data) -} - -dbFetchConfig() -.then(c => { - const groups = c.groups - .filter(g => g.code !== 'fiat') - .map(g => { - if (g.code === 'currencies') { - const values = g.values.filter(v => v.fieldLocator.code !== 'cryptoCurrencies') - return R.assoc('values', values, g) - } - - return g - }) - - return {groups: groups} -}) -.then(config => { - pp(config) - return db.none('update user_config set data=$1 where type=$2', [config, 'config']) -}) +settingsLoader.modifyConfig(fields) .then(() => { + console.log('success.') process.exit(0) }) -.catch(e => { - console.log(e) - process.exit(1) -})