From 887efdadf75e207fe22ec82c613319acaac043f8 Mon Sep 17 00:00:00 2001 From: emidev98 Date: Fri, 16 Feb 2024 16:19:00 +0200 Subject: [PATCH] feat: whale tokens --- app/page.tsx | 106 +++++++++++++------- components/Dropdown.tsx | 13 ++- components/Table.tsx | 56 ++--------- const/chains.ts | 44 +++++--- const/table.tsx | 2 +- lib/{AllianceQuery.ts => QueryAlliances.ts} | 0 lib/QueryInflation.ts | 38 +++++++ lib/QueryLP.ts | 41 ++++++++ models/AllianceFunctions.ts | 78 -------------- models/Chain.ts | 34 +++++-- models/LPResponse.ts | 16 +++ models/Prices.ts | 11 +- models/TableState.ts | 48 +++++++-- styles/Dropdown.module.css | 1 + styles/TableIcon.module.css | 8 +- 15 files changed, 295 insertions(+), 201 deletions(-) rename lib/{AllianceQuery.ts => QueryAlliances.ts} (100%) create mode 100644 lib/QueryInflation.ts create mode 100644 lib/QueryLP.ts delete mode 100644 models/AllianceFunctions.ts create mode 100644 models/LPResponse.ts diff --git a/app/page.tsx b/app/page.tsx index 18fe310..a9c7d79 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -5,47 +5,88 @@ import Card from "../components/Card"; import Kpi from "../components/Kpi"; import Table from "../components/Table"; import { DEFAULT_CHAIN, SUPPORTED_CHAINS } from "../const/chains"; -import { QueryAlliances } from "../lib/AllianceQuery"; -import { AllianceAsset } from "@terra-money/feather.js/dist/client/lcd/api/AllianceAPI"; +import { QueryAlliances } from "../lib/QueryAlliances"; import Link from "next/link"; import { useSearchParams, useRouter } from "next/navigation"; import { Suspense, useEffect, useState } from "react"; -import { mergePrices, Prices, TerraPriceServerResponse } from "../models/Prices"; +import { Prices, QueryAndMergePrices } from "../models/Prices"; import { Kpis } from "../const/kpis"; +import { LCD } from "../models/LCDConfig"; +import TableState from "../models/TableState"; +import { GetInflationEndpoint, ParseInflation } from "../lib/QueryInflation"; +import { QueryLP } from "../lib/QueryLP"; +import { Chain } from "../models/Chain"; export default function Home() { - const [prices, setPrices] = useState({}); - const [data, setData] = useState(undefined); const params = useSearchParams(); - let selectedChain = SUPPORTED_CHAINS[params.get("selected") ?? DEFAULT_CHAIN]; const router = useRouter(); - if (selectedChain === undefined) { - selectedChain = SUPPORTED_CHAINS[DEFAULT_CHAIN]; - router.push(`?selected=${SUPPORTED_CHAINS[DEFAULT_CHAIN].id}`) - } + const [tableState, setTableState] = useState(null); + const [selectedChain, setSelectedChain] = useState(undefined); + const [prices, setPrices] = useState({}); + const [isLoading, setIsLoading] = useState(true); useEffect(() => { - setData(undefined); - (async () => { - // If prices are not loaded, load them from the API(s) - // Otherwise, use the cached prices - if (Object.keys(prices).length === 0) { - const res = await Promise.all([ - fetch("https://price.api.tfm.com/tokens/?limit=1500"), - fetch("https://pisco-price-server.terra.dev/latest") - ]); - const [tfmPrices, terraOraclePrices]: [Prices, TerraPriceServerResponse] = await Promise.all([res[0].json(), res[1].json()]); - let prices = mergePrices(tfmPrices, terraOraclePrices); + const selectedParamIsSupported = SUPPORTED_CHAINS[params.get("selected") as any]; + if (selectedParamIsSupported) { + setSelectedChain(SUPPORTED_CHAINS[params.get("selected") as string]); + } else { + setSelectedChain(SUPPORTED_CHAINS[DEFAULT_CHAIN]) + router.push(`?selected=${SUPPORTED_CHAINS[DEFAULT_CHAIN].id}`); + } + }, [params]) + + useEffect(() => { + if (selectedChain) { + setIsLoading(true); + (async () => { + // Load the prices only the first time a user lands on + // the page, then use the prices from the state. + // + // NOTE: the variable is not being shadowed because otherwise + // the first load will result on 0 prices. + const _prices = Object.keys(prices).length === 0 ? await QueryAndMergePrices() : prices; + setPrices(_prices); + + // Query selectedChain alliances info + const _allianceAssetRes = await QueryAlliances(selectedChain).catch(() => []); - setPrices(prices); - } + // Query chain info on parallel to speed up the loading time + let chainInfoRes = await Promise.all([ + LCD.alliance.params(selectedChain.id), + LCD.bank.supplyByDenom(selectedChain.id, selectedChain.bondDenom), + GetInflationEndpoint(selectedChain.id), + ]).catch((e) => { + console.error(e) + return [] + }); - const res = await QueryAlliances(selectedChain).catch(() => []); + // Query this info in parallel to speed up the loading time + // because the requested data is independent from each other + const [inflation, allianceCoins] = await Promise.all([ + ParseInflation(selectedChain.id, chainInfoRes[2]), + QueryLP(selectedChain.allianceCoins) + ]) - setData(res); - })(); - }, [params]); + selectedChain.allianceCoins = allianceCoins; + + // If no error occured, set the data + // otherwise, keep the default data + if (chainInfoRes != undefined) { + let tableState = new TableState( + selectedChain, + _allianceAssetRes, + _prices, + chainInfoRes[0].params, + chainInfoRes[1], + inflation, + ); + setTableState(tableState) + } + setIsLoading(false); + })(); + } + }, [selectedChain]); return (
@@ -72,7 +113,7 @@ export default function Home() { {" "}Alliance assets on Terra -
+
{Kpis.map((kpi) => )}
@@ -81,17 +122,10 @@ export default function Home() {
}> - +
- {/*
- - }> - - - -
*/} ); diff --git a/components/Dropdown.tsx b/components/Dropdown.tsx index 8e3e771..17e2ea3 100644 --- a/components/Dropdown.tsx +++ b/components/Dropdown.tsx @@ -1,6 +1,6 @@ "use client"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import styles from "../styles/Dropdown.module.css"; import { useRouter, useSearchParams } from "next/navigation"; import { DEFAULT_CHAIN, SUPPORTED_CHAINS } from "../const/chains"; @@ -8,9 +8,18 @@ import { DEFAULT_CHAIN, SUPPORTED_CHAINS } from "../const/chains"; export default function Dropdown() { const params = useSearchParams(); const [show, setShow] = useState(false); - const [selected, setSelected] = useState(SUPPORTED_CHAINS[params.get("selected") ?? DEFAULT_CHAIN]); + const [selected, setSelected] = useState(); const router = useRouter(); + useEffect(() => { + if (SUPPORTED_CHAINS[params.get("selected") as any]) { + setSelected(SUPPORTED_CHAINS[params.get("selected") as string]); + } + else { + setSelected(SUPPORTED_CHAINS[DEFAULT_CHAIN]); + } + }, []) + return (
(TableState.default(selectedChain)); - - useEffect(() => { - (async () => { - // Query the data on paralel to speed up the loading time - const res = await Promise.all([ - LCD.alliance.params(selectedChain.id), - LCD.bank.supplyByDenom(selectedChain.id, selectedChain.bondDenom), - LCD.mint.inflation(selectedChain.id), - ]).catch((e) => { console.error(e) }); - - // If no error occured, set the data - // otherwise, keep the default data - if (res != undefined) { - let tableState = new TableState( - selectedChain, - allianceAssets, - prices, - res[0].params, - res[1], - res[2], - ); - setTableState(tableState) - } - })(); - }, [allianceAssets, selectedChain]); - +export default function Table({ tableState, isLoading}: TableProps) { return ( - +
@@ -56,7 +22,7 @@ export default function Table({ selectedChain, allianceAssets, prices }: TablePr
{v.title} {v.tooltip ? ( - + Info ) : null} @@ -70,11 +36,11 @@ export default function Table({ selectedChain, allianceAssets, prices }: TablePr
- - - - - + + + + + ))} diff --git a/const/chains.ts b/const/chains.ts index 3f14358..129f2e7 100644 --- a/const/chains.ts +++ b/const/chains.ts @@ -15,13 +15,11 @@ export const SUPPORTED_CHAINS: { [key: string]: Chain } = { name: "ampLuna", priceKey: "terra1ecgazyd0waaj3g7l9cmy5gulhxkps2gmxu9ghducvuypjq68mq2s5lvsct", icon: "https://raw.githubusercontent.com/terra-money/station-assets/main/img/coins/ampLuna.svg", - color: "#324ab2", }, "ibc/FBEE20115530F474F8BBE1460DA85437C3FBBFAF4A5DEBD71CA6B9C40559A161": { name: "stLuna", priceKey: "ibc/08095CEDEA29977C9DD0CE9A48329FDA622C183359D5F90CF04CC4FF80CBE431", icon: "https://raw.githubusercontent.com/terra-money/station-assets/main/img/coins/stLUNA.svg", - color: "#fb0174", }, }, }), @@ -41,34 +39,45 @@ export const SUPPORTED_CHAINS: { [key: string]: Chain } = { name: "ampLuna", priceKey: "terra1ecgazyd0waaj3g7l9cmy5gulhxkps2gmxu9ghducvuypjq68mq2s5lvsct", icon: "https://raw.githubusercontent.com/terra-money/station-assets/main/img/coins/ampLuna.svg", - color: "#324ab2", }, "ibc/40C29143BF4153B365089E40E437B7AA819672646C45BB0A5F1E10915A0B6708": { name: "bLuna", priceKey: "terra17aj4ty4sz4yhgm08na8drc0v03v2jwr3waxcqrwhajj729zhl7zqnpc0ml", icon: "https://raw.githubusercontent.com/terra-money/station-assets/main/img/coins/bLuna.png", - color: "#ff7500", + }, + "factory/migaloo1axtz4y7jyvdkkrflknv9dcut94xr5k8m6wete4rdrw4fuptk896su44x2z/uLP": { + name: "WHALE/wBTC", + lpInfo: { + contractAddr: "migaloo1axtz4y7jyvdkkrflknv9dcut94xr5k8m6wete4rdrw4fuptk896su44x2z", + tokensPriceKey: ["WHALE", "WBTC"], + tokensDecimals: [6, 8], + }, + icon: [ + "https://raw.githubusercontent.com/terra-money/station-assets/main/img/coins/Whale.svg", + "https://raw.githubusercontent.com/terra-money/station-assets/main/img/coins/wbtc.svg", + ], }, "factory/migaloo1xv4ql6t6r8zawlqn2tyxqsrvjpmjfm6kvdfvytaueqe3qvcwyr7shtx0hj/uLP": { - name: "USDC-WHALE-LP", - priceKey: "factory/migaloo1xv4ql6t6r8zawlqn2tyxqsrvjpmjfm6kvdfvytaueqe3qvcwyr7shtx0hj/uLP", + name: "WHALE/USDC", + lpInfo: { + contractAddr: "migaloo1xv4ql6t6r8zawlqn2tyxqsrvjpmjfm6kvdfvytaueqe3qvcwyr7shtx0hj", + tokensPriceKey: ["WHALE","USDC"], + tokensDecimals: [6, 6] + }, icon: [ - "https://raw.githubusercontent.com/terra-money/station-assets/main/img/coins/USDC.svg", "https://raw.githubusercontent.com/terra-money/station-assets/main/img/coins/Whale.svg", + "https://raw.githubusercontent.com/terra-money/station-assets/main/img/coins/USDC.svg", ], - color: "#3b74c5" }, "factory/migaloo1erul6xyq0gk6ws98ncj7lnq9l4jn4gnnu9we73gdz78yyl2lr7qqrvcgup/ash": { name: "ASH", - priceKey: "factory/migaloo1erul6xyq0gk6ws98ncj7lnq9l4jn4gnnu9we73gdz78yyl2lr7qqrvcgup/ash", + priceKey: "ASH", icon: "images/ash.svg", - color: "#3CCD64" }, "migaloo10nucfm2zqgzqmy7y7ls398t58pjt9cwjsvpy88y2nvamtl34rgmqt5em2v": { name: "mUSDC", - priceKey: "migaloo10nucfm2zqgzqmy7y7ls398t58pjt9cwjsvpy88y2nvamtl34rgmqt5em2v", + priceKey: "USDC", icon: "https://raw.githubusercontent.com/terra-money/station-assets/main/img/coins/USDC.svg", - color: "#3b74c5" }, }, }), @@ -88,20 +97,25 @@ export const SUPPORTED_CHAINS: { [key: string]: Chain } = { name: "rSWTH", priceKey: "rSWTH", icon: "https://raw.githubusercontent.com/terra-money/station-assets/main/img/coins/rSWTH.svg", - color: "#324ab2", }, "ibc/B3F639855EE7478750CC8F82072307ED6E131A8EFF20345E1D136B50C4E5EC36": { name: "ampWhale", priceKey: "ibc/B3F639855EE7478750CC8F82072307ED6E131A8EFF20345E1D136B50C4E5EC36", icon: "https://raw.githubusercontent.com/terra-money/station-assets/main/img/coins/ampWHALE.svg", - color: "#324ab2", }, "ibc/517E13F14A1245D4DE8CF467ADD4DA0058974CDCC880FA6AE536DBCA1D16D84E": { name: "bWhale", priceKey: "ibc/517E13F14A1245D4DE8CF467ADD4DA0058974CDCC880FA6AE536DBCA1D16D84E", icon: "https://raw.githubusercontent.com/terra-money/station-assets/main/img/coins/bWHALE.png", - color: "#fb0174", }, }, }), }; + + +export interface CarbonInflationRes { + numberOfWeeks: string; + inflationRate: string; + last7DaysInflationRate: string; + last14DaysInflationRate: string; +} \ No newline at end of file diff --git a/const/table.tsx b/const/table.tsx index f58e414..0a4e8d5 100644 --- a/const/table.tsx +++ b/const/table.tsx @@ -15,7 +15,7 @@ export const headers = [ }, { title: "Reward Weight", - tooltip: (chainId: string | null) => ( + tooltip: (chainId?: string) => ( <>

The proportion of total staking rewards on this chain to be directed to stakers of this asset.

{chainId == "phoenix-1" && ( diff --git a/lib/AllianceQuery.ts b/lib/QueryAlliances.ts similarity index 100% rename from lib/AllianceQuery.ts rename to lib/QueryAlliances.ts diff --git a/lib/QueryInflation.ts b/lib/QueryInflation.ts new file mode 100644 index 0000000..fb4d926 --- /dev/null +++ b/lib/QueryInflation.ts @@ -0,0 +1,38 @@ +import { Dec } from "@terra-money/feather.js"; +import { LCD } from "../models/LCDConfig"; +import { CarbonInflationRes } from "../const/chains"; + +// This is a very bad pattern but it will allow +// to decrease a long standing call to the API +const INFLATION_CACHE: { [chainId: string]: Dec } = {}; + +// If carbon would have used the standard API this would haven't been necessary +export const GetInflationEndpoint = (chainId: string): Promise => { + if (INFLATION_CACHE[chainId]) return Promise.resolve(); + + if (chainId === "carbon-1") { + return fetch("https://api-insights.carbon.network/chain/inflation") + } + + return LCD.mint.inflation(chainId); +}; + +export const ParseInflation = async (chainId: string, res: any): Promise => { + if (INFLATION_CACHE[chainId]) { + return INFLATION_CACHE[chainId]; + } + + if (chainId === "carbon-1") { + try { + let carbonApiRes: { result: CarbonInflationRes } = await (res as any).json(); + // never let inflation go up #QQ... + let inflation = new Dec(carbonApiRes.result.inflationRate); + INFLATION_CACHE[chainId] = inflation; + return inflation; + } + catch (e) { + return new Dec(0); + } + } + return res as Dec +} \ No newline at end of file diff --git a/lib/QueryLP.ts b/lib/QueryLP.ts new file mode 100644 index 0000000..0f3b69c --- /dev/null +++ b/lib/QueryLP.ts @@ -0,0 +1,41 @@ +import { Dec } from "@terra-money/feather.js"; +import { AllianceCoins } from "../models/Chain"; +import { LCD } from "../models/LCDConfig"; +import { LPResponseModel } from "../models/LPResponse"; + +// This function request the data for the smart contract in parallel, +// and then updates the allianceCoin object with the newly fetched data +// to be able to comput amount later on. +export const QueryLP = async (allianceCoin: AllianceCoins): Promise => { + const denomIndexes = new Array(); + const promises = new Array>(); + + for (const [denom, coin] of Object.entries(allianceCoin)) { + if (coin.lpInfo !== undefined) { + promises.push(LCD.wasm.contractQuery(coin.lpInfo.contractAddr, { pool: {} })) + denomIndexes.push(denom); + } + } + const res = await Promise.all(promises) + .catch((e) => { + console.log("QueryLP error", e); + return [] + }); + + for (let i = 0; i < res.length; i++) { + let poolRes = res[i]; + let coin = allianceCoin[denomIndexes[i]]; + + let tokenAmount = new Dec(poolRes.assets[0].amount) + let token1Amount = new Dec(poolRes.assets[1].amount) + let totalShare = new Dec(poolRes.total_share); + + if (coin.lpInfo) { + coin.lpInfo.totalShare = totalShare; + coin.lpInfo.tokensAmount = [tokenAmount, token1Amount]; + } + allianceCoin[denomIndexes[i]] = coin; + } + + return allianceCoin; +}; diff --git a/models/AllianceFunctions.ts b/models/AllianceFunctions.ts deleted file mode 100644 index edeb971..0000000 --- a/models/AllianceFunctions.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { AllianceAsset } from "@terra-money/feather.js/dist/client/lcd/api/AllianceAPI"; -import { SUPPORTED_CHAINS } from "../const/chains"; - -const SUPPORTED_TOKENS = {} as any; -const SECONDS_IN_YEAR = 31_536_000; - -export const getIcon = (row: AllianceAsset, chain: string) => { - if (!chain) return ""; - - const chainMapped = SUPPORTED_CHAINS[chain].allianceCoins[row.denom]; - return chainMapped ? chainMapped.icon : ""; -}; - -export const getLsdUsdValue = (row: AllianceAsset, chain: string, usdValues: any): number => { - if (!chain) return 1; - - const tokenName = SUPPORTED_CHAINS[chain]?.allianceCoins[row.denom]?.name; - - if (!tokenName) return 0; - const value = usdValues[SUPPORTED_TOKENS[tokenName]]; - return ((value ? value.usd : 0) * parseInt(row.total_tokens)) / 1000_000; -}; - -const getNativeUsdValue = (totalSupplyAmount: number, chain: string, usdValues: any, decimals: number) => { - const tokenName = SUPPORTED_CHAINS[chain]?.bondDenom; - const value = usdValues[SUPPORTED_TOKENS[tokenName]]; - return ((value ? value.usd : 0) * totalSupplyAmount) / 10 ** decimals; -}; - -const calcLsdLosePerYear = (row: AllianceAsset, chain: string, takeRate: string, usdValues: any) => { - const usdStaked = getLsdUsdValue(row, chain, usdValues); - return usdStaked * getTakeRate(row, takeRate); -}; - -export const getTakeRate = (row: AllianceAsset, takeRate: string): number => { - return 1 - (1 - parseFloat(row.take_rate)) ** (SECONDS_IN_YEAR / parseInt(takeRate)); -}; - -const annualRewardsToLunaStakers = ( - row: AllianceAsset, - totalSupplyAmount: number, - chain: string, - inflation: number, - totalRewardWeight: number, - usdValues: any, - decimals: number -) => { - const usdNative = getNativeUsdValue(totalSupplyAmount, chain, usdValues, decimals); - return usdNative * inflation * (parseFloat(row.reward_weight) / (1 + totalRewardWeight)); -}; - -export const getAdditionalYield = ( - row: AllianceAsset, - totalSupplyAmount: number, - chain: string, - inflation: number, - totalRewardWeight: number, - takeRate: string, - usdValues: any, - decimals: number -) => { - const usdStaked = getLsdUsdValue(row, chain, usdValues); - console.log("usdStaked", usdStaked) - const annualRewardsToNativeStakers = annualRewardsToLunaStakers(row, totalSupplyAmount, chain, inflation, totalRewardWeight, usdValues, decimals); - console.log("annualRewardsToNativeStakers", annualRewardsToNativeStakers) - const lsdLosePerYear = calcLsdLosePerYear(row, chain, takeRate, usdValues); - console.log("lsdLosePerYear", lsdLosePerYear) - return ( - (100 * (annualRewardsToNativeStakers - lsdLosePerYear)) / usdStaked - ); -}; - -export const toLocaleString = (val: number) => { - return val.toLocaleString("en-US", { - maximumFractionDigits: 2, - minimumFractionDigits: 2, - }); -}; diff --git a/models/Chain.ts b/models/Chain.ts index 67e5c4e..08e41f9 100644 --- a/models/Chain.ts +++ b/models/Chain.ts @@ -1,3 +1,4 @@ +import { Dec } from "@terra-money/feather.js"; export class Chain implements ChainModel { @@ -11,9 +12,7 @@ export class Chain implements ChainModel { contractAddress: string; denom: string; }; - allianceCoins: { - [key: string]: AllianceCoin - }; + allianceCoins: AllianceCoins; constructor(model: ChainModel) { this.id = model.id; this.bondDenom = model.bondDenom; @@ -39,6 +38,11 @@ export class Chain implements ChainModel { } } +export interface AllianceCoins { + [key: string]: AllianceCoin +} + + export interface ChainModel { id: string; bondDenom: string; @@ -59,14 +63,22 @@ export class AllianceCoin { name: string; priceKey?: string; icon?: string | string[]; - color?: string; - hubContractAddr?: string; + lpInfo?: { + tokensDecimals: number[]; + // This two properties can be determined from the key and name but + // that will lead to bad design so it's better to write them manually + contractAddr: string; + tokensPriceKey: string[]; + // this two properties must be computed from the contract request + tokensAmount?: Dec[]; + totalShare?: Dec; + } constructor(model?: AllianceCoinModel) { this.name = model?.name || ""; this.icon = model?.icon; - this.color = model?.color || ""; - this.hubContractAddr = model?.hubContractAddr || ""; + this.priceKey = model?.priceKey; + this.lpInfo = model?.lpInfo; } static fromAny(model: any): AllianceCoin { @@ -77,6 +89,10 @@ export class AllianceCoin { interface AllianceCoinModel { name: string; icon?: string | string[]; - color?: string; - hubContractAddr?: string; + priceKey?: string; + lpInfo?: { + contractAddr: string; + tokensPriceKey: string[]; + tokensDecimals: number[]; + } } \ No newline at end of file diff --git a/models/LPResponse.ts b/models/LPResponse.ts new file mode 100644 index 0000000..a7d2c0d --- /dev/null +++ b/models/LPResponse.ts @@ -0,0 +1,16 @@ +interface AssetInfo { + native_token: { + denom: string; + }; +} + +interface Asset { + info: AssetInfo; + amount: string; +} + +export interface LPResponseModel { + assets: Asset[]; + total_share: string; +} + diff --git a/models/Prices.ts b/models/Prices.ts index 0a2ccd2..eff1d03 100644 --- a/models/Prices.ts +++ b/models/Prices.ts @@ -15,8 +15,15 @@ export interface Prices { } } -export const mergePrices = (tfmPrices: Prices, tpsr: TerraPriceServerResponse): Prices => { - const prices = tpsr.prices.reduce((acc, price) => { +// Query all prices from the different servers +// available and merge them into a single object +export const QueryAndMergePrices = async (): Promise => { + const pricesRes = await Promise.all([ + fetch("https://price.api.tfm.com/tokens/?limit=1500"), + fetch("https://pisco-price-server.terra.dev/latest") + ]); + const [tfmPrices, terraOraclePrices]: [Prices, TerraPriceServerResponse] = await Promise.all([pricesRes[0].json(), pricesRes[1].json()]); + const prices = terraOraclePrices.prices.reduce((acc, price) => { acc[price.denom] = { chain: "", change24h: 0, diff --git a/models/TableState.ts b/models/TableState.ts index 61ef4cd..e2baed3 100644 --- a/models/TableState.ts +++ b/models/TableState.ts @@ -6,6 +6,8 @@ import { Prices } from "./Prices"; const SECONDS_IN_YEAR = 31_536_000; export default class TableState { + // Use the function to calculate the total reward weight + // this is to avoid recalculating it every time it's called private _totalRewardWeight: number = 0; constructor( @@ -61,6 +63,39 @@ export default class TableState { } getTotalValueStaked = (denom: string): number => { + const isLP = this.selectedChain.allianceCoins[denom]?.lpInfo !== undefined; + + return isLP ? this._getTotalLPValueStaked(denom) : this._getTotalTokenValueStaked(denom); + } + + private _getTotalLPValueStaked = (denom: string): number => { + const lpInfo = this.selectedChain.allianceCoins[denom].lpInfo; + + if (lpInfo && lpInfo.tokensAmount && lpInfo.totalShare) { + const tokenAmount = lpInfo.tokensAmount[0].div(10 ** lpInfo.tokensDecimals[0]); + const tokenPrice = this.prices[lpInfo.tokensPriceKey[0]]?.usd; + const stakedAmountToUSD = tokenAmount.mul(tokenPrice); + + const token1Amount = lpInfo.tokensAmount[1].div(10 ** lpInfo.tokensDecimals[1]); + const token1Price = this.prices[lpInfo.tokensPriceKey[1]]?.usd; + const stakedAmount1ToUSD = token1Amount.mul(token1Price); + + const totalTokens = this.allianceAssets?.find((asset) => asset.denom === denom)?.total_tokens; + if (totalTokens === undefined) { + return 0 + } + const totalStakedTokensToAlliance = new Dec(totalTokens); + const totalStakedSupply = lpInfo.totalShare; + const totalStakedToUsd = stakedAmountToUSD.plus(stakedAmount1ToUSD); + + + return totalStakedTokensToAlliance.div(totalStakedSupply).mul(totalStakedToUsd).toNumber(); + } + + return 0 + } + + private _getTotalTokenValueStaked = (denom: string): number => { const priceKey = this.selectedChain.allianceCoins[denom]?.priceKey; if (priceKey === undefined) { return 0 @@ -101,23 +136,18 @@ export default class TableState { const nativeTokenMarketCap = new Dec(nativeTokenPrice).mul(nativeTokenTotalSupply).div(10 ** this.selectedChain.decimals); let totalAssetStakedInUSD = new Dec(this.getTotalValueStaked(denom)); - console.log("totalAssetStakedInUSD", totalAssetStakedInUSD.toString()) if (totalAssetStakedInUSD.isNaN()) { return 0 } const assetRewardWeight = new Dec(asset.reward_weight); const annualRewardsToNativeStakers = nativeTokenMarketCap.mul(this.inflation) - .mul(assetRewardWeight.div(1 + this._totalRewardWeight)); - console.log("annualRewardsToNativeStakers", annualRewardsToNativeStakers.toString()) + .mul(assetRewardWeight.div(1 + this.getTotalRewardWeight())); const lsdLosePerYear = totalAssetStakedInUSD.mul(this.getTakeRate(denom)); - console.log("lsdLosePerYear", lsdLosePerYear.toString()) - const a = lsdLosePerYear.minus(assetRewardWeight).mul(100); - console.log("a", a.toString()) - console.log("final", a.div(totalAssetStakedInUSD).toString()) - console.log("final", a.div(totalAssetStakedInUSD).toNumber()) - return a.div(totalAssetStakedInUSD).toNumber(); + const additionalYild = annualRewardsToNativeStakers.minus(lsdLosePerYear).div(totalAssetStakedInUSD).mul(100); + + return additionalYild.isNegative() ? additionalYild.plus(100).toNumber() : additionalYild.toNumber(); } } diff --git a/styles/Dropdown.module.css b/styles/Dropdown.module.css index 584df94..743bca7 100644 --- a/styles/Dropdown.module.css +++ b/styles/Dropdown.module.css @@ -10,6 +10,7 @@ background: #2a2a2a; user-select: none; align-items: center; + min-height: 42px; } .select:hover { diff --git a/styles/TableIcon.module.css b/styles/TableIcon.module.css index 956a0c7..3be1ab5 100644 --- a/styles/TableIcon.module.css +++ b/styles/TableIcon.module.css @@ -1,12 +1,12 @@ .IconWrapper img { - width: 45px; - height: 45px; + width: 38px; + height: 38px; } .IconWrapper .ManyIcons { position: relative; - width: 45px; - height: 45px; + width: 38px; + height: 38px; } .IconWrapper .ManyIcons img {
{tableState.getAllianceAssetName(row.denom)}{toLocaleString(tableState.getTotalTokens(row.denom))}${toLocaleString(tableState.getTotalValueStaked(row.denom))}{toLocaleString(tableState.getTakeRate(row.denom))}%{toLocaleString(parseFloat(row.reward_weight) * 100)}%{toLocaleString(tableState.getAdditionalYield(row.denom))}%{toLocalString(tableState.getTotalTokens(row.denom))}${toLocalString(tableState.getTotalValueStaked(row.denom))}{toLocalString(tableState.getTakeRate(row.denom))}%{toLocalString(parseFloat(row.reward_weight) * 100)}%{toLocalString(tableState.getAdditionalYield(row.denom))}%