IPC removed, replaced by WS

This commit is contained in:
Luis Fernando Molina committed 2020-04-06 08:33:07 +02:00
1 parent ba4217fb24
commit 656c193511
503 files changed
+28128 -34498

No files matched your search

+118 -166
View File
@@ -48,17 +48,13 @@ const BN = require ('../static_dependencies/BN/bn')
// ----------------------------------------------------------------------------
// web3 / 0x imports
let Web3 = undefined
, ethAbi = undefined
let ethAbi = undefined
, ethUtil = undefined
, BigNumber = undefined
try {
const requireFunction = require;
Web3 = requireFunction ('web3') // eslint-disable-line global-require
ethAbi = requireFunction ('ethereumjs-abi') // eslint-disable-line global-require
ethUtil = requireFunction ('ethereumjs-util') // eslint-disable-line global-require
BigNumber = requireFunction ('bignumber.js') // eslint-disable-line global-require
// we prefer bignumber.js over BN.js
// BN = requireFunction ('bn.js') // eslint-disable-line global-require
} catch (e) {
@@ -77,6 +73,7 @@ module.exports = class Exchange {
'enableRateLimit': false,
'rateLimit': 2000, // milliseconds = seconds * 1000
'certified': false,
'pro': false,
'has': {
'cancelAllOrders': false,
'cancelOrder': true,
@@ -169,6 +166,7 @@ module.exports = class Exchange {
'429': RateLimitExceeded,
'404': ExchangeNotAvailable,
'409': ExchangeNotAvailable,
'410': ExchangeNotAvailable,
'500': ExchangeNotAvailable,
'501': ExchangeNotAvailable,
'502': ExchangeNotAvailable,
@@ -276,8 +274,6 @@ module.exports = class Exchange {
this.last_json_response = undefined
this.last_response_headers = undefined
this.arrayConcat = (a, b) => a.concat (b)
const unCamelCaseProperties = (obj = this) => {
if (obj !== null) {
for (const k of Object.getOwnPropertyNames (obj)) {
@@ -315,11 +311,6 @@ module.exports = class Exchange {
if (this.markets)
this.setMarkets (this.markets)
if (this.requiresWeb3 && !this.web3 && Web3) {
const provider = (this.web3ProviderURL) ? new Web3.providers.HttpProvider (this.web3ProviderURL) : new Web3.providers.HttpProvider ()
this.web3 = new Web3 (Web3.givenProvider || provider)
}
}
defaults () {
@@ -367,7 +358,6 @@ module.exports = class Exchange {
throw new Error (this.id + '.rateLimit property is not configured')
this.tokenBucket = this.extend ({
refillRate: 1 / this.rateLimit,
delay: 1,
capacity: 1,
defaultCost: 1,
@@ -472,42 +462,50 @@ module.exports = class Exchange {
}
}
print (... args) {
console.log (... args)
}
fetch (url, method = 'GET', headers = undefined, body = undefined) {
if (isNode && this.userAgent) {
if (typeof this.userAgent === 'string')
if (typeof this.userAgent === 'string') {
headers = extend ({ 'User-Agent': this.userAgent }, headers)
else if ((typeof this.userAgent === 'object') && ('User-Agent' in this.userAgent))
} else if ((typeof this.userAgent === 'object') && ('User-Agent' in this.userAgent)) {
headers = extend (this.userAgent, headers)
}
}
if (typeof this.proxy === 'function') {
url = this.proxy (url)
if (isNode)
if (isNode) {
headers = extend ({ 'Origin': this.origin }, headers)
}
} else if (typeof this.proxy === 'string') {
if (this.proxy.length)
if (isNode)
headers = extend ({ 'Origin': this.origin }, headers)
if (this.proxy.length && isNode) {
headers = extend ({ 'Origin': this.origin }, headers)
}
url = this.proxy + url
}
headers = extend (this.headers, headers)
if (this.verbose)
console.log ("fetch:\n", this.id, method, url, "\nRequest:\n", headers, "\n", body, "\n")
if (this.verbose) {
this.print ("fetch:\n", this.id, method, url, "\nRequest:\n", headers, "\n", body, "\n")
}
return this.executeRestRequest (url, method, headers, body)
}
async fetch2 (path, type = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
if (this.enableRateLimit)
await this.throttle ()
if (this.enableRateLimit) {
await this.throttle (this.rateLimit)
}
const request = this.sign (path, type, method, params, headers, body)
return this.fetch (request.url, request.method, request.headers, request.body)
@@ -622,8 +620,9 @@ module.exports = class Exchange {
this.last_json_response = json // FIXME: for those classes that haven't switched to handleErrors yet
}
if (this.verbose)
console.log ("handleRestResponse:\n", this.id, method, url, response.status, response.statusText, "\nResponse:\n", responseHeaders, "\n", responseBody, "\n")
if (this.verbose) {
this.print ("handleRestResponse:\n", this.id, method, url, response.status, response.statusText, "\nResponse:\n", responseHeaders, "\n", responseBody, "\n")
}
this.handleErrors (response.status, response.statusText, url, method, responseHeaders, responseBody, json, requestHeaders, requestBody)
this.defaultErrorHandler (response.status, response.statusText, url, method, responseHeaders, responseBody, json)
@@ -645,7 +644,7 @@ module.exports = class Exchange {
if (currencies) {
this.currencies = deepExtend (currencies, this.currencies)
} else {
const baseCurrencies =
let baseCurrencies =
values.filter (market => 'base' in market)
.map (market => ({
id: market.baseId || market.base,
@@ -653,7 +652,7 @@ module.exports = class Exchange {
code: market.base,
precision: market.precision ? (market.precision.base || market.precision.amount) : 8,
}))
const quoteCurrencies =
let quoteCurrencies =
values.filter (market => 'quote' in market)
.map (market => ({
id: market.quoteId || market.quote,
@@ -661,6 +660,10 @@ module.exports = class Exchange {
code: market.quote,
precision: market.precision ? (market.precision.quote || market.precision.price) : 8,
}))
baseCurrencies = sortBy (baseCurrencies, 'code')
quoteCurrencies = sortBy (quoteCurrencies, 'code')
this.baseCurrencies = indexBy (baseCurrencies, 'code')
this.quoteCurrencies = indexBy (quoteCurrencies, 'code')
const allCurrencies = baseCurrencies.concat (quoteCurrencies)
const groupedCurrencies = groupBy (allCurrencies, 'code')
const currencies = Object.keys (groupedCurrencies).map (code =>
@@ -673,7 +676,7 @@ module.exports = class Exchange {
return this.markets
}
async loadMarkets (reload = false, params = {}) {
async loadMarketsHelper (reload = false, params = {}) {
if (!reload && this.markets) {
if (!this.markets_by_id) {
return this.setMarkets (this.markets)
@@ -688,6 +691,21 @@ module.exports = class Exchange {
return this.setMarkets (markets, currencies)
}
// is async (returns a promise)
loadMarkets (reload = false, params = {}) {
if ((reload && !this.reloadingMarkets) || !this.marketsLoading) {
this.reloadingMarkets = true
this.marketsLoading = this.loadMarketsHelper (reload, params).then ((resolved) => {
this.reloadingMarkets = false
return resolved
}, (error) => {
this.reloadingMarkets = false
throw error
})
}
return this.marketsLoading
}
async loadAccounts (reload = false, params = {}) {
if (reload) {
this.accounts = await this.fetchAccounts (params)
@@ -725,43 +743,42 @@ module.exports = class Exchange {
}
parseTradingViewOHLCV (ohlcvs, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
const result = this.convertTradingViewToOHLCV (ohlcvs);
return this.parseOHLCVs (result, market, timeframe, since, limit);
const result = this.convertTradingViewToOHLCV (ohlcvs)
return this.parseOHLCVs (result, market, timeframe, since, limit)
}
convertTradingViewToOHLCV (ohlcvs) {
convertTradingViewToOHLCV (ohlcvs, t = 't', o = 'o', h = 'h', l = 'l', c = 'c', v = 'v', ms = false) {
const result = [];
for (let i = 0; i < ohlcvs['t'].length; i++) {
for (let i = 0; i < ohlcvs[t].length; i++) {
result.push ([
ohlcvs['t'][i] * 1000,
ohlcvs['o'][i],
ohlcvs['h'][i],
ohlcvs['l'][i],
ohlcvs['c'][i],
ohlcvs['v'][i],
]);
ms ? ohlcvs[t][i] : (ohlcvs[t][i] * 1000),
ohlcvs[o][i],
ohlcvs[h][i],
ohlcvs[l][i],
ohlcvs[c][i],
ohlcvs[v][i],
])
}
return result;
return result
}
convertOHLCVToTradingView (ohlcvs) {
const result = {
't': [],
'o': [],
'h': [],
'l': [],
'c': [],
'v': [],
};
convertOHLCVToTradingView (ohlcvs, t = 't', o = 'o', h = 'h', l = 'l', c = 'c', v = 'v', ms = false) {
const result = {}
result[t] = []
result[o] = []
result[h] = []
result[l] = []
result[c] = []
result[v] = []
for (let i = 0; i < ohlcvs.length; i++) {
result['t'].push (parseInt (ohlcvs[i][0] / 1000));
result['o'].push (ohlcvs[i][1]);
result['h'].push (ohlcvs[i][2]);
result['l'].push (ohlcvs[i][3]);
result['c'].push (ohlcvs[i][4]);
result['v'].push (ohlcvs[i][5]);
result[t].push (ms ? ohlcvs[i][0] : parseInt (ohlcvs[i][0] / 1000))
result[o].push (ohlcvs[i][1])
result[h].push (ohlcvs[i][2])
result[l].push (ohlcvs[i][3])
result[c].push (ohlcvs[i][4])
result[v].push (ohlcvs[i][5])
}
return result;
return result
}
fetchTicker (symbol, params = {}) {
@@ -993,8 +1010,8 @@ module.exports = class Exchange {
async fetchStatus (params = {}) {
if (this.has['fetchTime']) {
const time = await this.fetchTime(params)
return this.status = this.extend(this.status, {
const time = await this.fetchTime (params)
this.status = this.extend (this.status, {
'updated': time,
})
}
@@ -1026,27 +1043,34 @@ module.exports = class Exchange {
return this.markets;
}
filterBySinceLimit (array, since = undefined, limit = undefined, key = 'timestamp') {
if (since !== undefined && since !== null)
array = array.filter (entry => entry[key] >= since)
if (limit !== undefined && limit !== null)
array = array.slice (0, limit)
filterBySinceLimit (array, since = undefined, limit = undefined, key = 'timestamp', tail = false) {
const sinceIsDefined = (since !== undefined && since !== null)
if (sinceIsDefined) {
array = array.filter ((entry) => entry[key] >= since)
}
if (limit !== undefined && limit !== null) {
array = (tail && !sinceIsDefined) ? array.slice (-limit) : array.slice (0, limit)
}
return array
}
filterByValueSinceLimit (array, field, value = undefined, since = undefined, limit = undefined) {
filterByValueSinceLimit (array, field, value = undefined, since = undefined, limit = undefined, key = 'timestamp', tail = false) {
const valueIsDefined = value !== undefined && value !== null
const sinceIsDefined = since !== undefined && since !== null
// single-pass filter for both symbol and since
if (valueIsDefined || sinceIsDefined)
array = Object.values (array).filter (entry =>
((valueIsDefined ? (entry[field] === value) : true) &&
(sinceIsDefined ? (entry.timestamp >= since) : true)))
if (valueIsDefined || sinceIsDefined) {
array = Object.values (array).filter ((entry) =>
((valueIsDefined ? (entry[field] === value) : true) &&
(sinceIsDefined ? (entry[key] >= since) : true)))
}
if (limit !== undefined && limit !== null)
array = Object.values (array).slice (0, limit)
if (limit !== undefined && limit !== null) {
array = ((tail && !sinceIsDefined) ?
Object.values (array).slice (-limit) :
Object.values (array).slice (0, limit))
}
return array
}
@@ -1064,13 +1088,15 @@ module.exports = class Exchange {
objects = Object.values (objects)
// return all of them if no values were passed
if (values === undefined || values === null)
if (values === undefined || values === null) {
return indexed ? indexBy (objects, key) : objects
}
const result = []
for (let i = 0; i < objects.length; i++) {
if (values.includes (objects[i][key]))
if (values.includes (objects[i][key])) {
result.push (objects[i])
}
}
return indexed ? indexBy (result, key) : result
@@ -1081,7 +1107,7 @@ module.exports = class Exchange {
// if (!this.isArray (trades)) {
// throw new ExchangeError (this.id + ' parseTrades expected an array in the trades argument, but got ' + typeof trades);
// }
let result = Object.values (trades || []).map (trade => this.extend (this.parseTrade (trade, market), params))
let result = Object.values (trades || []).map ((trade) => this.extend (this.parseTrade (trade, market), params))
result = sortBy (result, 'timestamp')
const symbol = (market !== undefined) ? market['symbol'] : undefined
return this.filterBySymbolSinceLimit (result, symbol, since, limit)
@@ -1092,7 +1118,7 @@ module.exports = class Exchange {
// if (!this.isArray (transactions)) {
// throw new ExchangeError (this.id + ' parseTransactions expected an array in the transactions argument, but got ' + typeof transactions);
// }
let result = Object.values (transactions || []).map (transaction => this.extend (this.parseTransaction (transaction, currency), params))
let result = Object.values (transactions || []).map ((transaction) => this.extend (this.parseTransaction (transaction, currency), params))
result = this.sortBy (result, 'timestamp');
const code = (currency !== undefined) ? currency['code'] : undefined;
return this.filterByCurrencySinceLimit (result, code, since, limit);
@@ -1248,97 +1274,32 @@ module.exports = class Exchange {
// ------------------------------------------------------------------------
// web3 / 0x methods
static hasWeb3 () {
return Web3 && ethUtil && ethAbi && BigNumber
return ethUtil && ethAbi
}
checkRequiredDependencies () {
if (!Exchange.hasWeb3 ()) {
throw new ExchangeError ("Required dependencies missing: \nnpm i web3 ethereumjs-util ethereumjs-abi bignumber.js --no-save");
throw new ExchangeError ('Required dependencies missing: \nnpm i ethereumjs-util ethereumjs-abi --no-save');
}
}
ethDecimals (unit = 'ether') {
const units = {
'wei': 0, // 1
'kwei': 3, // 1000
'babbage': 3, // 1000
'femtoether': 3, // 1000
'mwei': 6, // 1000000
'lovelace': 6, // 1000000
'picoether': 6, // 1000000
'gwei': 9, // 1000000000
'shannon': 9, // 1000000000
'nanoether': 9, // 1000000000
'nano': 9, // 1000000000
'szabo': 12, // 1000000000000
'microether': 12, // 1000000000000
'micro': 12, // 1000000000000
'finney': 15, // 1000000000000000
'milliether': 15, // 1000000000000000
'milli': 15, // 1000000000000000
'ether': 18, // 1000000000000000000
'kether': 21, // 1000000000000000000000
'grand': 21, // 1000000000000000000000
'mether': 24, // 1000000000000000000000000
'gether': 27, // 1000000000000000000000000000
'tether': 30, // 1000000000000000000000000000000
}
return this.safeValue (units, unit)
}
ethUnit (decimals = 18) {
const units = {
0: 'wei', // 1000000000000000000
3: 'kwei', // 1000000000000000
6: 'mwei', // 1000000000000
9: 'gwei', // 1000000000
12: 'szabo', // 1000000
15: 'finney', // 1000
18: 'ether', // 1
21: 'kether', // 0.001
24: 'mether', // 0.000001
27: 'gether', // 0.000000001
30: 'tether', // 0.000000000001
}
return this.safeValue (units, decimals)
}
fromWei (amount, unit = 'ether', decimals = 18) {
if (amount === undefined) {
return amount
}
if (decimals !== 18) {
amount = new BigNumber (amount).times (new BigNumber (10 ** (18 - decimals))).toFixed ()
} else {
amount = new BigNumber (amount).toFixed ()
}
return parseFloat (this.web3.utils.fromWei (amount, unit))
}
toWei (amount, unit = 'ether', decimals = 18) {
if (amount === undefined) {
return amount
}
if (decimals !== 18) {
amount = new BigNumber (this.numberToString (amount)).div (new BigNumber (10 ** (18 - decimals))).toFixed ()
} else {
amount = this.numberToString (amount)
}
return this.web3.utils.toWei (amount, unit)
}
soliditySha3 (array) {
const values = this.solidityValues (array);
const types = this.solidityTypes (values);
return '0x' + ethAbi.soliditySHA3 (types, values).toString ('hex')
}
solidityTypes (array) {
return array.map (value => (this.web3.utils.isAddress (value) ? 'address' : 'uint256'))
}
solidityValues (array) {
return array.map (value => (this.web3.utils.isAddress (value) ? value : (new BigNumber (value).toFixed ())))
// we only support address, uint256, and string solidity types
const encoded = []
for (const value of array) {
if (Number.isInteger (value) || value.match (/^[0-9]+$/)) {
encoded.push (this.numberToBE (this.numberToString (value), 32))
} else {
const noPrefix = Exchange.remove0xPrefix (value)
if (noPrefix.length === 40 && noPrefix.toLowerCase ().match (/^[0-9a-f]+$/)) { // check if it is an address
encoded.push (this.base16ToBinary (noPrefix))
} else {
encoded.push (this.stringToBinary (noPrefix))
}
}
}
const concated = this.binaryConcatArray (encoded)
return '0x' + this.hash (concated, 'keccak', 'hex')
}
getZeroExOrderHash (order) {
@@ -1424,15 +1385,6 @@ module.exports = class Exchange {
])).toString ('hex');
}
signZeroExOrder (order, privateKey) {
const orderHash = this.getZeroExOrderHash (order);
const signature = this.signMessage (orderHash, privateKey);
return this.extend (order, {
'orderHash': orderHash,
'ecSignature': signature, // todo fix v if needed
})
}
signZeroExOrderV2 (order, privateKey) {
const orderHash = this.getZeroExOrderHashV2 (order);
const signature = this.signMessage (orderHash, privateKey);
+9 -11
View File
@@ -31,6 +31,7 @@ module.exports =
, index
, ordered: x => x // a stub to keep assoc keys in order (in JS it does nothing, it's mostly for Python)
, unique: x => Array.from (index (x))
, arrayConcat: (a, b) => a.concat (b)
/* ............................................. */
@@ -199,7 +200,7 @@ module.exports =
return out
}
return x
}
@@ -217,22 +218,19 @@ module.exports =
/* ............................................. */
, deepExtend: function deepExtend (...xs) {
let out = undefined
for (const x of xs) {
if (isDictionary (x)) {
if (!isObject (out))
if (!isObject (out)) {
out = {}
for (const k in x)
}
for (const k in x) {
out[k] = deepExtend (out[k], x[k])
} else out = x
}
} else {
out = x
}
}
return out
}
+31 -6
View File
@@ -106,9 +106,13 @@ const decimalToPrecision = (x, roundingMode
/* handle tick size */
if (countingMode === TICK_SIZE) {
const missing = x % numPrecisionDigits
const reminder = x / numPrecisionDigits
if (reminder !== Math.floor (reminder)) {
const precisionDigitsString = decimalToPrecision (numPrecisionDigits, ROUND, 100, DECIMAL_PLACES, NO_PADDING)
const newNumPrecisionDigits = precisionFromString (precisionDigitsString)
let missing = x % numPrecisionDigits
// See: https://github.com/ccxt/ccxt/pull/6486
missing = Number (decimalToPrecision (missing, ROUND, 8, DECIMAL_PLACES, NO_PADDING));
const fpError = decimalToPrecision (missing / numPrecisionDigits, ROUND, Math.max (newNumPrecisionDigits, 8), DECIMAL_PLACES, NO_PADDING)
if (precisionFromString (fpError) !== 0) {
if (roundingMode === ROUND) {
if (x > 0) {
if (missing >= numPrecisionDigits / 2) {
@@ -127,8 +131,6 @@ const decimalToPrecision = (x, roundingMode
x = x - missing
}
}
const precisionDigitsString = decimalToPrecision (numPrecisionDigits, ROUND, 100, DECIMAL_PLACES, NO_PADDING)
const newNumPrecisionDigits = precisionFromString (precisionDigitsString)
return decimalToPrecision (x, ROUND, newNumPrecisionDigits, DECIMAL_PLACES, paddingMode);
}
@@ -282,10 +284,33 @@ const decimalToPrecision = (x, roundingMode
return String.fromCharCode (...out)
}
// toWei / fromWei
function fromWei (amount, decimals = 18) {
if (amount === undefined) {
return amount
}
const exponential = Math.floor (amount).toExponential () // wei must be whole numbers
const [ n, exponent ] = exponential.split ('e')
const newExponent = parseInt (exponent) - decimals
return parseFloat (n + 'e' + newExponent)
}
function toWei (amount, decimals = 18) {
if (amount === undefined) {
return amount
}
const exponential = parseFloat (amount).toExponential ()
const [ n, exponent ] = exponential.split ('e')
const newExponent = parseInt (exponent) + decimals
return numberToString (Math.floor (parseFloat (n + 'e' + newExponent))) // wei must be whole numbers
}
/* ------------------------------------------------------------------------ */
module.exports = {
toWei,
fromWei,
numberToString,
precisionFromString,
decimalToPrecision,
+2 -2
View File
@@ -18,7 +18,7 @@ module.exports = {
const queue = []
return Object.assign ((cost) => {
return Object.assign ((rateLimit, cost) => {
if (queue.length > cfg.maxCapacity)
throw new Error ('Backlog is over max capacity of ' + cfg.maxCapacity)
@@ -46,7 +46,7 @@ module.exports = {
const t = now ()
, elapsed = t - lastTimestamp
lastTimestamp = t
numTokens = Math.min (cfg.capacity, numTokens + elapsed * cfg.refillRate)
numTokens = Math.min (cfg.capacity, numTokens + elapsed * (1 / rateLimit))
await sleep (cfg.delay)
}
running = false
+2
View File
@@ -3,6 +3,7 @@
/* ------------------------------------------------------------------------ */
const isNumber = Number.isFinite
, isInteger = Number.isInteger
, isArray = Array.isArray
, hasProps = o => ((o !== undefined) && (o !== null))
, isString = s => (typeof s === 'string')
@@ -25,6 +26,7 @@ const asFloat = x => ((isNumber (x) || isString (x)) ? parseFloat (x) : Na
module.exports = {
isNumber
, isInteger
, isArray
, isObject
, isString