|
| 1 | +import { asCouchDoc, syncedDocument } from 'edge-server-tools' |
1 | 2 | import { HttpResponse } from 'serverlet' |
2 | 3 | import { ExpressRequest } from 'serverlet/express' |
3 | 4 |
|
4 | 5 | import { ONE_MINUTE } from './constants' |
5 | 6 | import { getRates } from './getRates' |
| 7 | +import { dbSettings } from './providers/couch' |
6 | 8 | import { |
| 9 | + asCrossChainMapping, |
7 | 10 | asIncomingGetRatesParams, |
| 11 | + asStringNullMap, |
| 12 | + CrossChainMapping, |
8 | 13 | GetRatesParams, |
9 | 14 | IncomingGetRatesParams |
10 | 15 | } from './types' |
| 16 | +import { toCryptoKey } from './utils' |
11 | 17 |
|
12 | 18 | const fixIncomingGetRatesParams = ( |
13 | 19 | rawParams: IncomingGetRatesParams, |
@@ -49,16 +55,91 @@ const fixIncomingGetRatesParams = ( |
49 | 55 | return params as GetRatesParams |
50 | 56 | } |
51 | 57 |
|
| 58 | +// Map incoming crypto assets to their cross-chain canonical versions |
| 59 | +// Also return a mapping from each original asset key to its canonical key |
| 60 | +const applyCrossChainMappings = ( |
| 61 | + params: GetRatesParams, |
| 62 | + mapping: CrossChainMapping |
| 63 | +): { |
| 64 | + mappedParams: GetRatesParams |
| 65 | + originalToCanonicalKey: Map<string, string> |
| 66 | +} => { |
| 67 | + const originalToCanonicalKey = new Map<string, string>() |
| 68 | + const mappedCrypto = params.crypto.map(c => { |
| 69 | + const originalKey = toCryptoKey(c.asset) |
| 70 | + const cross = mapping[originalKey] |
| 71 | + if (cross == null) { |
| 72 | + originalToCanonicalKey.set(originalKey, originalKey) |
| 73 | + return c |
| 74 | + } |
| 75 | + const canonicalAsset = { |
| 76 | + pluginId: cross.destChain, |
| 77 | + tokenId: cross.tokenId |
| 78 | + } |
| 79 | + const canonicalKey = toCryptoKey(canonicalAsset) |
| 80 | + originalToCanonicalKey.set(originalKey, canonicalKey) |
| 81 | + return { |
| 82 | + ...c, |
| 83 | + asset: canonicalAsset |
| 84 | + } |
| 85 | + }) |
| 86 | + return { |
| 87 | + mappedParams: { ...params, crypto: mappedCrypto }, |
| 88 | + originalToCanonicalKey |
| 89 | + } |
| 90 | +} |
| 91 | + |
| 92 | +const crosschainMappings = syncedDocument( |
| 93 | + 'crosschain:automated', |
| 94 | + asCrossChainMapping |
| 95 | +) |
| 96 | +crosschainMappings.sync(dbSettings).catch(e => { |
| 97 | + console.error('crosschainMappings sync error', e) |
| 98 | +}) |
| 99 | + |
52 | 100 | export const ratesV3 = async ( |
53 | 101 | request: ExpressRequest |
54 | 102 | ): Promise<HttpResponse> => { |
55 | 103 | try { |
56 | 104 | const rightNow = new Date() |
57 | 105 | const params = fixIncomingGetRatesParams(request.req.body, rightNow) |
58 | | - const result = await getRates(params, rightNow) |
| 106 | + |
| 107 | + // Map all incoming crypto assets to their canonical versions |
| 108 | + const { mappedParams, originalToCanonicalKey } = applyCrossChainMappings( |
| 109 | + params, |
| 110 | + crosschainMappings.doc |
| 111 | + ) |
| 112 | + const result = await getRates(mappedParams, rightNow) |
| 113 | + |
| 114 | + // Build a quick lookup from canonical key + isoDate -> rate |
| 115 | + const canonicalLookup = new Map<string, number>() |
| 116 | + for (const r of result.crypto) { |
| 117 | + if (r.rate == null) continue |
| 118 | + const key = `${r.isoDate.toISOString()}_${toCryptoKey(r.asset)}` |
| 119 | + canonicalLookup.set(key, r.rate) |
| 120 | + } |
| 121 | + |
| 122 | + // Rebuild crypto results for the original requested assets |
| 123 | + const remappedCrypto = params.crypto.map(c => { |
| 124 | + const originalKey = toCryptoKey(c.asset) |
| 125 | + const maybeCanonical = originalToCanonicalKey.get(originalKey) |
| 126 | + const canonicalKey = maybeCanonical ?? originalKey |
| 127 | + const lookupKey = `${c.isoDate.toISOString()}_${canonicalKey}` |
| 128 | + const rate = canonicalLookup.get(lookupKey) |
| 129 | + return { |
| 130 | + isoDate: c.isoDate, |
| 131 | + asset: c.asset, |
| 132 | + rate |
| 133 | + } |
| 134 | + }) |
| 135 | + |
59 | 136 | return { |
60 | 137 | headers: { 'content-type': 'application/json' }, |
61 | | - body: JSON.stringify(result) |
| 138 | + body: JSON.stringify({ |
| 139 | + targetFiat: params.targetFiat, |
| 140 | + crypto: remappedCrypto, |
| 141 | + fiat: result.fiat |
| 142 | + }) |
62 | 143 | } |
63 | 144 | } catch (e) { |
64 | 145 | return { |
|
0 commit comments