chore: use monorepo organization
This commit is contained in:
parent
deaf7d6ecc
commit
a687827f7e
1099 changed files with 8184 additions and 11535 deletions
21
packages/server/lib/plugins/exchange/binance.js
Normal file
21
packages/server/lib/plugins/exchange/binance.js
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
const { COINS } = require('@lamassu/coins')
|
||||
const _ = require('lodash/fp')
|
||||
|
||||
const { ORDER_TYPES } = require('./consts')
|
||||
|
||||
const ORDER_TYPE = ORDER_TYPES.MARKET
|
||||
const { BTC, BCH, XMR, ETH, LTC, ZEC, LN } = COINS
|
||||
const CRYPTO = [BTC, ETH, LTC, ZEC, BCH, XMR, LN]
|
||||
const FIAT = ['EUR']
|
||||
const DEFAULT_FIAT_MARKET = 'EUR'
|
||||
const REQUIRED_CONFIG_FIELDS = ['apiKey', 'privateKey', 'currencyMarket']
|
||||
|
||||
const loadConfig = (account) => {
|
||||
const mapper = {
|
||||
'privateKey': 'secret'
|
||||
}
|
||||
const mapped = _.mapKeys(key => mapper[key] ? mapper[key] : key)(account)
|
||||
return { ...mapped, timeout: 3000 }
|
||||
}
|
||||
|
||||
module.exports = { loadConfig, DEFAULT_FIAT_MARKET, REQUIRED_CONFIG_FIELDS, CRYPTO, FIAT, ORDER_TYPE }
|
||||
21
packages/server/lib/plugins/exchange/binanceus.js
Normal file
21
packages/server/lib/plugins/exchange/binanceus.js
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
const { COINS } = require('@lamassu/coins')
|
||||
const _ = require('lodash/fp')
|
||||
|
||||
const { ORDER_TYPES } = require('./consts')
|
||||
|
||||
const ORDER_TYPE = ORDER_TYPES.MARKET
|
||||
const { BTC, BCH, DASH, ETH, LTC, ZEC, USDT, USDT_TRON, LN, USDC } = COINS
|
||||
const CRYPTO = [BTC, ETH, LTC, DASH, ZEC, BCH, USDT, USDT_TRON, LN, USDC]
|
||||
const FIAT = ['USD']
|
||||
const DEFAULT_FIAT_MARKET = 'USD'
|
||||
const REQUIRED_CONFIG_FIELDS = ['apiKey', 'privateKey', 'currencyMarket']
|
||||
|
||||
const loadConfig = (account) => {
|
||||
const mapper = {
|
||||
'privateKey': 'secret'
|
||||
}
|
||||
const mapped = _.mapKeys(key => mapper[key] ? mapper[key] : key)(account)
|
||||
return { ...mapped, timeout: 3000 }
|
||||
}
|
||||
|
||||
module.exports = { loadConfig, DEFAULT_FIAT_MARKET, REQUIRED_CONFIG_FIELDS, CRYPTO, FIAT, ORDER_TYPE }
|
||||
22
packages/server/lib/plugins/exchange/bitfinex.js
Normal file
22
packages/server/lib/plugins/exchange/bitfinex.js
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
const { COINS } = require('@lamassu/coins')
|
||||
const _ = require('lodash/fp')
|
||||
|
||||
const { ORDER_TYPES } = require('./consts')
|
||||
|
||||
const ORDER_TYPE = ORDER_TYPES.MARKET
|
||||
const { BTC, ETH, LTC, BCH, USDT, LN, USDC } = COINS
|
||||
const CRYPTO = [BTC, ETH, LTC, BCH, USDT, LN, USDC]
|
||||
const FIAT = ['USD', 'EUR']
|
||||
const DEFAULT_FIAT_MARKET = 'EUR'
|
||||
const AMOUNT_PRECISION = 8
|
||||
const REQUIRED_CONFIG_FIELDS = ['key', 'secret']
|
||||
|
||||
const loadConfig = (account) => {
|
||||
const mapper = {
|
||||
'key': 'apiKey',
|
||||
}
|
||||
const mapped = _.mapKeys(key => mapper[key] ? mapper[key] : key)(account)
|
||||
return { ...mapped, timeout: 3000 }
|
||||
}
|
||||
|
||||
module.exports = { loadConfig, REQUIRED_CONFIG_FIELDS, DEFAULT_FIAT_MARKET, CRYPTO, FIAT, ORDER_TYPE, AMOUNT_PRECISION }
|
||||
23
packages/server/lib/plugins/exchange/bitstamp.js
Normal file
23
packages/server/lib/plugins/exchange/bitstamp.js
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
const { COINS } = require('@lamassu/coins')
|
||||
const _ = require('lodash/fp')
|
||||
|
||||
const { ORDER_TYPES } = require('./consts')
|
||||
|
||||
const ORDER_TYPE = ORDER_TYPES.MARKET
|
||||
const { BTC, ETH, LTC, BCH, USDT, LN, USDC } = COINS
|
||||
const CRYPTO = [BTC, ETH, LTC, BCH, USDT, LN, USDC]
|
||||
const FIAT = ['USD', 'EUR']
|
||||
const DEFAULT_FIAT_MARKET = 'EUR'
|
||||
const AMOUNT_PRECISION = 8
|
||||
const REQUIRED_CONFIG_FIELDS = ['key', 'secret', 'clientId', 'currencyMarket']
|
||||
|
||||
const loadConfig = (account) => {
|
||||
const mapper = {
|
||||
'key': 'apiKey',
|
||||
'clientId': 'uid'
|
||||
}
|
||||
const mapped = _.mapKeys(key => mapper[key] ? mapper[key] : key)(account)
|
||||
return { ...mapped, timeout: 3000 }
|
||||
}
|
||||
|
||||
module.exports = { loadConfig, DEFAULT_FIAT_MARKET, REQUIRED_CONFIG_FIELDS, CRYPTO, FIAT, ORDER_TYPE, AMOUNT_PRECISION }
|
||||
92
packages/server/lib/plugins/exchange/ccxt.js
Normal file
92
packages/server/lib/plugins/exchange/ccxt.js
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
const { utils: coinUtils } = require('@lamassu/coins')
|
||||
const _ = require('lodash/fp')
|
||||
const ccxt = require('ccxt')
|
||||
const mem = require('mem')
|
||||
|
||||
const { buildMarket, ALL, isConfigValid } = require('../common/ccxt')
|
||||
const { ORDER_TYPES } = require('./consts')
|
||||
const logger = require('../../logger')
|
||||
const { currencies } = require('../../new-admin/config')
|
||||
const T = require('../../time')
|
||||
|
||||
const DEFAULT_PRICE_PRECISION = 2
|
||||
const DEFAULT_AMOUNT_PRECISION = 8
|
||||
|
||||
function trade (side, account, tradeEntry, exchangeName) {
|
||||
const { cryptoAtoms, fiatCode, cryptoCode: _cryptoCode, tradeId } = tradeEntry
|
||||
try {
|
||||
const cryptoCode = coinUtils.getEquivalentCode(_cryptoCode)
|
||||
const exchangeConfig = ALL[exchangeName]
|
||||
if (!exchangeConfig) throw Error('Exchange configuration not found')
|
||||
|
||||
const { USER_REF, loadOptions, loadConfig = _.noop, REQUIRED_CONFIG_FIELDS, ORDER_TYPE, AMOUNT_PRECISION } = exchangeConfig
|
||||
if (!isConfigValid(account, REQUIRED_CONFIG_FIELDS)) throw Error('Invalid config')
|
||||
|
||||
const selectedFiatMarket = account.currencyMarket
|
||||
const symbol = buildMarket(selectedFiatMarket, cryptoCode, exchangeName)
|
||||
const precision = _.defaultTo(DEFAULT_AMOUNT_PRECISION, AMOUNT_PRECISION)
|
||||
const amount = coinUtils.toUnit(cryptoAtoms, cryptoCode).toFixed(precision)
|
||||
const accountOptions = _.isFunction(loadOptions) ? loadOptions(account) : {}
|
||||
const withCustomKey = USER_REF ? { [USER_REF]: tradeId } : {}
|
||||
const options = _.assign(accountOptions, withCustomKey)
|
||||
const exchange = new ccxt[exchangeName](loadConfig(account))
|
||||
|
||||
if (ORDER_TYPE === ORDER_TYPES.MARKET) {
|
||||
return exchange.createOrder(symbol, ORDER_TYPES.MARKET, side, amount, null, options)
|
||||
}
|
||||
|
||||
return exchange.fetchOrderBook(symbol)
|
||||
.then(orderBook => {
|
||||
const price = calculatePrice(side, amount, orderBook).toFixed(DEFAULT_PRICE_PRECISION)
|
||||
return exchange.createOrder(symbol, ORDER_TYPES.LIMIT, side, amount, price, options)
|
||||
})
|
||||
} catch (e) {
|
||||
return Promise.reject(e)
|
||||
}
|
||||
}
|
||||
|
||||
function calculatePrice (side, amount, orderBook) {
|
||||
const book = side === 'buy' ? 'asks' : 'bids'
|
||||
let collected = 0.0
|
||||
for (const entry of orderBook[book]) {
|
||||
collected += parseFloat(entry[1])
|
||||
if (collected >= amount) return parseFloat(entry[0])
|
||||
}
|
||||
throw new Error('Insufficient market depth')
|
||||
}
|
||||
|
||||
function _getMarkets (exchangeName, availableCryptos) {
|
||||
const prunedCryptos = _.compose(_.uniq, _.map(coinUtils.getEquivalentCode))(availableCryptos)
|
||||
|
||||
try {
|
||||
const exchange = new ccxt[exchangeName]()
|
||||
const cryptosToQuoteAgainst = ['USDT']
|
||||
const currencyCodes = _.concat(_.map(it => it.code, currencies), cryptosToQuoteAgainst)
|
||||
|
||||
return exchange.fetchMarkets()
|
||||
.then(_.filter(it => (it.type === 'spot' || it.spot)))
|
||||
.then(res =>
|
||||
_.reduce((acc, value) => {
|
||||
if (_.includes(value.base, prunedCryptos) && _.includes(value.quote, currencyCodes)) {
|
||||
if (value.quote === value.base) return acc
|
||||
|
||||
if (_.isNil(acc[value.quote])) {
|
||||
return { ...acc, [value.quote]: [value.base] }
|
||||
}
|
||||
|
||||
acc[value.quote].push(value.base)
|
||||
}
|
||||
return acc
|
||||
}, {}, res)
|
||||
)
|
||||
} catch (e) {
|
||||
logger.debug(`No CCXT exchange found for ${exchangeName}`)
|
||||
}
|
||||
}
|
||||
|
||||
const getMarkets = mem(_getMarkets, {
|
||||
maxAge: T.week,
|
||||
cacheKey: (exchangeName, availableCryptos) => exchangeName
|
||||
})
|
||||
|
||||
module.exports = { trade, getMarkets }
|
||||
21
packages/server/lib/plugins/exchange/cex.js
Normal file
21
packages/server/lib/plugins/exchange/cex.js
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
const { COINS } = require('@lamassu/coins')
|
||||
const _ = require('lodash/fp')
|
||||
|
||||
const { ORDER_TYPES } = require('./consts')
|
||||
|
||||
const ORDER_TYPE = ORDER_TYPES.MARKET
|
||||
const { BTC, BCH, DASH, ETH, LTC, USDT, TRX, USDT_TRON, LN } = COINS
|
||||
const CRYPTO = [BTC, ETH, LTC, DASH, BCH, USDT, TRX, USDT_TRON, LN]
|
||||
const FIAT = ['USD', 'EUR']
|
||||
const DEFAULT_FIAT_MARKET = 'EUR'
|
||||
const REQUIRED_CONFIG_FIELDS = ['apiKey', 'privateKey', 'currencyMarket']
|
||||
|
||||
const loadConfig = (account) => {
|
||||
const mapper = {
|
||||
'privateKey': 'secret'
|
||||
}
|
||||
const mapped = _.mapKeys(key => mapper[key] ? mapper[key] : key)(account)
|
||||
return { ...mapped, timeout: 3000 }
|
||||
}
|
||||
|
||||
module.exports = { loadConfig, DEFAULT_FIAT_MARKET, REQUIRED_CONFIG_FIELDS, CRYPTO, FIAT, ORDER_TYPE }
|
||||
7
packages/server/lib/plugins/exchange/consts.js
Normal file
7
packages/server/lib/plugins/exchange/consts.js
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
|
||||
const ORDER_TYPES = {
|
||||
MARKET: 'market',
|
||||
LIMIT: 'limit'
|
||||
}
|
||||
|
||||
module.exports = { ORDER_TYPES }
|
||||
25
packages/server/lib/plugins/exchange/itbit.js
Normal file
25
packages/server/lib/plugins/exchange/itbit.js
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
const _ = require('lodash/fp')
|
||||
|
||||
const { ORDER_TYPES } = require('./consts')
|
||||
const { COINS } = require('@lamassu/coins')
|
||||
|
||||
const ORDER_TYPE = ORDER_TYPES.LIMIT
|
||||
const { BTC, ETH, USDT, LN } = COINS
|
||||
const CRYPTO = [BTC, ETH, USDT, LN]
|
||||
const FIAT = ['USD']
|
||||
const DEFAULT_FIAT_MARKET = 'USD'
|
||||
const AMOUNT_PRECISION = 4
|
||||
const REQUIRED_CONFIG_FIELDS = ['clientKey', 'clientSecret', 'userId', 'walletId', 'currencyMarket']
|
||||
|
||||
const loadConfig = (account) => {
|
||||
const mapper = {
|
||||
'clientKey': 'apiKey',
|
||||
'clientSecret': 'secret',
|
||||
'userId': 'uid'
|
||||
}
|
||||
const mapped = _.mapKeys(key => mapper[key] ? mapper[key] : key)(_.omit(['walletId'], account))
|
||||
return { ...mapped, timeout: 3000 }
|
||||
}
|
||||
const loadOptions = ({ walletId }) => ({ walletId })
|
||||
|
||||
module.exports = { loadOptions, loadConfig, DEFAULT_FIAT_MARKET, REQUIRED_CONFIG_FIELDS, CRYPTO, FIAT, ORDER_TYPE, AMOUNT_PRECISION }
|
||||
30
packages/server/lib/plugins/exchange/kraken.js
Normal file
30
packages/server/lib/plugins/exchange/kraken.js
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
const _ = require('lodash/fp')
|
||||
|
||||
const { ORDER_TYPES } = require('./consts')
|
||||
const { COINS } = require('@lamassu/coins')
|
||||
|
||||
const ORDER_TYPE = ORDER_TYPES.MARKET
|
||||
const { BTC, BCH, DASH, ETH, LTC, ZEC, XMR, USDT, TRX, USDT_TRON, LN, USDC } = COINS
|
||||
const CRYPTO = [BTC, ETH, LTC, DASH, ZEC, BCH, XMR, USDT, TRX, USDT_TRON, LN, USDC]
|
||||
const FIAT = ['USD', 'EUR']
|
||||
const DEFAULT_FIAT_MARKET = 'EUR'
|
||||
const AMOUNT_PRECISION = 6
|
||||
const REQUIRED_CONFIG_FIELDS = ['apiKey', 'privateKey', 'currencyMarket']
|
||||
const USER_REF = 'userref'
|
||||
|
||||
const loadConfig = (account) => {
|
||||
const mapper = {
|
||||
'privateKey': 'secret'
|
||||
}
|
||||
const mapped = _.mapKeys(key => mapper[key] ? mapper[key] : key)(account)
|
||||
|
||||
return {
|
||||
...mapped,
|
||||
timeout: 3000,
|
||||
nonce: function () { return this.microseconds() }
|
||||
}
|
||||
}
|
||||
|
||||
const loadOptions = () => ({ expiretm: '+60' })
|
||||
|
||||
module.exports = { USER_REF, loadOptions, loadConfig, DEFAULT_FIAT_MARKET, REQUIRED_CONFIG_FIELDS, CRYPTO, FIAT, ORDER_TYPE, AMOUNT_PRECISION }
|
||||
14
packages/server/lib/plugins/exchange/mock-exchange.js
Normal file
14
packages/server/lib/plugins/exchange/mock-exchange.js
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
module.exports = {
|
||||
buy,
|
||||
sell
|
||||
}
|
||||
|
||||
function buy (cryptoAtoms, fiatCode, cryptoCode) {
|
||||
console.log('[mock] buying %s %s for %s', cryptoAtoms.toString(), cryptoCode, fiatCode)
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
function sell (cryptoAtoms, fiatCode, cryptoCode) {
|
||||
console.log('[mock] selling %s %s for %s', cryptoAtoms.toString(), cryptoCode, fiatCode)
|
||||
return Promise.resolve()
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue