From 42c38c3cdf6d8ad543ad8357b9297c2f7169e284 Mon Sep 17 00:00:00 2001 From: kaladinlight <35275952+kaladinlight@users.noreply.github.com> Date: Wed, 18 Sep 2024 13:03:50 -0600 Subject: [PATCH] savers lockup logic --- src/assets/translations/de/main.json | 2 +- src/assets/translations/en/main.json | 6 +- src/assets/translations/es/main.json | 2 +- src/assets/translations/fr/main.json | 2 +- src/assets/translations/ja/main.json | 2 +- src/assets/translations/pt/main.json | 2 +- src/assets/translations/ru/main.json | 2 +- src/assets/translations/tr/main.json | 2 +- src/assets/translations/uk/main.json | 2 +- src/assets/translations/zh/main.json | 2 +- .../Acknowledgement/Acknowledgement.tsx | 4 +- .../Deposit/components/Deposit.tsx | 181 +++++++++++++----- .../Overview/ThorchainSaversOverview.tsx | 69 +++---- src/lib/utils/thorchain/constants.ts | 5 +- .../queries/hooks/useUserLpData.ts | 5 +- .../resolvers/thorchainsavers/index.ts | 57 ++++-- .../resolvers/thorchainsavers/types.ts | 14 ++ src/state/slices/opportunitiesSlice/types.ts | 6 +- .../slices/opportunitiesSlice/utils/index.ts | 20 +- 19 files changed, 231 insertions(+), 154 deletions(-) diff --git a/src/assets/translations/de/main.json b/src/assets/translations/de/main.json index 6b1602d1560..879f4ba2eef 100644 --- a/src/assets/translations/de/main.json +++ b/src/assets/translations/de/main.json @@ -408,7 +408,7 @@ "disabledDepositTitle": "Einzahlungen sind vorübergehend deaktiviert.", "haltedWithdrawTitle": "Auszahlungen sind vorübergehend gestoppt.", "disabledWithdrawTitle": "Auszahlungen sind vorübergehend deaktiviert.", - "runePoolWithdrawLockedTitle": "Sie müssen %{timeHuman} warten, um abzuheben.", + "withdrawLockedTitle": "Sie müssen %{timeHuman} warten, um abzuheben.", "haltedDescription": "Bitte twittern Sie an @THORChain, um die Obergrenzen zu erhöhen!", "protocolFee": "Protokollgebühr", "fee": "Gebühr", diff --git a/src/assets/translations/en/main.json b/src/assets/translations/en/main.json index eeb65c4a173..4779b7b4a5e 100644 --- a/src/assets/translations/en/main.json +++ b/src/assets/translations/en/main.json @@ -409,7 +409,7 @@ "disabledDepositTitle": "Deposits are temporarily disabled.", "haltedWithdrawTitle": "Withdraws are temporarily halted.", "disabledWithdrawTitle": "Withdraws are temporarily disabled.", - "runePoolWithdrawLockedTitle": "You have to wait %{timeHuman} to withdraw.", + "withdrawLockedTitle": "You have to wait %{timeHuman} to withdraw.", "haltedDescription": "Please tweet at @THORChain to raise the caps!", "protocolFee": "Protocol Fee", "fee": "Fee", @@ -505,8 +505,8 @@ "myRewardsBody": "Your active positions with claimable rewards will appear here.", "viewAllPositions": "View All Positions", "liquidityPools": "Liquidity Pools", - "liquidityLockupWarning": "There is a lockup period of %{time} in which you will be unable to withdraw your liquidity.", - "liquidityLocked": "Withdrawing liquidity is locked for %{time}", + "liquidityLockupWarning": "There is a lockup period of %{time}. During lockup you can't access your liquidity.", + "liquidityLocked": "Liquidity Locked (%{time})", "stakingVaults": "Staking & Vaults", "farming": "Farming", "totalEarningBalance": "Total Earning Balance", diff --git a/src/assets/translations/es/main.json b/src/assets/translations/es/main.json index c83617be4d3..4e8872f2255 100644 --- a/src/assets/translations/es/main.json +++ b/src/assets/translations/es/main.json @@ -408,7 +408,7 @@ "disabledDepositTitle": "Depósitos temporalmente deshabilitados.", "haltedWithdrawTitle": "Retiros suspendidos temporalmente.", "disabledWithdrawTitle": "Retiros temporalmente deshabilitados.", - "runePoolWithdrawLockedTitle": "Tienes que esperar %{timeHuman} para retirar.", + "withdrawLockedTitle": "Tienes que esperar %{timeHuman} para retirar.", "haltedDescription": "¡Tuitee a @THORChain para aumentar los límites!", "protocolFee": "Tarifa de Protocolo", "fee": "Comisión", diff --git a/src/assets/translations/fr/main.json b/src/assets/translations/fr/main.json index 43ce153a82f..89de141b2f5 100644 --- a/src/assets/translations/fr/main.json +++ b/src/assets/translations/fr/main.json @@ -408,7 +408,7 @@ "disabledDepositTitle": "Les dépôts sont temporairement désactivés.", "haltedWithdrawTitle": "Les retraits sont temporairement interrompus.", "disabledWithdrawTitle": "Les retraits sont temporairement désactivés.", - "runePoolWithdrawLockedTitle": "Vous devez attendre %{timeHuman} pour retirer.", + "withdrawLockedTitle": "Vous devez attendre %{timeHuman} pour retirer.", "haltedDescription": "Veuillez tweeter @THORChain pour augmenter les plafonds !", "protocolFee": "Frais de protocole", "fee": "Frais", diff --git a/src/assets/translations/ja/main.json b/src/assets/translations/ja/main.json index 9325c6b69e8..c512304c4c8 100644 --- a/src/assets/translations/ja/main.json +++ b/src/assets/translations/ja/main.json @@ -408,7 +408,7 @@ "disabledDepositTitle": "デポジットは一時的に無効になります。", "haltedWithdrawTitle": "出金を一時停止しております。", "disabledWithdrawTitle": "引き出しは一時的に無効になっています。", - "runePoolWithdrawLockedTitle": "引き出すには%{timeHuman}待つ必要があります。", + "withdrawLockedTitle": "引き出すには%{timeHuman}待つ必要があります。", "haltedDescription": "上限を増やすには、@THORChain でツイートしてください。", "protocolFee": "プロトコル手数料", "fee": "手数料", diff --git a/src/assets/translations/pt/main.json b/src/assets/translations/pt/main.json index 8147b1db31a..421f85c7d8e 100644 --- a/src/assets/translations/pt/main.json +++ b/src/assets/translations/pt/main.json @@ -408,7 +408,7 @@ "disabledDepositTitle": "Os depósitos estão temporariamente desativados.", "haltedWithdrawTitle": "As retiradas estão temporariamente suspensas.", "disabledWithdrawTitle": "Os saques estão temporariamente desativados.", - "runePoolWithdrawLockedTitle": "Você tem que esperar %{timeHuman} para sacar.", + "withdrawLockedTitle": "Você tem que esperar %{timeHuman} para sacar.", "haltedDescription": "Por favor, twitte em @THORChain para aumentar o limite!", "protocolFee": "Taxas do Protocolo", "fee": "Taxa", diff --git a/src/assets/translations/ru/main.json b/src/assets/translations/ru/main.json index 73749d94d8e..48faea47f0f 100644 --- a/src/assets/translations/ru/main.json +++ b/src/assets/translations/ru/main.json @@ -408,7 +408,7 @@ "disabledDepositTitle": "Депозиты временно отключены.", "haltedWithdrawTitle": "Вывод средств временно приостановлен.", "disabledWithdrawTitle": "Вывод средств временно отключен.", - "runePoolWithdrawLockedTitle": "Чтобы снять деньги, вам придется подождать %{timeHuman}.", + "withdrawLockedTitle": "Чтобы снять деньги, вам придется подождать %{timeHuman}.", "haltedDescription": "Пожалуйста, напишите в твиттере @THORChain, чтобы поднять капитализацию!", "protocolFee": "Плата за протокол", "fee": "Комиссия", diff --git a/src/assets/translations/tr/main.json b/src/assets/translations/tr/main.json index 80d8d3ddf56..1552ba2bc56 100644 --- a/src/assets/translations/tr/main.json +++ b/src/assets/translations/tr/main.json @@ -408,7 +408,7 @@ "disabledDepositTitle": "Para yatırma işlemleri geçici olarak devre dışı bırakıldı.", "haltedWithdrawTitle": "Para çekme işlemleri geçici olarak durdurulmuştur.", "disabledWithdrawTitle": "Para çekme işlemleri geçici olarak devre dışı bırakıldı.", - "runePoolWithdrawLockedTitle": "Para çekmek için %{timeHuman} beklemeniz gerekiyor.", + "withdrawLockedTitle": "Para çekmek için %{timeHuman} beklemeniz gerekiyor.", "haltedDescription": "Lütfen @THORChain adresine tweet atarak üst sınırınızı yükseltin!", "protocolFee": "Protokol Ücreti", "fee": "Ücret", diff --git a/src/assets/translations/uk/main.json b/src/assets/translations/uk/main.json index e1107c350f4..77802b4ac1c 100644 --- a/src/assets/translations/uk/main.json +++ b/src/assets/translations/uk/main.json @@ -408,7 +408,7 @@ "disabledDepositTitle": "Депозити тимчасово не працюють.", "haltedWithdrawTitle": "Виведення коштів тимчасово призупинено.", "disabledWithdrawTitle": "Виведення коштів тимчасово відключено.", - "runePoolWithdrawLockedTitle": "Ви повинні дочекатися %{timeHuman}, щоб вивести кошти.", + "withdrawLockedTitle": "Ви повинні дочекатися %{timeHuman}, щоб вивести кошти.", "haltedDescription": "Будь ласка, напишіть у твіттері @THORChain, щоб підняти наш рівень!", "protocolFee": "Плата за протокол", "fee": "Комісія", diff --git a/src/assets/translations/zh/main.json b/src/assets/translations/zh/main.json index 4b7a9a68546..f9e6240877f 100644 --- a/src/assets/translations/zh/main.json +++ b/src/assets/translations/zh/main.json @@ -408,7 +408,7 @@ "disabledDepositTitle": "暂时禁止存款。", "haltedWithdrawTitle": "提款暂时停止。", "disabledWithdrawTitle": "暂时禁止提款。", - "runePoolWithdrawLockedTitle": "您必须等待 %{timeHuman} 才能提款。", + "withdrawLockedTitle": "您必须等待 %{timeHuman} 才能提款。", "haltedDescription": "请 @THORChain 发推文以提高上限!", "protocolFee": "协议费", "fee": "费用", diff --git a/src/components/Acknowledgement/Acknowledgement.tsx b/src/components/Acknowledgement/Acknowledgement.tsx index 258c6cf27a1..faed30c55e8 100644 --- a/src/components/Acknowledgement/Acknowledgement.tsx +++ b/src/components/Acknowledgement/Acknowledgement.tsx @@ -91,6 +91,7 @@ type AcknowledgementProps = { buttonTranslation?: string | [string, InterpolationOptions] icon?: ComponentWithAs<'svg', IconProps> disableButton?: boolean + position?: 'relative' | 'static' } type StreamingAcknowledgementProps = Omit & { @@ -113,6 +114,7 @@ export const Acknowledgement = ({ buttonTranslation, disableButton, icon: CustomIcon, + position = 'relative', }: AcknowledgementProps) => { const translate = useTranslate() const [isShowing, setIsShowing] = useState(false) @@ -149,7 +151,7 @@ export const Acknowledgement = ({ return ( = ({ null, ) const [daysToBreakEven, setDaysToBreakEven] = useState(null) + const [shouldShowInfoAcknowledgement, setShouldShowInfoAcknowledgement] = useState(false) + const [depositValues, setDepositValues] = useState() const [inputValues, setInputValues] = useState<{ fiatAmount: string cryptoAmount: string @@ -166,6 +176,29 @@ export const Deposit: React.FC = ({ selectPortfolioCryptoBalanceBaseUnitByFilter(state, balanceFilter), ) + const liquidityLockupTime = useQuery({ + ...reactQueries.thornode.mimir(), + staleTime: thorchainBlockTimeMs, + select: mimirData => { + const liquidityLockupBlocks = mimirData.LIQUIDITYLOCKUPBLOCKS as number | undefined + return Number(bnOrZero(liquidityLockupBlocks).times(THORCHAIN_BLOCK_TIME_SECONDS).toFixed(0)) + }, + }) + + const runePoolDepositMaturityTime = useQuery({ + ...reactQueries.thornode.mimir(), + staleTime: thorchainBlockTimeMs, + select: mimirData => { + const runePoolDepositMaturityBlocks = mimirData.RUNEPOOLDEPOSITMATURITYBLOCKS as + | number + | undefined + + return Number( + bnOrZero(runePoolDepositMaturityBlocks).times(THORCHAIN_BLOCK_TIME_SECONDS).toFixed(0), + ) + }, + }) + const { data: thorchainSaversDepositQuote, isLoading: isThorchainSaversDepositQuoteLoading, @@ -816,60 +849,102 @@ export const Deposit: React.FC = ({ [validateFiatAmountDebounced], ) + const handleContinueMaybeAck = useCallback( + (formValues: DepositValues) => { + setDepositValues(formValues) + if (isRunePool && runePoolDepositMaturityTime.data) { + setShouldShowInfoAcknowledgement(true) + return + } + + if (!isRunePool && liquidityLockupTime.data) { + setShouldShowInfoAcknowledgement(true) + return + } + + handleContinue(formValues) + }, + [liquidityLockupTime, runePoolDepositMaturityTime, isRunePool, handleContinue], + ) + + const handleAcknowledge = useCallback(() => { + if (!depositValues) return + handleContinue(depositValues) + }, [depositValues, handleContinue]) + if (!state || !contextDispatch || !opportunityData) return null return ( - - {!isRunePool ? ( - <> - - {translate('common.slippage')} - - - - - - - - - - {translate('defi.modals.saversVaults.timeToBreakEven.title')} - - - - - {translate( - `defi.modals.saversVaults.${bnOrZero(daysToBreakEven).eq(1) ? 'day' : 'days'}`, - { amount: daysToBreakEven ?? '0' }, - )} - - - - - ) : null} - + + {!isRunePool ? ( + <> + + {translate('common.slippage')} + + + + + + + + + + {translate('defi.modals.saversVaults.timeToBreakEven.title')} + + + + + {translate( + `defi.modals.saversVaults.${bnOrZero(daysToBreakEven).eq(1) ? 'day' : 'days'}`, + { amount: daysToBreakEven ?? '0' }, + )} + + + + + ) : null} + + ) } diff --git a/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Overview/ThorchainSaversOverview.tsx b/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Overview/ThorchainSaversOverview.tsx index 5d25b3e205f..7d91685c921 100644 --- a/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Overview/ThorchainSaversOverview.tsx +++ b/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Overview/ThorchainSaversOverview.tsx @@ -51,7 +51,7 @@ import { import type { StakingId } from 'state/slices/opportunitiesSlice/types' import { DefiProvider, DefiType } from 'state/slices/opportunitiesSlice/types' import { - isRunePoolUserStakingOpportunity, + isSaversUserStakingOpportunity, makeDefiProviderDisplayName, serializeUserStakingId, toOpportunityId, @@ -235,24 +235,9 @@ export const ThorchainSaversOverview: React.FC = ({ .length, ) - const isRunepoolWithdrawUnlocked = useMemo(() => { - if (!isRunePoolUserStakingOpportunity(earnOpportunityData)) return - - const maturityDate = new Date(earnOpportunityData.maturity) - const currentDate = new Date() - - return currentDate >= maturityDate - }, [earnOpportunityData]) - - const runepoolSecondsLeftBeforeWithdrawal = useMemo(() => { - if (!isRunePoolUserStakingOpportunity(earnOpportunityData)) return 0 - - const maturityDate = new Date(earnOpportunityData.maturity) - const currentDate = new Date() - - const diffTime = maturityDate.getTime() - currentDate.getTime() - - return Math.ceil(diffTime / 1000) + const remainingLockupTime = useMemo(() => { + if (!isSaversUserStakingOpportunity(earnOpportunityData)) return 0 + return Math.max(earnOpportunityData.dateUnlocked - Math.floor(Date.now() / 1000), 0) }, [earnOpportunityData]) const accountFilter = useMemo(() => ({ accountId: maybeAccountId }), [maybeAccountId]) @@ -280,9 +265,7 @@ export const ThorchainSaversOverview: React.FC = ({ isHaltedDeposits, isDisabledDeposits, isDisabledWithdrawals, - isRunepoolWithdrawUnlocked, - isRunePool, - runepoolSecondsLeftBeforeWithdrawal, + remainingLockupTime, }: { isFull?: boolean hasPendingTxs?: boolean @@ -290,9 +273,7 @@ export const ThorchainSaversOverview: React.FC = ({ isHaltedDeposits?: boolean isDisabledDeposits?: boolean isDisabledWithdrawals?: boolean - isRunepoolWithdrawUnlocked?: boolean - isRunePool?: boolean - runepoolSecondsLeftBeforeWithdrawal?: number + remainingLockupTime?: number } = {}): DefiButtonProps[] => [ ...(isFull ? [] @@ -325,21 +306,27 @@ export const ThorchainSaversOverview: React.FC = ({ hasPendingTxs || hasPendingQueries || isDisabledWithdrawals || - (isRunePool && !isRunepoolWithdrawUnlocked), + Boolean(remainingLockupTime), toolTip: (() => { - if (isRunePool && !isRunepoolWithdrawUnlocked && runepoolSecondsLeftBeforeWithdrawal) - return translate('defi.modals.saversVaults.runePoolWithdrawLockedTitle', { - timeHuman: formatSecondsToDuration(runepoolSecondsLeftBeforeWithdrawal), - }) - if (isDisabledWithdrawals) + if (isDisabledWithdrawals) { return translate('defi.modals.saversVaults.disabledWithdrawTitle') - if (hasPendingTxs || hasPendingQueries) + } + + if (remainingLockupTime) { + return translate('defi.modals.saversVaults.withdrawLockedTitle', { + timeHuman: formatSecondsToDuration(remainingLockupTime), + }) + } + + if (hasPendingTxs || hasPendingQueries) { return translate('defi.modals.saversVaults.cannotWithdrawWhilePendingTx') + } })(), }, ], [translate], ) + const menu: DefiButtonProps[] = useMemo(() => { if (!earnOpportunityData) return [] @@ -350,23 +337,19 @@ export const ThorchainSaversOverview: React.FC = ({ isHaltedDeposits: isTradingActive === false, isDisabledDeposits: isThorchainSaversDepositEnabled === false, isDisabledWithdrawals: isThorchainSaversWithdrawalsEnabled === false, - isRunepoolWithdrawUnlocked, - runepoolSecondsLeftBeforeWithdrawal, - isRunePool, + remainingLockupTime, }) }, [ earnOpportunityData, - makeDefaultMenu, - opportunityMetadata?.isFull, - isHardCapReached, - hasPendingTxs, hasPendingQueries, - isTradingActive, + hasPendingTxs, + isHardCapReached, isThorchainSaversDepositEnabled, isThorchainSaversWithdrawalsEnabled, - isRunepoolWithdrawUnlocked, - runepoolSecondsLeftBeforeWithdrawal, - isRunePool, + isTradingActive, + makeDefaultMenu, + opportunityMetadata?.isFull, + remainingLockupTime, ]) const renderVaultCap = useMemo(() => { diff --git a/src/lib/utils/thorchain/constants.ts b/src/lib/utils/thorchain/constants.ts index 11610787a42..b1c0a1a5ace 100644 --- a/src/lib/utils/thorchain/constants.ts +++ b/src/lib/utils/thorchain/constants.ts @@ -6,9 +6,6 @@ export const THORCHAIN_AFFILIATE_NAME = 'ss' export const THORCHAIN_POOL_MODULE_ADDRESS = 'thor1g98cy3n9mmjrpn0sxmn63lztelera37n8n67c0' // Current blocktime as per https://thorchain.network/stats -export const THORCHAIN_BLOCK_TIME_SECONDS = '6.1' +export const THORCHAIN_BLOCK_TIME_SECONDS = '6' export const thorchainBlockTimeMs = bn(THORCHAIN_BLOCK_TIME_SECONDS).times(1000).toNumber() export const RUNEPOOL_DEPOSIT_MEMO = 'POOL+' - -// Number of blocks to withdraw from RUNEPool (https://gitlab.com/thorchain/thornode/-/blob/develop/constants/constants_v1.go#L117) -export const RUNEPOOL_MINIMUM_WITHDRAW_BLOCKS = 14400 * 90 diff --git a/src/pages/ThorChainLP/queries/hooks/useUserLpData.ts b/src/pages/ThorChainLP/queries/hooks/useUserLpData.ts index 44bd88d09e8..d3c102623f0 100644 --- a/src/pages/ThorChainLP/queries/hooks/useUserLpData.ts +++ b/src/pages/ThorChainLP/queries/hooks/useUserLpData.ts @@ -90,10 +90,7 @@ export const getUserLpDataPosition = ({ const remainingLockupTime = (() => { const dateNow = Math.floor(Date.now() / 1000) const dateUnlocked = Number(position.dateLastAdded) + liquidityLockupTime - - if (dateNow >= dateUnlocked) return 0 - - return dateNow - dateUnlocked + return Math.max(dateUnlocked - dateNow, 0) })() return { diff --git a/src/state/slices/opportunitiesSlice/resolvers/thorchainsavers/index.ts b/src/state/slices/opportunitiesSlice/resolvers/thorchainsavers/index.ts index 8a8bf4e16db..92bf4b870c5 100644 --- a/src/state/slices/opportunitiesSlice/resolvers/thorchainsavers/index.ts +++ b/src/state/slices/opportunitiesSlice/resolvers/thorchainsavers/index.ts @@ -1,5 +1,5 @@ import type { AssetId } from '@shapeshiftoss/caip' -import { fromAccountId, thorchainAssetId } from '@shapeshiftoss/caip' +import { thorchainAssetId } from '@shapeshiftoss/caip' import type { ThornodePoolResponse } from '@shapeshiftoss/swapper/dist/swappers/ThorchainSwapper/types' import { poolAssetIdToAssetId } from '@shapeshiftoss/swapper/dist/swappers/ThorchainSwapper/utils/poolAssetHelpers/poolAssetHelpers' import { isSome, toBaseUnit } from '@shapeshiftoss/utils' @@ -9,10 +9,8 @@ import { thornode } from 'react-queries/queries/thornode' import { queryClient } from 'context/QueryClientProvider/queryClient' import { bn, bnOrZero } from 'lib/bignumber/bignumber' import { fromThorBaseUnit } from 'lib/utils/thorchain' -import { - RUNEPOOL_MINIMUM_WITHDRAW_BLOCKS, - thorchainBlockTimeMs, -} from 'lib/utils/thorchain/constants' +import { THORCHAIN_BLOCK_TIME_SECONDS } from 'lib/utils/thorchain/constants' +import type { ThorchainMimir } from 'lib/utils/thorchain/lending/types' import { selectAssetById } from 'state/slices/assetsSlice/selectors' import { selectMarketDataByAssetIdUserCurrency } from 'state/slices/marketDataSlice/selectors' import { selectFeatureFlags } from 'state/slices/preferencesSlice/selectors' @@ -33,6 +31,7 @@ import type { OpportunitiesUserDataResolverInput, } from '../types' import type { + MidgardSaverResponse, ThorchainRunepoolInformationResponseSuccess, ThorchainRunepoolMemberPositionResponse, ThorchainRunepoolReservePositionsResponse, @@ -304,6 +303,20 @@ export const thorchainSaversStakingOpportunitiesUserDataResolver = async ({ } try { + const { data: mimir } = await axios.get( + `${getConfig().REACT_APP_THORCHAIN_NODE_URL}/lcd/thorchain/mimir`, + ) + + const liquidityLockupBlocks = mimir.LIQUIDITYLOCKUPBLOCKS as number | undefined + const liquidityLockupTime = Number( + bnOrZero(liquidityLockupBlocks).times(THORCHAIN_BLOCK_TIME_SECONDS).toFixed(0), + ) + + const runePoolDepositMaturityBlocks = mimir.RUNEPOOLDEPOSITMATURITYBLOCKS as number | undefined + const runePoolDepositMaturityTime = Number( + bnOrZero(runePoolDepositMaturityBlocks).times(THORCHAIN_BLOCK_TIME_SECONDS).toFixed(0), + ) + for (const stakingOpportunityId of opportunityIds) { const asset = selectAssetById(state, stakingOpportunityId) if (!asset) @@ -327,7 +340,7 @@ export const thorchainSaversStakingOpportunitiesUserDataResolver = async ({ continue } - const { asset_deposit_value, asset_redeem_value } = accountPosition + const { asset_deposit_value, asset_redeem_value, asset_address } = accountPosition const stakedAmountCryptoBaseUnit = fromThorBaseUnit(asset_deposit_value).times( bn(10).pow(asset.precision), @@ -341,23 +354,29 @@ export const thorchainSaversStakingOpportunitiesUserDataResolver = async ({ stakedAmountCryptoBaseUnitIncludeRewards.minus(stakedAmountCryptoBaseUnit).toFixed(), ] - const maybeMaturity = await (async () => { - if (stakingOpportunityId !== thorchainAssetId) return {} - + const dateUnlocked = await (async () => { try { - const { data: userPosition } = await axios.get<[ThorchainRunepoolMemberPositionResponse]>( - `${getConfig().REACT_APP_MIDGARD_URL}/runepool/${fromAccountId(accountId).account}`, + if (stakingOpportunityId === thorchainAssetId) { + const { data } = await axios.get<[ThorchainRunepoolMemberPositionResponse]>( + `${getConfig().REACT_APP_MIDGARD_URL}/runepool/${asset_address}`, + ) + + return bnOrZero(data[0].dateLastAdded).plus(runePoolDepositMaturityTime).toNumber() + } + + const { data } = await axios.get( + `${getConfig().REACT_APP_MIDGARD_URL}/saver/${asset_address}`, ) - const maturity = - userPosition[0].dateLastAdded + thorchainBlockTimeMs * RUNEPOOL_MINIMUM_WITHDRAW_BLOCKS + const dateLastAdded = data.pools.find(({ pool }) => pool === accountPosition.asset) + ?.dateLastAdded - return { maturity } + return dateLastAdded + ? bnOrZero(dateLastAdded).plus(liquidityLockupTime).toNumber() + : undefined } catch (error) { - if (axios.isAxiosError(error) && error.response?.status === 404) { - return { maturity: undefined } - } - throw new Error('Error fetching RUNEpool maturity') + if (axios.isAxiosError(error) && error.response?.status === 404) return + throw new Error('Error fetching savers date last added') } })() @@ -366,7 +385,7 @@ export const thorchainSaversStakingOpportunitiesUserDataResolver = async ({ userStakingId, stakedAmountCryptoBaseUnit: stakedAmountCryptoBaseUnit.toFixed(), rewardsCryptoBaseUnit: { amounts: rewardsAmountsCryptoBaseUnit, claimable: false }, - ...maybeMaturity, + dateUnlocked, } } diff --git a/src/state/slices/opportunitiesSlice/resolvers/thorchainsavers/types.ts b/src/state/slices/opportunitiesSlice/resolvers/thorchainsavers/types.ts index d5799a4f7cd..2dd25012ba0 100644 --- a/src/state/slices/opportunitiesSlice/resolvers/thorchainsavers/types.ts +++ b/src/state/slices/opportunitiesSlice/resolvers/thorchainsavers/types.ts @@ -46,6 +46,20 @@ export type MidgardPoolResponse = { volume24h: string } +export type MidgardSaverResponse = { + pools: { + assetAdded: string + assetAddress: string + assetDeposit: string + assetRedeem: string + assetWithdrawn: string + dateFirstAdded: string + dateLastAdded: string + pool: string + saverUnits: string + }[] +} + export type ThorchainSaverPositionResponse = { asset: string asset_address: string diff --git a/src/state/slices/opportunitiesSlice/types.ts b/src/state/slices/opportunitiesSlice/types.ts index 48f3fe6a7d4..77058ca62e2 100644 --- a/src/state/slices/opportunitiesSlice/types.ts +++ b/src/state/slices/opportunitiesSlice/types.ts @@ -101,13 +101,13 @@ export type UserStakingOpportunityBase = { } } -export type RunepoolUserStakingOpportunity = { - maturity: number +export type SaversUserStakingOpportunity = { + dateUnlocked: number } & UserStakingOpportunityBase export type UserStakingOpportunity = | UserStakingOpportunityBase - | RunepoolUserStakingOpportunity + | SaversUserStakingOpportunity | CosmosSdkStakingSpecificUserStakingOpportunity | FoxySpecificUserStakingOpportunity diff --git a/src/state/slices/opportunitiesSlice/utils/index.ts b/src/state/slices/opportunitiesSlice/utils/index.ts index af9af65241a..48e6ab053f5 100644 --- a/src/state/slices/opportunitiesSlice/utils/index.ts +++ b/src/state/slices/opportunitiesSlice/utils/index.ts @@ -1,11 +1,5 @@ import type { AccountId, AssetId, ChainId } from '@shapeshiftoss/caip' -import { - fromAccountId, - fromAssetId, - thorchainAssetId, - toAccountId, - toAssetId, -} from '@shapeshiftoss/caip' +import { fromAccountId, fromAssetId, toAccountId, toAssetId } from '@shapeshiftoss/caip' import type { Asset, MarketData } from '@shapeshiftoss/types' import { bn, bnOrZero } from 'lib/bignumber/bignumber' import { fromBaseUnit } from 'lib/math' @@ -19,7 +13,7 @@ import type { FoxySpecificUserStakingOpportunity } from '../resolvers/foxy/types import type { OpportunityId, OpportunityMetadataBase, - RunepoolUserStakingOpportunity, + SaversUserStakingOpportunity, StakingEarnOpportunityType, StakingId, UserStakingId, @@ -234,12 +228,8 @@ export const getOpportunityAccessor: GetOpportunityAccessor = ({ provider, type return 'underlyingAssetIds' } -export const isRunePoolUserStakingOpportunity = ( +export const isSaversUserStakingOpportunity = ( opportunity: StakingEarnOpportunityType | undefined, -): opportunity is StakingEarnOpportunityType & RunepoolUserStakingOpportunity => { - return Boolean( - opportunity && - opportunity.provider === DefiProvider.ThorchainSavers && - opportunity.id === thorchainAssetId, - ) +): opportunity is StakingEarnOpportunityType & SaversUserStakingOpportunity => { + return Boolean(opportunity && opportunity.provider === DefiProvider.ThorchainSavers) }