From eb6d4f8b6bd3a470739d9e21da4641805ce641f4 Mon Sep 17 00:00:00 2001 From: ns212 Date: Tue, 26 Sep 2023 21:51:03 +0000 Subject: [PATCH 01/12] api: refactor the market data api --- api/market_data.js | 103 +++++++++++++++++++++++++++++++++++++++++++ api/market_data.py | 106 --------------------------------------------- vercel.json | 2 +- 3 files changed, 104 insertions(+), 107 deletions(-) create mode 100644 api/market_data.js delete mode 100644 api/market_data.py diff --git a/api/market_data.js b/api/market_data.js new file mode 100644 index 0000000000..f5254de8b1 --- /dev/null +++ b/api/market_data.js @@ -0,0 +1,103 @@ +// Dia to Coingecko names +const tickers = { + "Tether USD": "tether", + "Acala USD": "acala-dollar", + "BNB": "binancecoin", + "Wrapped BTC": "wrapped-bitcoin", + "Dai Stablecoin": "dai", + "Ether": "ethereum", + "USD Coin": "usd-coin", + "tBTC v2": "tbtc" +} + +// Coingecko to Dia asset ids +const dia_assets = { + "bitcoin": "/Bitcoin/0x0000000000000000000000000000000000000000", + "ethereum": "/Ethereum/0x0000000000000000000000000000000000000000", + "interlay": "/Interlay/0x0000000000000000000000000000000000000000", + "polkadot": "/Polkadot/0x0000000000000000000000000000000000000000", + "kusama": "/Kusama/0x0000000000000000000000000000000000000000", + "kintsugi": "/Kintsugi/Token:KINT", + "acala-dollar": "/Acala/Token:AUSD", + "karura": "/Bifrost/518", + "tether": "/Ethereum/0xdAC17F958D2ee523a2206206994597C13D831ec7", + "voucher-dot": "/Bifrost-polkadot/2304", + "binancecoin": "/Ethereum/0xB8c77482e45F1F44dE1745F52C74426C631bDD52", + "bnb": "/Ethereum/0xB8c77482e45F1F44dE1745F52C74426C631bDD52", + "tbtc": "/Ethereum/0x18084fbA666a33d37592fA2633fD49a74DD93a88", + "dai": "/Ethereum/0x6B175474E89094C44Da98b954EedeAC495271d0F", + "moonbeam": "/Moonbeam/0x0000000000000000000000000000000000000000", + "usd-coin": "/Ethereum/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "wrapped-bitcoin": "/Ethereum/0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599" +} + +const fetchDiaAsset = async (asset) => { + try { + if (!dia_assets[asset]) { + console.log('Missing DIA asset: ', asset) + return coingecko({ ids: [asset], vs_currencies: ["usd"] }) + } + const url = 'https://api.diadata.org/v1/assetQuotation' + dia_assets[asset] + const response = await fetch(url, { headers: { "accept": "application/json" } }) + if (!response.ok) { + throw new Error(response.status) + } + const json = await response.json() + + // optionally rename the ticker + const name = (tickers[json.Name] ?? json.Name).toLowerCase() + return { + [name]: { + 'usd': json.Price + } + } + } catch (error) { + console.log(error) + } +} + +const dia = async (args) => { + const assets = args.ids.split(',') + + return Promise + .all(assets.map(x => fetchDiaAsset(x))) + .then(x => x.reduce((map, obj) => { + // we need to convert the list to an object + const k = Object.keys(obj)[0] + map[k] = obj[k] + return map + }, {})) +} + +const coingecko = async (args) => { + const url = 'https://api.coingecko.com/api/v3/simple/price?' + new URLSearchParams(args) + const response = await fetch(url, { headers: { "accept": "application/json" } }) + return await response.json() +} + +const fetchPrices = (priceSource, args) => { + if (priceSource === 'coingecko') { + return coingecko(args) + } else if (priceSource === 'dia') { + return dia(args) + } else { + try { + return dia(args) + } catch (error) { + console.log(error) + return coingecko(args) + } + } +} + +export default async function (request, response) { + const args = request.query + const priceSource = args['price-source'] + + const resp = fetchPrices(priceSource, args) + return response + .status(200) + .setHeader("content-type", "application/json") + .setHeader("cache-control", "public, maxage=0, s-maxage=300") + .json(resp) +} diff --git a/api/market_data.py b/api/market_data.py deleted file mode 100644 index 6c2c7eeae3..0000000000 --- a/api/market_data.py +++ /dev/null @@ -1,106 +0,0 @@ -from flask import Flask, request, jsonify -from flask_cors import CORS -import requests -import os - -app = Flask(__name__) -CORS(app) - -api_key = os.environ.get("CG_API_KEY") - -tickers = { - "Tether USD": "tether", - "Acala USD": "acala-dollar" -} - -# map coingecko ids to dia ids -dia_assets = { - "bitcoin": "/Bitcoin/0x0000000000000000000000000000000000000000", - "ethereum": "/Ethereum/0x0000000000000000000000000000000000000000", - "interlay": "/Interlay/0x0000000000000000000000000000000000000000", - "polkadot": "/Polkadot/0x0000000000000000000000000000000000000000", - "kusama": "/Kusama/0x0000000000000000000000000000000000000000", - "kintsugi": "/Kintsugi/Token:KINT", - "acala-dollar": "/Acala/Token:AUSD", - "karura": "/Bifrost/518", - "tether": "/Ethereum/0xdAC17F958D2ee523a2206206994597C13D831ec7", - "voucher-dot": "/Bifrost-polkadot/2304", - "binancecoin": "/Ethereum/0xB8c77482e45F1F44dE1745F52C74426C631bDD52", - "bnb": "/Ethereum/0xB8c77482e45F1F44dE1745F52C74426C631bDD52", - "tbtc": "/Ethereum/0x18084fbA666a33d37592fA2633fD49a74DD93a88", - "dai": "/Ethereum/0x6B175474E89094C44Da98b954EedeAC495271d0F", -} - -@app.after_request -def add_header(response): - response.cache_control.max_age = 0 - response.cache_control.s_maxage = 300 - return response - -def coingecko(args): - headers_dict = { - "content-type": "application/json", - "accept": "application/json" - } - url = "https://api.coingecko.com/api/v3/simple/price" - resp = requests.get(url, params=args, headers=headers_dict) - data = resp.json() - return data - -def dia(asset): - headers_dict = { - "content-type": "application/json", - "accept": "application/json" - } - - url = "https://api.diadata.org/v1/assetQuotation" - try: - url += dia_assets[asset] - resp = requests.get(url, headers=headers_dict) - data = resp.json() - - # optionally rename the ticker - ticker = tickers.get(data["Name"], data["Name"]).lower() - - return { - ticker: { - "usd": data["Price"], - } - } - except KeyError: - try: - return coingecko({"ids": [asset], "vs_currencies": ["usd"]}) - except Exception as e: - print("Coingecko error", e) - return { asset: None } - - -@app.route("/marketdata/price", methods=["GET"]) -def get_price(): - args = request.args - - price_source = args.get('price-source') - - data = {} - - def _dia(): - ticker_ids = args["ids"].split(",") - for ticker_id in ticker_ids: - data.update(dia(ticker_id)) - - if price_source == "dia": - _dia() - elif price_source == "coingecko": - data = coingecko(args) - else: - try: - _dia() - except Exception as e: - print("Error", e) - data = coingecko(args) - - return jsonify(data) - - -if __name__ == "__main__": - app.run() diff --git a/vercel.json b/vercel.json index 99b54b6e47..aa83fe8074 100644 --- a/vercel.json +++ b/vercel.json @@ -20,7 +20,7 @@ }, { "source": "/marketdata/(.*)", - "destination": "/api/market_data.py" + "destination": "/api/market_data.js" }, { "source": "/terms/(.*)", From 03643722b99f9fb9315d77b7d0a82298d866322d Mon Sep 17 00:00:00 2001 From: ns212 Date: Tue, 26 Sep 2023 21:59:06 +0000 Subject: [PATCH 02/12] api: refactor the market data api --- api/market_data.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/market_data.js b/api/market_data.js index f5254de8b1..14d7736275 100644 --- a/api/market_data.js +++ b/api/market_data.js @@ -94,7 +94,7 @@ export default async function (request, response) { const args = request.query const priceSource = args['price-source'] - const resp = fetchPrices(priceSource, args) + const resp = await fetchPrices(priceSource, args) return response .status(200) .setHeader("content-type", "application/json") From 97668c6002f8ecb8752f9a60032922d7c955303f Mon Sep 17 00:00:00 2001 From: ns212 Date: Tue, 26 Sep 2023 22:26:40 +0000 Subject: [PATCH 03/12] api: refactor the market data api --- vercel.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/vercel.json b/vercel.json index aa83fe8074..ca05a8c330 100644 --- a/vercel.json +++ b/vercel.json @@ -7,6 +7,10 @@ "api/terms.js": { "memory": 256, "maxDuration": 10 + }, + "api/market_data.js": { + "memory": 128, + "maxDuration": 5 } }, "rewrites": [ From 8323c38098c2b786baad5206e26cdc58a97b966a Mon Sep 17 00:00:00 2001 From: Tom Jeatt Date: Wed, 27 Sep 2023 11:08:47 +0100 Subject: [PATCH 04/12] wip: add log --- src/hooks/api/vaults/use-get-vault-data.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hooks/api/vaults/use-get-vault-data.tsx b/src/hooks/api/vaults/use-get-vault-data.tsx index 74e14d086b..28f23103cd 100644 --- a/src/hooks/api/vaults/use-get-vault-data.tsx +++ b/src/hooks/api/vaults/use-get-vault-data.tsx @@ -33,6 +33,7 @@ const useGetVaultData = ({ address }: { address: string }): VaultOverview | unde // const [queryError, setQueryError] = useState(undefined); const prices = useGetPrices(); + console.log('prices', prices); const vaultsResponseData = useGetVaults({ address }); // useErrorHandler(queryError); From 7eecb0232c6a4bcc70cd15cc79232e88b8561ed0 Mon Sep 17 00:00:00 2001 From: Tom Jeatt Date: Wed, 27 Sep 2023 11:22:25 +0100 Subject: [PATCH 05/12] wip: hardcode value to run against market data api --- src/hooks/api/use-get-prices.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hooks/api/use-get-prices.tsx b/src/hooks/api/use-get-prices.tsx index 8cacd07989..2d64d82583 100644 --- a/src/hooks/api/use-get-prices.tsx +++ b/src/hooks/api/use-get-prices.tsx @@ -14,7 +14,8 @@ import { useGetCurrencies } from './use-get-currencies'; // MEMO: Returns `undefined` for currencies without coingecko ID. const getCoingeckoId = (currency: CurrencyExt) => { if (isForeignAsset(currency)) { - return currency.foreignAsset.coingeckoId; + // This is a temporary fix + return currency.foreignAsset.coingeckoId || 'voucher-dot'; } return COINGECKO_ID_BY_CURRENCY_TICKER[currency.ticker]; }; From 186e0cb93cec26312211578797e81adcef50a4fb Mon Sep 17 00:00:00 2001 From: Tom Jeatt Date: Wed, 27 Sep 2023 11:34:49 +0100 Subject: [PATCH 06/12] wip: try setting asset name --- api/market_data.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/api/market_data.js b/api/market_data.js index 14d7736275..78417b9238 100644 --- a/api/market_data.js +++ b/api/market_data.js @@ -7,7 +7,8 @@ const tickers = { "Dai Stablecoin": "dai", "Ether": "ethereum", "USD Coin": "usd-coin", - "tBTC v2": "tbtc" + "tBTC v2": "tbtc", + "voucher dot": 'voucher-dot' } // Coingecko to Dia asset ids From 0e7b63766b1027f96433d07f178a7327b38f80d6 Mon Sep 17 00:00:00 2001 From: Tom Jeatt Date: Wed, 27 Sep 2023 11:43:36 +0100 Subject: [PATCH 07/12] fix: casing --- api/market_data.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/market_data.js b/api/market_data.js index 78417b9238..80c40d3a1f 100644 --- a/api/market_data.js +++ b/api/market_data.js @@ -8,7 +8,7 @@ const tickers = { "Ether": "ethereum", "USD Coin": "usd-coin", "tBTC v2": "tbtc", - "voucher dot": 'voucher-dot' + "Voucher Dot": 'voucher-dot' } // Coingecko to Dia asset ids From 8beefa677fbb7aede0c49473c0e3ee23360acec2 Mon Sep 17 00:00:00 2001 From: Tom Jeatt Date: Wed, 27 Sep 2023 11:56:14 +0100 Subject: [PATCH 08/12] chore: add vKSM ids --- api/market_data.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/api/market_data.js b/api/market_data.js index 80c40d3a1f..a34dd6c28f 100644 --- a/api/market_data.js +++ b/api/market_data.js @@ -8,7 +8,8 @@ const tickers = { "Ether": "ethereum", "USD Coin": "usd-coin", "tBTC v2": "tbtc", - "Voucher Dot": 'voucher-dot' + "Voucher Dot": 'voucher-dot', + "Voucher KSM": "voucher-ksm" } // Coingecko to Dia asset ids @@ -23,6 +24,7 @@ const dia_assets = { "karura": "/Bifrost/518", "tether": "/Ethereum/0xdAC17F958D2ee523a2206206994597C13D831ec7", "voucher-dot": "/Bifrost-polkadot/2304", + "voucher-ksm": "/Bifrost/260", "binancecoin": "/Ethereum/0xB8c77482e45F1F44dE1745F52C74426C631bDD52", "bnb": "/Ethereum/0xB8c77482e45F1F44dE1745F52C74426C631bDD52", "tbtc": "/Ethereum/0x18084fbA666a33d37592fA2633fD49a74DD93a88", From 8acf5b0931c202c85c2d1783b32b4dd882961069 Mon Sep 17 00:00:00 2001 From: Tom Jeatt Date: Wed, 27 Sep 2023 12:05:22 +0100 Subject: [PATCH 09/12] fix: handle VDOT and VKSM --- src/hooks/api/use-get-prices.tsx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/hooks/api/use-get-prices.tsx b/src/hooks/api/use-get-prices.tsx index 2d64d82583..6cc9f3184b 100644 --- a/src/hooks/api/use-get-prices.tsx +++ b/src/hooks/api/use-get-prices.tsx @@ -14,8 +14,17 @@ import { useGetCurrencies } from './use-get-currencies'; // MEMO: Returns `undefined` for currencies without coingecko ID. const getCoingeckoId = (currency: CurrencyExt) => { if (isForeignAsset(currency)) { - // This is a temporary fix - return currency.foreignAsset.coingeckoId || 'voucher-dot'; + // TODO: This is a temporary fix to force V[DOT/KSM] prices. We need to refactor the lib to return an id + // even when a CoinGecko id doesn't exist. We also need to remove references to CoinGecko ids; this + // doesn't make sense/is very confusing now that we use DIA as our primary price source. + switch (currency) { + case currency.ticker === 'VDOT': + return 'voucher-dot'; + case currency.ticker === 'VKSM': + return 'voucher-ksm'; + default: + return currency.foreignAsset.coingeckoId; + } } return COINGECKO_ID_BY_CURRENCY_TICKER[currency.ticker]; }; From dd72523f61cb5af041549bbfdfb8e46446a9f4d7 Mon Sep 17 00:00:00 2001 From: Tom Jeatt Date: Wed, 27 Sep 2023 12:23:16 +0100 Subject: [PATCH 10/12] typo: quotation marks --- api/market_data.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/market_data.js b/api/market_data.js index a34dd6c28f..59f3664ce7 100644 --- a/api/market_data.js +++ b/api/market_data.js @@ -8,7 +8,7 @@ const tickers = { "Ether": "ethereum", "USD Coin": "usd-coin", "tBTC v2": "tbtc", - "Voucher Dot": 'voucher-dot', + "Voucher Dot": "voucher-dot", "Voucher KSM": "voucher-ksm" } From d24dc895b799b89e12aa8c0f3c47a8cbb991c287 Mon Sep 17 00:00:00 2001 From: Tom Jeatt Date: Wed, 27 Sep 2023 13:05:05 +0100 Subject: [PATCH 11/12] chore: fix switch statement and remove console log --- src/hooks/api/use-get-prices.tsx | 7 ++++--- src/hooks/api/vaults/use-get-vault-data.tsx | 2 -- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/hooks/api/use-get-prices.tsx b/src/hooks/api/use-get-prices.tsx index 6cc9f3184b..a9ba628c69 100644 --- a/src/hooks/api/use-get-prices.tsx +++ b/src/hooks/api/use-get-prices.tsx @@ -17,10 +17,10 @@ const getCoingeckoId = (currency: CurrencyExt) => { // TODO: This is a temporary fix to force V[DOT/KSM] prices. We need to refactor the lib to return an id // even when a CoinGecko id doesn't exist. We also need to remove references to CoinGecko ids; this // doesn't make sense/is very confusing now that we use DIA as our primary price source. - switch (currency) { - case currency.ticker === 'VDOT': + switch (currency.ticker) { + case 'VDOT': return 'voucher-dot'; - case currency.ticker === 'VKSM': + case 'VKSM': return 'voucher-ksm'; default: return currency.foreignAsset.coingeckoId; @@ -32,6 +32,7 @@ const getCoingeckoId = (currency: CurrencyExt) => { const composeIds = (currencies: CurrencyExt[]): string => currencies.reduce((acc, currency) => { const coingeckoId = getCoingeckoId(currency); + console.log('coingeckoId', coingeckoId); if (!coingeckoId) { return acc; } diff --git a/src/hooks/api/vaults/use-get-vault-data.tsx b/src/hooks/api/vaults/use-get-vault-data.tsx index 28f23103cd..ee5a05bab7 100644 --- a/src/hooks/api/vaults/use-get-vault-data.tsx +++ b/src/hooks/api/vaults/use-get-vault-data.tsx @@ -33,8 +33,6 @@ const useGetVaultData = ({ address }: { address: string }): VaultOverview | unde // const [queryError, setQueryError] = useState(undefined); const prices = useGetPrices(); - console.log('prices', prices); - const vaultsResponseData = useGetVaults({ address }); // useErrorHandler(queryError); From e56eef08f8ce38dd54c3fb960cf30c8be5596c28 Mon Sep 17 00:00:00 2001 From: Tom Jeatt Date: Wed, 27 Sep 2023 13:40:40 +0100 Subject: [PATCH 12/12] fix: revert change --- src/hooks/api/vaults/use-get-vault-data.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hooks/api/vaults/use-get-vault-data.tsx b/src/hooks/api/vaults/use-get-vault-data.tsx index ee5a05bab7..74e14d086b 100644 --- a/src/hooks/api/vaults/use-get-vault-data.tsx +++ b/src/hooks/api/vaults/use-get-vault-data.tsx @@ -33,6 +33,7 @@ const useGetVaultData = ({ address }: { address: string }): VaultOverview | unde // const [queryError, setQueryError] = useState(undefined); const prices = useGetPrices(); + const vaultsResponseData = useGetVaults({ address }); // useErrorHandler(queryError);