Skip to content

Commit 3f69a6f

Browse files
committed
Request and save rates by alphabetical currency pairs
Reduces impact of spam attacks that requests rates in every permutation
1 parent b395a19 commit 3f69a6f

File tree

1 file changed

+33
-4
lines changed

1 file changed

+33
-4
lines changed

src/exchangeRateRouter.ts

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { mul } from 'biggystring'
1+
import { div, mul } from 'biggystring'
22
import { asArray, asMaybe, asObject, asOptional, asString } from 'cleaners'
33
import express from 'express'
44
import nano from 'nano'
@@ -7,7 +7,7 @@ import promisify from 'promisify-node'
77

88
import { config } from './config'
99
import { REDIS_COINRANK_KEY_PREFIX } from './constants'
10-
import { asReturnGetRate, getExchangeRates } from './rates'
10+
import { asReturnGetRate, getExchangeRates, PRECISION } from './rates'
1111
import {
1212
asCoinrankAssetReq,
1313
asCoinrankReq,
@@ -293,13 +293,42 @@ const queryExchangeRates: express.RequestHandler = async (
293293
return next()
294294
}
295295

296+
const flippedAssets: { [key: string]: true } = {}
297+
298+
// To prevent redudant rate requests and storage, sort the assets in alphabetical order
299+
// ie. iso:USD_BTC -> BTC_iso:USD. Mark any flipped assets with the flippedAssets flag true
300+
// so we can flip them back later.
301+
const normalizedRequestedRates = exReq.requestedRates.data.map(req => {
302+
const [assetA, assetB] = req.currency_pair.split('_')
303+
if (assetA > assetB) {
304+
const flippedPair = `${assetB}_${assetA}`
305+
flippedAssets[`${flippedPair}_${req.date}`] = true
306+
return { ...req, currency_pair: flippedPair }
307+
}
308+
return req
309+
})
310+
296311
try {
297312
const queriedRates = await getExchangeRates(
298-
exReq.requestedRates.data,
313+
normalizedRequestedRates,
299314
dbRates
300315
)
316+
const unflippedRates = queriedRates.data.map(rate => {
317+
const key = `${rate.currency_pair}_${rate.date}`
318+
if (flippedAssets[key] === true) {
319+
delete flippedAssets[key]
320+
const [assetA, assetB] = rate.currency_pair.split('_')
321+
const unflippedPair = `${assetB}_${assetA}`
322+
if (rate.exchangeRate != null) {
323+
const unflippedRate = div('1', rate.exchangeRate, PRECISION)
324+
rate.exchangeRate = unflippedRate
325+
}
326+
return { ...rate, currency_pair: unflippedPair }
327+
}
328+
return rate
329+
})
301330
exReq.requestedRatesResult = {
302-
data: [...(exReq.requestedRatesResult?.data ?? []), ...queriedRates.data],
331+
data: [...(exReq.requestedRatesResult?.data ?? []), ...unflippedRates],
303332
documents: [...queriedRates.documents] // TODO: Change data type since the douch docs aren't needed after this
304333
}
305334
} catch (e) {

0 commit comments

Comments
 (0)