diff --git a/.eslintignore b/.eslintignore index d1441ab904..8bc7bc20b9 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,4 +1,4 @@ node_modules build src/react-app-env.d.ts -api \ No newline at end of file +/api diff --git a/package.json b/package.json index 77c623b5c0..43ebdb7185 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "@headlessui/react": "^1.1.1", "@heroicons/react": "^2.0.0", "@interlay/bridge": "0.2.7", - "@interlay/interbtc-api": "2.1.1", + "@interlay/interbtc-api": "2.2.2", "@interlay/monetary-js": "0.7.2", "@polkadot/api": "9.14.2", "@polkadot/extension-dapp": "0.44.1", diff --git a/src/assets/locales/en/translation.json b/src/assets/locales/en/translation.json index e22cf946c5..439791e0dd 100644 --- a/src/assets/locales/en/translation.json +++ b/src/assets/locales/en/translation.json @@ -514,7 +514,7 @@ } }, "staking_page": { - "the_estimated_amount_of_governance_token_you_will_receive_as_rewards": "The estimated amount of {{governanceTokenSymbol}} per year you will receive as rewards. Depends on your proportion of the total {{voteGovernanceTokenSymbol}}.", + "the_estimated_amount_of_governance_token_you_will_receive_as_rewards": "The estimated amount of {{governanceTokenSymbol}} you will receive as rewards. Depends on your proportion of the total {{voteGovernanceTokenSymbol}}.", "new_vote_governance_token_gained": "New {{voteGovernanceTokenSymbol}} Gained", "the_increase_in_your_vote_governance_token_balance": "The increase in your {{voteGovernanceTokenSymbol}} balance", "total_vote_governance_token_in_the_network": "Total {{voteGovernanceTokenSymbol}} in the network", diff --git a/src/components/FundWallet/FundWallet.tsx b/src/components/FundWallet/FundWallet.tsx index 08be16e11e..5dc156e1ad 100644 --- a/src/components/FundWallet/FundWallet.tsx +++ b/src/components/FundWallet/FundWallet.tsx @@ -58,7 +58,12 @@ const FundWallet = forwardRef( {description} {entities.map((entity, key) => ( - + {entity.icon} ))} diff --git a/src/components/FundWallet/use-entities.tsx b/src/components/FundWallet/use-entities.tsx index 38915363d7..afb4868502 100644 --- a/src/components/FundWallet/use-entities.tsx +++ b/src/components/FundWallet/use-entities.tsx @@ -1,5 +1,4 @@ import { ReactNode } from 'react'; -import { LinkProps } from 'react-router-dom'; import BANXA_INTERLAY from '@/assets/img/banxa-dark.png'; import BANXA_KITNSUGI from '@/assets/img/banxa-white.png'; @@ -11,14 +10,14 @@ import { ReactComponent as MexcLogoForInterlayIcon } from '@/assets/img/exchange import { ReactComponent as MexcLogoForKintsugiIcon } from '@/assets/img/exchanges/mexc-logo-for-kintsugi.svg'; import { ReactComponent as StellaSwapLogoIcon } from '@/assets/img/exchanges/stellaswap-logo.svg'; import { ReactComponent as ZenlinkLogoIcon } from '@/assets/img/exchanges/zenlink-logo.svg'; -import { BANXA_LINK, LINK_QUERY_PARAMETERS } from '@/config/links'; import { GOVERNANCE_TOKEN } from '@/config/relay-chains'; +import { EXTERNAL_PAGES, EXTERNAL_QUERY_PARAMETERS } from '@/utils/constants/links'; import { KUSAMA, POLKADOT } from '@/utils/constants/relay-chain-names'; import { useWallet } from '@/utils/hooks/use-wallet'; const queryString = require('query-string'); -type FundWalletEntities = { link: LinkProps['to']; icon: ReactNode }; +type FundWalletEntities = { pathname: string; search?: string; icon: ReactNode }; type UseEntitiesResult = { exchanges: FundWalletEntities[]; @@ -29,43 +28,48 @@ const useEntities = (): UseEntitiesResult => { const wallet = useWallet(); const banxaLink = { - pathname: BANXA_LINK, + pathname: EXTERNAL_PAGES.BANXA, search: queryString.stringify({ - [LINK_QUERY_PARAMETERS.BANXA.WALLET_ADDRESS]: wallet.getRelayChainAddress(), - [LINK_QUERY_PARAMETERS.BANXA.FIAT_TYPE]: 'EUR', - [LINK_QUERY_PARAMETERS.BANXA.COIN_TYPE]: GOVERNANCE_TOKEN.ticker + [EXTERNAL_QUERY_PARAMETERS.BANXA.WALLET_ADDRESS]: wallet.account?.toString(), + [EXTERNAL_QUERY_PARAMETERS.BANXA.FIAT_TYPE]: 'EUR', + [EXTERNAL_QUERY_PARAMETERS.BANXA.COIN_TYPE]: GOVERNANCE_TOKEN.ticker }) }; if (process.env.REACT_APP_RELAY_CHAIN_NAME === POLKADOT) { const exchanges = [ { - link: 'https://acala.network/', + pathname: 'https://acala.network/', icon: }, { - link: 'https://stellaswap.com/', + pathname: 'https://stellaswap.com/', icon: }, { - link: 'https://trade.kraken.com/charts/KRAKEN:INTR-USD', + pathname: 'https://trade.kraken.com/charts/KRAKEN:INTR-USD', icon: }, { - link: 'https://www.gate.io/trade/INTR_USDT', + pathname: 'https://www.gate.io/trade/INTR_USDT', icon: }, { - link: 'https://www.mexc.com/exchange/INTR_USDT', + pathname: 'https://www.mexc.com/exchange/INTR_USDT', icon: }, { - link: 'https://www.lbank.info/exchange/intr/usdt', + pathname: 'https://www.lbank.info/exchange/intr/usdt', icon: } ]; - const payments = [{ link: banxaLink, icon: banxa }]; + const payments = [ + { + ...banxaLink, + icon: banxa + } + ]; return { exchanges, @@ -74,24 +78,24 @@ const useEntities = (): UseEntitiesResult => { } else if (process.env.REACT_APP_RELAY_CHAIN_NAME === KUSAMA) { const exchanges = [ { - link: 'https://www.kraken.com/en-gb/prices/kint-kintsugi-price-chart/usd-us-dollar?interval=1m', + pathname: 'https://www.kraken.com/en-gb/prices/kint-kintsugi-price-chart/usd-us-dollar?interval=1m', icon: }, { - link: 'https://www.gate.io/de/trade/kint_usdt', + pathname: 'https://www.gate.io/de/trade/kint_usdt', icon: }, { - link: 'https://dex.zenlink.pro/#/swap', + pathname: 'https://dex.zenlink.pro/#/swap', icon: }, { - link: 'https://www.mexc.com/de-DE/exchange/KINT_USDT', + pathname: 'https://www.mexc.com/de-DE/exchange/KINT_USDT', icon: } ]; - const payments = [{ link: banxaLink, icon: banxa }]; + const payments = [{ ...banxaLink, icon: banxa }]; return { exchanges, diff --git a/src/components/LoanPositionsTable/LoanPositionsTable.tsx b/src/components/LoanPositionsTable/LoanPositionsTable.tsx index 5dd60b7919..f50d1df43c 100644 --- a/src/components/LoanPositionsTable/LoanPositionsTable.tsx +++ b/src/components/LoanPositionsTable/LoanPositionsTable.tsx @@ -7,6 +7,7 @@ import { convertMonetaryAmountToValueInUSD } from '@/common/utils/utils'; import { Switch } from '@/component-library'; import { LoanType } from '@/types/loans'; import { getTokenPrice } from '@/utils/helpers/prices'; +import { useGetAccountSubsidyRewards } from '@/utils/hooks/api/loans/use-get-account-subsidy-rewards'; import { useGetPrices } from '@/utils/hooks/api/use-get-prices'; import { AssetCell, BalanceCell, Table, TableProps } from '../DataGrid'; @@ -52,6 +53,7 @@ const LoanPositionsTable = ({ const titleId = useId(); const { t } = useTranslation(); const prices = useGetPrices(); + const { data: subsidyRewards } = useGetAccountSubsidyRewards(); const isLending = variant === 'lend'; const showCollateral = !!onPressCollateralSwitch && isLending; @@ -84,13 +86,13 @@ const LoanPositionsTable = ({ const { currency } = amountProp; const asset = ; - const { borrowApy, borrowReward, lendApy, lendReward } = assets[currency.ticker]; + const { borrowApy, lendApy } = assets[currency.ticker]; const apyCellProps = isLending - ? { apy: lendApy, rewards: lendReward } + ? { apy: lendApy, rewards: subsidyRewards ? subsidyRewards.perMarket[currency.ticker].lend : null } : { apy: borrowApy, - rewards: borrowReward, + rewards: subsidyRewards ? subsidyRewards.perMarket[currency.ticker].borrow : null, accumulatedDebt: (position as BorrowPosition).accumulatedDebt, isBorrow: true }; @@ -133,7 +135,7 @@ const LoanPositionsTable = ({ collateral }; }), - [assets, isLending, onPressCollateralSwitch, onRowAction, positions, prices, showCollateral] + [assets, isLending, onPressCollateralSwitch, onRowAction, positions, prices, showCollateral, subsidyRewards] ); return ( diff --git a/src/config/links.ts b/src/config/links.ts index 7e5ed0781d..8f1d7557b1 100644 --- a/src/config/links.ts +++ b/src/config/links.ts @@ -19,14 +19,6 @@ const KINTSUGI_SUBSCAN_LINK = 'https://kintsugi.subscan.io'; const INTERLAY_VAULT_DOCS_LINK = 'https://docs.interlay.io/#/vault/overview'; const INTERLAY_DOS_AND_DONTS_DOCS_LINK = 'https://docs.interlay.io/#/vault/installation?id=dos-and-donts'; -const LINK_QUERY_PARAMETERS = { - BANXA: { - WALLET_ADDRESS: 'walletAddress', - FIAT_TYPE: 'fiatType', - COIN_TYPE: 'coinType' - } -}; - const BANXA_LINK = 'http://talisman.banxa.com/'; export { @@ -48,6 +40,5 @@ export { KINTSUGI_GOVERNANCE_LINK, KINTSUGI_SUBSCAN_LINK, KINTSUGI_TERMS_AND_CONDITIONS_LINK, - KINTSUGI_USE_WRAPPED_CURRENCY_LINK, - LINK_QUERY_PARAMETERS + KINTSUGI_USE_WRAPPED_CURRENCY_LINK }; diff --git a/src/pages/AMM/Pools/components/PoolsInsights/PoolsInsights.tsx b/src/pages/AMM/Pools/components/PoolsInsights/PoolsInsights.tsx index 09f41e7566..a845df1639 100644 --- a/src/pages/AMM/Pools/components/PoolsInsights/PoolsInsights.tsx +++ b/src/pages/AMM/Pools/components/PoolsInsights/PoolsInsights.tsx @@ -5,8 +5,8 @@ import { useMutation } from 'react-query'; import { toast } from 'react-toastify'; import { formatUSD } from '@/common/utils/utils'; -import { Card, CTA, Dl, DlGroup } from '@/component-library'; -import { IsAuthenticated } from '@/components'; +import { Card, Dl, DlGroup } from '@/component-library'; +import { AuthCTA } from '@/components'; import { calculateAccountLiquidityUSD, calculateTotalLiquidityUSD } from '@/pages/AMM/shared/utils'; import { submitExtrinsic } from '@/utils/helpers/extrinsic'; import { AccountPoolsData } from '@/utils/hooks/api/amm/use-get-account-pools'; @@ -87,13 +87,11 @@ const PoolsInsights = ({ pools, accountPoolsData, refetch }: PoolsInsightsProps) {t('rewards')} {formatUSD(totalClaimableRewardUSD, { compact: true })} - - {hasClaimableRewards && ( - - Claim - - )} - + {hasClaimableRewards && ( + + Claim + + )} ); diff --git a/src/pages/Loans/LoansOverview/components/BorrowAssetsTable/BorrowAssetsTable.tsx b/src/pages/Loans/LoansOverview/components/BorrowAssetsTable/BorrowAssetsTable.tsx index e81e132de8..d055d959cd 100644 --- a/src/pages/Loans/LoansOverview/components/BorrowAssetsTable/BorrowAssetsTable.tsx +++ b/src/pages/Loans/LoansOverview/components/BorrowAssetsTable/BorrowAssetsTable.tsx @@ -8,6 +8,7 @@ import { Cell, Table, TableProps } from '@/components'; import { ApyCell } from '@/components/LoanPositionsTable/ApyCell'; import { LoanTablePlaceholder } from '@/components/LoanPositionsTable/LoanTablePlaceholder'; import { getTokenPrice } from '@/utils/helpers/prices'; +import { useGetAccountSubsidyRewards } from '@/utils/hooks/api/loans/use-get-account-subsidy-rewards'; import { useGetPrices } from '@/utils/hooks/api/use-get-prices'; import { StyledAssetCell } from './BorrowAssetsTable.style'; @@ -47,17 +48,19 @@ const BorrowAssetsTable = ({ assets, onRowAction, ...props }: BorrowAssetsTableP const titleId = useId(); const { t } = useTranslation(); const prices = useGetPrices(); + const { data: subsidyRewards } = useGetAccountSubsidyRewards(); const rows: BorrowAssetsTableRow[] = useMemo( () => - Object.values(assets).map(({ borrowApy, currency, availableCapacity, borrowReward, totalBorrows }) => { + Object.values(assets).map(({ borrowApy, currency, availableCapacity, totalBorrows }) => { const asset = ; + const reward = subsidyRewards ? subsidyRewards.perMarket[currency.ticker].borrow : null; const apy = ( - Object.values(assets).map(({ lendApy, lendReward, currency, totalLiquidity }) => { + Object.values(assets).map(({ lendApy, currency, totalLiquidity }) => { const asset = ; + const reward = subsidyRewards ? subsidyRewards.perMarket[currency.ticker].lend : null; const apy = ( onRowAction?.(currency.ticker as Key)} @@ -83,7 +86,7 @@ const LendAssetsTable = ({ assets, onRowAction, ...props }: LendAssetsTableProps totalSupply }; }), - [assets, balances, onRowAction, prices] + [assets, balances, onRowAction, prices, subsidyRewards] ); return ( diff --git a/src/pages/Loans/LoansOverview/components/LoansInsights/LoansInsights.tsx b/src/pages/Loans/LoansOverview/components/LoansInsights/LoansInsights.tsx index 7e8f2d7f0f..41bfd6a148 100644 --- a/src/pages/Loans/LoansOverview/components/LoansInsights/LoansInsights.tsx +++ b/src/pages/Loans/LoansOverview/components/LoansInsights/LoansInsights.tsx @@ -4,8 +4,8 @@ import { useMutation } from 'react-query'; import { toast } from 'react-toastify'; import { formatNumber, formatPercentage, formatUSD } from '@/common/utils/utils'; -import { Card, CTA, Dl, DlGroup } from '@/component-library'; -import { IsAuthenticated } from '@/components'; +import { Card, Dl, DlGroup } from '@/component-library'; +import { AuthCTA } from '@/components'; import ErrorModal from '@/legacy-components/ErrorModal'; import { submitExtrinsic } from '@/utils/helpers/extrinsic'; import { AccountLendingStatistics } from '@/utils/hooks/api/loans/use-get-account-lending-statistics'; @@ -42,11 +42,11 @@ const LoansInsights = ({ statistics }: LoansInsightsProps): JSX.Element => { const netPercentage = formatPercentage(netAPY?.toNumber() || 0); const netPercentageLabel = `${netAPY?.gt(0) ? '+' : ''}${netPercentage}`; - const subsidyRewardsAmount = formatNumber(subsidyRewards?.toBig().toNumber() || 0, { - maximumFractionDigits: subsidyRewards?.currency.humanDecimals || 5 + const subsidyRewardsAmount = formatNumber(subsidyRewards?.total.toBig().toNumber() || 0, { + maximumFractionDigits: subsidyRewards?.total.currency.humanDecimals || 5 }); - const subsidyRewardsAmountLabel = `${subsidyRewardsAmount} ${subsidyRewards?.currency.ticker || ''}`; - const hasSubsidyRewards = !!subsidyRewards && !subsidyRewards?.isZero(); + const subsidyRewardsAmountLabel = `${subsidyRewardsAmount} ${subsidyRewards?.total.currency.ticker || ''}`; + const hasSubsidyRewards = !!subsidyRewards && !subsidyRewards?.total.isZero(); return ( <> @@ -75,13 +75,11 @@ const LoansInsights = ({ statistics }: LoansInsightsProps): JSX.Element => { Rewards {subsidyRewardsAmountLabel} - - {hasSubsidyRewards && ( - - Claim - - )} - + {hasSubsidyRewards && ( + + Claim + + )} {claimRewardsMutation.isError && ( diff --git a/src/pages/Staking/BalancesUI/index.tsx b/src/pages/Staking/BalancesUI/index.tsx index 75334113dd..977e951896 100644 --- a/src/pages/Staking/BalancesUI/index.tsx +++ b/src/pages/Staking/BalancesUI/index.tsx @@ -92,7 +92,7 @@ const BalancesUI = ({ stakedAmount, voteStakedAmount, projectedRewardAmount }: P tokenSymbol={VOTE_GOVERNANCE_TOKEN_SYMBOL} /> { tooltip={`The APR may change as the amount of total ${VOTE_GOVERNANCE_TOKEN_SYMBOL} changes.`} /> ` +const StyledCTA = styled(AuthCTA)` position: relative; padding-left: ${(props) => props.$loading && theme.spacing.spacing8}; `; diff --git a/src/pages/Vaults/Vault/components/Rewards/Rewards.tsx b/src/pages/Vaults/Vault/components/Rewards/Rewards.tsx index 2b7be815f1..e2bc840f77 100644 --- a/src/pages/Vaults/Vault/components/Rewards/Rewards.tsx +++ b/src/pages/Vaults/Vault/components/Rewards/Rewards.tsx @@ -7,7 +7,6 @@ import { toast } from 'react-toastify'; import { formatNumber, formatUSD } from '@/common/utils/utils'; import { CardProps } from '@/component-library'; import { LoadingSpinner } from '@/component-library/LoadingSpinner'; -import { IsAuthenticated } from '@/components'; import { GOVERNANCE_TOKEN_SYMBOL, WRAPPED_TOKEN } from '@/config/relay-chains'; import ErrorModal from '@/legacy-components/ErrorModal'; import { ZERO_GOVERNANCE_TOKEN_AMOUNT } from '@/utils/constants/currency'; @@ -83,25 +82,23 @@ const Rewards = ({ const stakingTitle = ( Rewards - - {hasWithdrawRewardsBtn && ( - - {/* TODO: temporary approach. Loading spinner should be added to the CTA itself */} - {claimRewardsMutation.isLoading && ( - - - - )} - Withdraw all rewards - - )} - + {hasWithdrawRewardsBtn && ( + + {/* TODO: temporary approach. Loading spinner should be added to the CTA itself */} + {claimRewardsMutation.isLoading && ( + + + + )} + Withdraw all rewards + + )} {claimRewardsMutation.isError && ( = { enableAsCollateral: mockEnableAsCollateral, disableAsCollateral: mockDisableAsCollateral, claimAllSubsidyRewards: mockClaimAllSubsidyRewards, - getLendingStats: mockGetLendingStats + getLendingStats: mockGetLendingStats, + getLendTokenExchangeRates: mockGetLendTokenExchangeRates }, oracle: { getExchangeRate: mockOracleGetExchangeRate diff --git a/src/test/mocks/@interlay/interbtc-api/parachain/loans.ts b/src/test/mocks/@interlay/interbtc-api/parachain/loans.ts index e29119298d..4e2651d8b9 100644 --- a/src/test/mocks/@interlay/interbtc-api/parachain/loans.ts +++ b/src/test/mocks/@interlay/interbtc-api/parachain/loans.ts @@ -126,7 +126,16 @@ const DEFAULT_ASSETS: TickerToData = { const mockGetLendPositionsOfAccount = jest.fn().mockReturnValue(DEFAULT_LEND_POSITIONS); const mockGetBorrowPositionsOfAccount = jest.fn().mockReturnValue(DEFAULT_BORROW_POSITIONS); const mockGetLoanAssets = jest.fn().mockReturnValue(DEFAULT_ASSETS); -const mockGetAccountSubsidyRewards = jest.fn().mockReturnValue(DEFAULT_INTR.MONETARY.MEDIUM); +const mockGetAccountSubsidyRewards = jest.fn().mockReturnValue({ + total: DEFAULT_INTR.MONETARY.MEDIUM, + perMarket: { + INTR: null, + IBTC: null, + DOT: null + } +}); + +const mockGetLendTokenExchangeRates = jest.fn(); const mockLend = jest.fn(); const mockWithdraw = jest.fn(); @@ -196,6 +205,7 @@ export { mockGetBorrowPositionsOfAccount, mockGetLendingStats, mockGetLendPositionsOfAccount, + mockGetLendTokenExchangeRates, mockGetLoanAssets, mockLend, mockRepay, diff --git a/src/utils/constants/links.ts b/src/utils/constants/links.ts index 852612b127..7c64f49388 100644 --- a/src/utils/constants/links.ts +++ b/src/utils/constants/links.ts @@ -1,3 +1,5 @@ +import { BANXA_LINK } from '@/config/links'; + const URL_PARAMETERS = Object.freeze({ VAULT: { ACCOUNT: 'vaultAccount', @@ -32,6 +34,10 @@ const PAGES = Object.freeze({ WALLET: '/wallet' }); +const EXTERNAL_PAGES = Object.freeze({ + BANXA: `${BANXA_LINK}` +}); + const QUERY_PARAMETERS = Object.freeze({ TAB: 'tab', PAGE: 'page', @@ -45,4 +51,12 @@ const QUERY_PARAMETERS = Object.freeze({ } }); -export { PAGES, QUERY_PARAMETERS, URL_PARAMETERS }; +const EXTERNAL_QUERY_PARAMETERS = Object.freeze({ + BANXA: { + WALLET_ADDRESS: 'walletAddress', + FIAT_TYPE: 'fiatType', + COIN_TYPE: 'coinType' + } +}); + +export { EXTERNAL_PAGES, EXTERNAL_QUERY_PARAMETERS, PAGES, QUERY_PARAMETERS, URL_PARAMETERS }; diff --git a/src/utils/hooks/api/loans/use-get-account-lending-statistics.tsx b/src/utils/hooks/api/loans/use-get-account-lending-statistics.tsx index b9211bba93..0aa6d77d05 100644 --- a/src/utils/hooks/api/loans/use-get-account-lending-statistics.tsx +++ b/src/utils/hooks/api/loans/use-get-account-lending-statistics.tsx @@ -122,7 +122,14 @@ const useGetAccountLendingStatistics = (): UseGetAccountLendingStatistics => { return undefined; } - return getAccountPositionsStats(loanAssets, lendPositions, borrowPositions, subsidyRewards, prices, lendingStats); + return getAccountPositionsStats( + loanAssets, + lendPositions, + borrowPositions, + subsidyRewards.total, + prices, + lendingStats + ); }, [lendPositions, borrowPositions, prices, subsidyRewards, loanAssets, lendingStats]); return { diff --git a/src/utils/hooks/api/loans/use-get-account-subsidy-rewards.tsx b/src/utils/hooks/api/loans/use-get-account-subsidy-rewards.tsx index c373f8647a..9be4fdf62c 100644 --- a/src/utils/hooks/api/loans/use-get-account-subsidy-rewards.tsx +++ b/src/utils/hooks/api/loans/use-get-account-subsidy-rewards.tsx @@ -1,5 +1,4 @@ -import { CurrencyExt } from '@interlay/interbtc-api'; -import { MonetaryAmount } from '@interlay/monetary-js'; +import { AccruedRewards } from '@interlay/interbtc-api'; import { AccountId } from '@polkadot/types/interfaces'; import { useErrorHandler } from 'react-error-boundary'; import { useQuery, useQueryClient } from 'react-query'; @@ -9,7 +8,7 @@ import { BLOCKTIME_REFETCH_INTERVAL } from '@/utils/constants/api'; import useAccountId from '../../use-account-id'; interface AccountAccruedRewards { - data: MonetaryAmount | undefined; + data: AccruedRewards | undefined; refetch: () => void; } diff --git a/src/utils/hooks/api/use-get-prices.tsx b/src/utils/hooks/api/use-get-prices.tsx index 73fd8df062..0e9cbb817f 100644 --- a/src/utils/hooks/api/use-get-prices.tsx +++ b/src/utils/hooks/api/use-get-prices.tsx @@ -1,5 +1,6 @@ -import { CurrencyExt, ForeignAsset } from '@interlay/interbtc-api'; +import { CurrencyExt, isForeignAsset, isLendToken, TickerToData } from '@interlay/interbtc-api'; import { Bitcoin } from '@interlay/monetary-js'; +import Big from 'big.js'; import { useEffect } from 'react'; import { useQuery } from 'react-query'; import { useSelector } from 'react-redux'; @@ -10,9 +11,12 @@ import { COINGECKO_ID_BY_CURRENCY_TICKER } from '@/utils/constants/currency'; import { useGetCurrencies } from './use-get-currencies'; +// MEMO: Returns `undefined` for currencies without coingecko ID. const getCoingeckoId = (currency: CurrencyExt) => { - const asForeignAsset = currency as ForeignAsset; - return asForeignAsset.foreignAsset?.coingeckoId || COINGECKO_ID_BY_CURRENCY_TICKER[currency.ticker]; + if (isForeignAsset(currency)) { + return currency.foreignAsset.coingeckoId; + } + return COINGECKO_ID_BY_CURRENCY_TICKER[currency.ticker]; }; const composeIds = (currencies: CurrencyExt[]): string => @@ -31,8 +35,38 @@ const composeIds = (currencies: CurrencyExt[]): string => const composeEndpoint = (assetsIds: string): string => `${PRICES_API.URL}&ids=${assetsIds}`; -const getPricesByTicker = (currencies: CurrencyExt[], prices: Prices) => +const fetchPricesFromCoingecko = async (endpoint: string) => { + const response = await fetch(endpoint); + return response.json(); +}; + +const getUnderlyingCurrencyFromLendToken = (currencies: CurrencyExt[], lendToken: CurrencyExt) => { + // MEMO: This works as long as lend tokens tickers + // are same as underlying currencies with only `q` character prepended. + const underlyingCurrencyTicker = lendToken.ticker.slice(1); + const underlyingCurrency = currencies.find(({ ticker }) => ticker === underlyingCurrencyTicker); + if (underlyingCurrency === undefined) { + throw new Error(`No underlying currency found for currency ${lendToken.name}`); + } + return underlyingCurrency; +}; + +const getPricesByTicker = (currencies: CurrencyExt[], prices: Prices, lendTokenPrices: TickerToData) => currencies.reduce((acc, currency) => { + if (isLendToken(currency)) { + const underlyingCurrency = getUnderlyingCurrencyFromLendToken(currencies, currency); + const underlyingCurrencyCoingeckoId = getCoingeckoId(underlyingCurrency); + + const underlyingToLendTokenRate = lendTokenPrices[underlyingCurrency.ticker].toNumber(); + const underlyingCurrencyPriceUSD = prices[underlyingCurrencyCoingeckoId].usd; + const lendTokenPrice = { + // MEMO: Can be extended to different counter currencies later if needed. + usd: underlyingToLendTokenRate * underlyingCurrencyPriceUSD + }; + + return { ...acc, [currency.ticker]: lendTokenPrice }; + } + const coingeckoId = getCoingeckoId(currency); return { ...acc, [currency.ticker]: prices[coingeckoId] }; }, {}); @@ -46,10 +80,12 @@ const getPrices = async (currencies?: CurrencyExt[]): Promise