Refactored some exchange code
This commit is contained in:
parent
54a231ab60
commit
134eaaa518
20 changed files with 141 additions and 643 deletions
|
|
@ -1,86 +0,0 @@
|
|||
'use strict'
|
||||
|
||||
const querystring = require('querystring')
|
||||
const axios = require('axios')
|
||||
const crypto = require('crypto')
|
||||
const _ = require('lodash/fp')
|
||||
|
||||
const API_ENDPOINT = 'https://www.bitstamp.net/api/v2'
|
||||
|
||||
let counter = -1
|
||||
let lastTimestamp = Date.now()
|
||||
|
||||
function pad (num) {
|
||||
const asString = num.toString(10)
|
||||
if (num < 10) return '00' + asString
|
||||
if (num < 100) return '0' + asString
|
||||
return asString
|
||||
}
|
||||
|
||||
function generateNonce () {
|
||||
const timestamp = Date.now()
|
||||
if (timestamp !== lastTimestamp) counter = -1
|
||||
lastTimestamp = timestamp
|
||||
counter = (counter + 1) % 1000
|
||||
return timestamp.toString(10) + pad(counter)
|
||||
}
|
||||
|
||||
function authRequest (config, path, data) {
|
||||
if (!config.key || !config.secret || !config.clientId) {
|
||||
const err = new Error('Must provide key, secret and client ID')
|
||||
return Promise.reject(err)
|
||||
}
|
||||
|
||||
data = data || {}
|
||||
|
||||
const nonce = generateNonce()
|
||||
const msg = [nonce, config.clientId, config.key].join('')
|
||||
|
||||
const signature = crypto
|
||||
.createHmac('sha256', Buffer.from(config.secret))
|
||||
.update(msg)
|
||||
.digest('hex')
|
||||
.toUpperCase()
|
||||
|
||||
const signedData = _.merge(data, {
|
||||
key: config.key,
|
||||
signature: signature,
|
||||
nonce: nonce
|
||||
})
|
||||
|
||||
return request(path, 'POST', signedData)
|
||||
}
|
||||
|
||||
function buildMarket (fiatCode, cryptoCode) {
|
||||
if (!_.includes(cryptoCode, ['BTC', 'ETH', 'LTC', 'BCH'])) {
|
||||
throw new Error('Unsupported crypto: ' + cryptoCode)
|
||||
}
|
||||
|
||||
if (!_.includes(fiatCode, ['USD', 'EUR'])) {
|
||||
throw new Error('Unsupported fiat: ' + fiatCode)
|
||||
}
|
||||
|
||||
return `${cryptoCode.toLowerCase()}${fiatCode.toLowerCase()}`
|
||||
}
|
||||
|
||||
function request (path, method, data) {
|
||||
const options = {
|
||||
method: method,
|
||||
url: API_ENDPOINT + path + '/',
|
||||
headers: {
|
||||
'User-Agent': 'Mozilla/4.0 (compatible; Lamassu client)',
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
}
|
||||
}
|
||||
|
||||
if (data) options.data = querystring.stringify(data)
|
||||
|
||||
return axios(options)
|
||||
.then(r => r.data)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
authRequest,
|
||||
request,
|
||||
buildMarket
|
||||
}
|
||||
|
|
@ -13,16 +13,16 @@ const FIAT = {
|
|||
kraken: ['USD', 'EUR']
|
||||
}
|
||||
|
||||
module.exports = { verifyCurrencies }
|
||||
|
||||
function verifyCurrencies (exchangeName, fiatCode, cryptoCode) {
|
||||
if (!_.includes(cryptoCode, CRYPTO[exchangeName])) {
|
||||
throw new Error('Unsupported crypto: ' + cryptoCode)
|
||||
}
|
||||
if (!(exchangeName === 'coinbase')) { // coinbase is only used for ticker and it's expected to support most of the fiat
|
||||
if (exchangeName !== 'coinbase') {
|
||||
if (!_.includes(fiatCode, FIAT[exchangeName])) {
|
||||
throw new Error('Unsupported fiat: ' + fiatCode)
|
||||
}
|
||||
}
|
||||
return cryptoCode + '/' + fiatCode
|
||||
}
|
||||
|
||||
module.exports = { verifyCurrencies, CRYPTO, FIAT }
|
||||
|
|
|
|||
|
|
@ -1,92 +0,0 @@
|
|||
'use strict'
|
||||
|
||||
const querystring = require('querystring')
|
||||
const axios = require('axios')
|
||||
const crypto = require('crypto')
|
||||
const _ = require('lodash/fp')
|
||||
|
||||
const API_ENDPOINT = 'https://api.itbit.com/v1'
|
||||
|
||||
let counter = -1
|
||||
let lastTimestamp = Date.now()
|
||||
|
||||
function generateNonce () {
|
||||
const timestamp = Date.now()
|
||||
if (timestamp !== lastTimestamp) counter = -1
|
||||
lastTimestamp = timestamp
|
||||
counter = (counter + 1) % 1000
|
||||
return timestamp.toString() + counter.toString()
|
||||
}
|
||||
|
||||
function authRequest (account, method, path, data) {
|
||||
if (!account.userId || !account.walletId || !account.clientKey || !account.clientSecret) {
|
||||
const err = new Error('Must provide user ID, wallet ID, client key, and client secret')
|
||||
return Promise.reject(err)
|
||||
}
|
||||
|
||||
const url = buildURL(method, path, data)
|
||||
const dataString = method !== 'GET' && !_.isEmpty(data) ? JSON.stringify(data) : ''
|
||||
const nonce = generateNonce()
|
||||
const timestamp = Date.now()
|
||||
const message = nonce + JSON.stringify([method, url, dataString, nonce.toString(), timestamp.toString()])
|
||||
|
||||
const hashBuffer = crypto
|
||||
.createHash('sha256')
|
||||
.update(message).digest()
|
||||
|
||||
const bufferToHash = Buffer.concat([Buffer.from(url), hashBuffer])
|
||||
|
||||
const signature = crypto
|
||||
.createHmac('sha512', Buffer.from(account.clientSecret))
|
||||
.update(bufferToHash)
|
||||
.digest('base64')
|
||||
|
||||
return request(method, path, data, {
|
||||
'Authorization': account.clientKey + ':' + signature,
|
||||
'X-Auth-Timestamp': timestamp,
|
||||
'X-Auth-Nonce': nonce
|
||||
})
|
||||
}
|
||||
|
||||
function request (method, path, data, auth) {
|
||||
const options = {
|
||||
method: method,
|
||||
url: buildURL(method, path, data),
|
||||
headers: {
|
||||
'User-Agent': 'Lamassu itBit node.js client',
|
||||
...(auth)
|
||||
},
|
||||
...(method !== 'GET' && { data: data })
|
||||
}
|
||||
|
||||
return axios(options)
|
||||
.then(r => r.data)
|
||||
.catch(e => {
|
||||
var description = _.get(e, 'response.data.description')
|
||||
throw new Error(description || e.message)
|
||||
})
|
||||
}
|
||||
|
||||
const cryptoCodeTranslations = { 'BTC': 'XBT', 'ETH': 'ETH' }
|
||||
function buildMarket (fiatCode, cryptoCode) {
|
||||
const translatedCryptoCode = cryptoCodeTranslations[cryptoCode]
|
||||
if (!translatedCryptoCode) {
|
||||
throw new Error('Unsupported crypto: ' + cryptoCode)
|
||||
}
|
||||
|
||||
if (!_.includes(fiatCode, ['USD', 'EUR', 'SGD'])) {
|
||||
throw new Error('Unsupported fiat: ' + fiatCode)
|
||||
}
|
||||
|
||||
return translatedCryptoCode + fiatCode
|
||||
}
|
||||
|
||||
function buildURL (method, path, data) {
|
||||
let url = API_ENDPOINT + path
|
||||
if (method === 'GET' && !_.isEmpty(data)) {
|
||||
url += '?' + querystring.stringify(data)
|
||||
}
|
||||
return url
|
||||
}
|
||||
|
||||
module.exports = { authRequest, request, buildMarket }
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
const PAIRS = {
|
||||
BTC: {
|
||||
USD: 'XXBTZUSD',
|
||||
EUR: 'XXBTZEUR'
|
||||
},
|
||||
ETH: {
|
||||
USD: 'XETHZUSD',
|
||||
EUR: 'XETHZEUR'
|
||||
},
|
||||
ZEC: {
|
||||
USD: 'XZECZUSD',
|
||||
EUR: 'XZECZEUR'
|
||||
},
|
||||
LTC: {
|
||||
USD: 'XLTCZUSD',
|
||||
EUR: 'XLTCZEUR'
|
||||
},
|
||||
DASH: {
|
||||
USD: 'DASHUSD',
|
||||
EUR: 'DASHEUR'
|
||||
},
|
||||
BCH: {
|
||||
USD: 'BCHUSD',
|
||||
EUR: 'BCHEUR'
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {PAIRS}
|
||||
Loading…
Add table
Add a link
Reference in a new issue