From 6f4c8edc51a5aca84f3fe52c92e70d3858676b83 Mon Sep 17 00:00:00 2001 From: Joaquin Battilana Date: Mon, 20 May 2024 13:36:55 +0100 Subject: [PATCH 1/9] feat: half migration rework --- .../MigrateV3/MigrateV3Actions.tsx | 6 + .../transactions/MigrateV3/MigrateV3Modal.tsx | 22 +--- .../MigrateV3/MigrateV3ModalContent.tsx | 116 ++++++++++-------- .../StakingMigrate/StakingMigrateActions.tsx | 2 +- .../Supply/SupplyWrappedTokenActions.tsx | 13 +- .../Withdraw/WithdrawAndUnwrapActions.tsx | 4 +- src/hooks/useApprovedAmount.tsx | 30 ++++- src/hooks/useModal.tsx | 8 +- .../migration/MigrationBottomPanel.tsx | 2 +- src/services/ApprovedAmountService.ts | 10 +- src/ui-config/queries.ts | 5 +- 11 files changed, 126 insertions(+), 92 deletions(-) diff --git a/src/components/transactions/MigrateV3/MigrateV3Actions.tsx b/src/components/transactions/MigrateV3/MigrateV3Actions.tsx index 27654752be..bf95203b84 100644 --- a/src/components/transactions/MigrateV3/MigrateV3Actions.tsx +++ b/src/components/transactions/MigrateV3/MigrateV3Actions.tsx @@ -4,14 +4,18 @@ import { useTransactionHandler } from 'src/helpers/useTransactionHandler'; import { UserMigrationReserves } from 'src/hooks/migration/useUserMigrationReserves'; import { UserSummaryForMigration } from 'src/hooks/migration/useUserSummaryForMigration'; import { useRootStore } from 'src/store/root'; +import { MarketDataType } from 'src/ui-config/marketsConfig'; import { TxActionsWrapper } from '../TxActionsWrapper'; +import { useApprovedAmounts } from 'src/hooks/useApprovedAmount'; export type MigrateV3ActionsProps = { isWrongNetwork: boolean; blocked: boolean; userMigrationReserves: UserMigrationReserves; toUserSummaryForMigration: UserSummaryForMigration; + fromMarket: MarketDataType; + toMarket: MarketDataType; }; export const MigrateV3Actions = ({ @@ -19,6 +23,8 @@ export const MigrateV3Actions = ({ blocked, userMigrationReserves, toUserSummaryForMigration, + fromMarket, + toMarket, }: MigrateV3ActionsProps) => { const migrateWithPermits = useRootStore((store) => store.migrateWithPermits); const migrateWithoutPermits = useRootStore((store) => store.migrateWithoutPermits); diff --git a/src/components/transactions/MigrateV3/MigrateV3Modal.tsx b/src/components/transactions/MigrateV3/MigrateV3Modal.tsx index 1e6b5d7151..b07bef9b88 100644 --- a/src/components/transactions/MigrateV3/MigrateV3Modal.tsx +++ b/src/components/transactions/MigrateV3/MigrateV3Modal.tsx @@ -1,32 +1,18 @@ import React from 'react'; import { BasicModal } from 'src/components/primitives/BasicModal'; -import { useUserMigrationReserves } from 'src/hooks/migration/useUserMigrationReserves'; -import { useUserSummaryForMigration } from 'src/hooks/migration/useUserSummaryForMigration'; import { ModalType, useModalContext } from 'src/hooks/useModal'; -import { selectCurrentChainIdV3MarketData } from 'src/store/poolSelectors'; -import { useRootStore } from 'src/store/root'; import { MigrateV3ModalContent } from './MigrateV3ModalContent'; export const MigrateV3Modal = () => { - const { type, close } = useModalContext(); + const { type, close, args } = useModalContext(); - const currentChainId = useRootStore((store) => store.currentChainId); - const currentNetworkConfig = useRootStore((store) => store.currentNetworkConfig); - const currentMarketData = useRootStore((store) => store.currentMarketData); - const toMarketData = selectCurrentChainIdV3MarketData(currentChainId, currentNetworkConfig); - const fromMarketData = currentMarketData; - - const { data: userMigrationReserves } = useUserMigrationReserves(fromMarketData, toMarketData); - const { data: toUserSummaryForMigration } = useUserSummaryForMigration(toMarketData); + const { fromMarket, toMarket } = args; return ( - {userMigrationReserves && toUserSummaryForMigration && ( - + {fromMarket && toMarket && ( + )} ); diff --git a/src/components/transactions/MigrateV3/MigrateV3ModalContent.tsx b/src/components/transactions/MigrateV3/MigrateV3ModalContent.tsx index e1d3b25d2f..d61616a271 100644 --- a/src/components/transactions/MigrateV3/MigrateV3ModalContent.tsx +++ b/src/components/transactions/MigrateV3/MigrateV3ModalContent.tsx @@ -2,9 +2,9 @@ import { InterestRate } from '@aave/contract-helpers'; import { Trans } from '@lingui/macro'; import { Box, Button } from '@mui/material'; import { useRouter } from 'next/router'; -import { useCallback } from 'react'; -import { UserMigrationReserves } from 'src/hooks/migration/useUserMigrationReserves'; -import { UserSummaryForMigration } from 'src/hooks/migration/useUserSummaryForMigration'; +import { useMemo } from 'react'; +import { useUserMigrationReserves } from 'src/hooks/migration/useUserMigrationReserves'; +import { useUserSummaryForMigration } from 'src/hooks/migration/useUserSummaryForMigration'; import { useModalContext } from 'src/hooks/useModal'; import { useWeb3Context } from 'src/libs/hooks/useWeb3Context'; import { useRootStore } from 'src/store/root'; @@ -12,7 +12,7 @@ import { selectedUserSupplyReservesForMigration, selectSelectedBorrowReservesForMigrationV3, } from 'src/store/v3MigrationSelectors'; -import { CustomMarket, getNetworkConfig } from 'src/utils/marketsAndNetworksConfig'; +import { CustomMarket, getNetworkConfig, MarketDataType } from 'src/utils/marketsAndNetworksConfig'; import { TxErrorView } from '../FlowCommons/Error'; import { GasEstimationError } from '../FlowCommons/GasEstimationError'; @@ -24,64 +24,70 @@ import { MigrateV3Actions } from './MigrateV3Actions'; import { MigrateV3ModalAssetsList } from './MigrateV3ModalAssetsList'; interface MigrationV3ModalContentProps { - toUserSummaryForMigration: UserSummaryForMigration; - userMigrationReserves: UserMigrationReserves; + fromMarket: MarketDataType; + toMarket: MarketDataType; } -export const MigrateV3ModalContent = ({ - toUserSummaryForMigration, - userMigrationReserves, -}: MigrationV3ModalContentProps) => { - const currentChainId = useRootStore((store) => store.currentChainId); +export const MigrateV3ModalContent = ({ fromMarket, toMarket }: MigrationV3ModalContentProps) => { + const { data: userMigrationReserves } = useUserMigrationReserves(fromMarket, toMarket); + const { data: toUserSummaryForMigration } = useUserSummaryForMigration(toMarket); + + const currentChainId = fromMarket.chainId; const setCurrentMarket = useRootStore((store) => store.setCurrentMarket); const currentMarket = useRootStore((store) => store.currentMarket); + const selectedMigrationSupplyAssets = useRootStore( + (store) => store.selectedMigrationSupplyAssets + ); + const selectedMigrationBorrowAssets = useRootStore( + (store) => store.selectedMigrationBorrowAssets + ); const { gasLimit, mainTxState: migrateTxState, txError, closeWithCb } = useModalContext(); const { chainId: connectedChainId, readOnlyModeAddress } = useWeb3Context(); const router = useRouter(); const networkConfig = getNetworkConfig(currentChainId); - const { supplyPositions, borrowPositions } = useRootStore( - useCallback( - (state) => ({ - supplyPositions: selectedUserSupplyReservesForMigration( - state.selectedMigrationSupplyAssets, - userMigrationReserves.supplyReserves, - userMigrationReserves.isolatedReserveV3 - ), - borrowPositions: selectSelectedBorrowReservesForMigrationV3( - state.selectedMigrationBorrowAssets, - toUserSummaryForMigration, - userMigrationReserves - ), - }), - [userMigrationReserves, toUserSummaryForMigration] - ) - ); - - const supplyAssets = supplyPositions.map((supplyAsset) => { - return { - underlyingAsset: supplyAsset.underlyingAsset, - iconSymbol: supplyAsset.reserve.iconSymbol, - symbol: supplyAsset.reserve.symbol, - amount: supplyAsset.underlyingBalance, - amountInUSD: supplyAsset.underlyingBalanceUSD, - }; - }); - - const borrowsAssets = borrowPositions.map((asset) => { - return { - underlyingAsset: asset.debtKey, - iconSymbol: asset.reserve.iconSymbol, - symbol: asset.reserve.symbol, - amount: - asset.interestRate == InterestRate.Stable ? asset.stableBorrows : asset.variableBorrows, - amountInUSD: - asset.interestRate == InterestRate.Stable - ? asset.stableBorrowsUSD - : asset.variableBorrowsUSD, - }; - }); + const supplyAssets = useMemo(() => { + if (!userMigrationReserves) { + return []; + } + return selectedUserSupplyReservesForMigration( + selectedMigrationSupplyAssets, + userMigrationReserves.supplyReserves, + userMigrationReserves.isolatedReserveV3 + ).map((supplyAsset) => { + return { + underlyingAsset: supplyAsset.underlyingAsset, + iconSymbol: supplyAsset.reserve.iconSymbol, + symbol: supplyAsset.reserve.symbol, + amount: supplyAsset.underlyingBalance, + amountInUSD: supplyAsset.underlyingBalanceUSD, + }; + }); + }, [userMigrationReserves, selectedMigrationSupplyAssets]); + + const borrowAssets = useMemo(() => { + if (!userMigrationReserves || !toUserSummaryForMigration) { + return []; + } + return selectSelectedBorrowReservesForMigrationV3( + selectedMigrationBorrowAssets, + toUserSummaryForMigration, + userMigrationReserves + ).map((asset) => { + return { + underlyingAsset: asset.debtKey, + iconSymbol: asset.reserve.iconSymbol, + symbol: asset.reserve.symbol, + amount: + asset.interestRate == InterestRate.Stable ? asset.stableBorrows : asset.variableBorrows, + amountInUSD: + asset.interestRate == InterestRate.Stable + ? asset.stableBorrowsUSD + : asset.variableBorrowsUSD, + }; + }); + }, [userMigrationReserves, toUserSummaryForMigration, selectedMigrationBorrowAssets]); // is Network mismatched const isWrongNetwork = currentChainId !== connectedChainId; @@ -134,14 +140,14 @@ export const MigrateV3ModalContent = ({ )} - + Selected supply assets} assets={supplyAssets} /> Selected borrow assets} - assets={borrowsAssets} + assets={borrowAssets} /> @@ -153,6 +159,8 @@ export const MigrateV3ModalContent = ({ blocked={false} userMigrationReserves={userMigrationReserves} toUserSummaryForMigration={toUserSummaryForMigration} + fromMarket={fromMarket} + toMarket={toMarket} /> )} diff --git a/src/components/transactions/StakingMigrate/StakingMigrateActions.tsx b/src/components/transactions/StakingMigrate/StakingMigrateActions.tsx index c1c890d67c..dcd7d0bec5 100644 --- a/src/components/transactions/StakingMigrate/StakingMigrateActions.tsx +++ b/src/components/transactions/StakingMigrate/StakingMigrateActions.tsx @@ -64,7 +64,7 @@ export const StakingMigrateActions = ({ isFetching: fetchingApprovedAmount, isFetchedAfterMount, } = useApprovedAmount({ - marketData: currentMarketData, + chainId: currentMarketData.chainId, token: AaveSafetyModule.STK_ABPT, spender: AaveSafetyModule.STK_ABPT_STK_AAVE_WSTETH_BPTV2_MIGRATOR, }); diff --git a/src/components/transactions/Supply/SupplyWrappedTokenActions.tsx b/src/components/transactions/Supply/SupplyWrappedTokenActions.tsx index 1943d83837..3ada521cdf 100644 --- a/src/components/transactions/Supply/SupplyWrappedTokenActions.tsx +++ b/src/components/transactions/Supply/SupplyWrappedTokenActions.tsx @@ -69,7 +69,11 @@ export const SupplyWrappedTokenActions = ({ data: approvedAmount, isFetching, refetch: fetchApprovedAmount, - } = useApprovedAmount({ marketData, token: tokenIn, spender: tokenWrapperAddress }); + } = useApprovedAmount({ + chainId: marketData.chainId, + token: tokenIn, + spender: tokenWrapperAddress, + }); let requiresApproval = false; if (approvedAmount !== undefined) { @@ -171,7 +175,12 @@ export const SupplyWrappedTokenActions = ({ queryClient.invalidateQueries({ queryKey: queryKeysFactory.pool }); queryClient.invalidateQueries({ - queryKey: queryKeysFactory.approvedAmount(user, tokenIn, tokenWrapperAddress, marketData), + queryKey: queryKeysFactory.approvedAmount( + user, + tokenIn, + tokenWrapperAddress, + marketData.chainId + ), }); } catch (error) { const parsedError = getErrorTextFromError(error, TxAction.GAS_ESTIMATION, false); diff --git a/src/components/transactions/Withdraw/WithdrawAndUnwrapActions.tsx b/src/components/transactions/Withdraw/WithdrawAndUnwrapActions.tsx index 5ecf6cb13f..7ae30d671e 100644 --- a/src/components/transactions/Withdraw/WithdrawAndUnwrapActions.tsx +++ b/src/components/transactions/Withdraw/WithdrawAndUnwrapActions.tsx @@ -73,7 +73,7 @@ export const WithdrawAndUnwrapAction = ({ isFetching: fetchingApprovedAmount, refetch: fetchApprovedAmount, } = useApprovedAmount({ - marketData, + chainId: marketData.chainId, token: poolReserve.aTokenAddress, spender: tokenWrapperAddress, }); @@ -154,7 +154,7 @@ export const WithdrawAndUnwrapAction = ({ user, poolReserve.aTokenAddress, tokenWrapperAddress, - marketData + marketData.chainId ), }); } catch (error) { diff --git a/src/hooks/useApprovedAmount.tsx b/src/hooks/useApprovedAmount.tsx index 7c25075048..0ab54367cb 100644 --- a/src/hooks/useApprovedAmount.tsx +++ b/src/hooks/useApprovedAmount.tsx @@ -1,23 +1,43 @@ -import { useQuery } from '@tanstack/react-query'; +import { ChainId } from '@aave/contract-helpers'; +import { useQueries, useQuery } from '@tanstack/react-query'; import { useRootStore } from 'src/store/root'; import { MarketDataType } from 'src/ui-config/marketsConfig'; import { queryKeysFactory } from 'src/ui-config/queries'; import { useSharedDependencies } from 'src/ui-config/SharedDependenciesProvider'; +export const useApprovedAmounts = ({ + chainId, + tokens, + spender, +}: { + chainId: ChainId; + tokens: string[]; + spender: string; +}) => { + const { approvedAmountService } = useSharedDependencies(); + const user = useRootStore((store) => store.account); + return useQueries({ + queries: tokens.map((token) => ({ + queryFn: () => approvedAmountService.getApprovedAmount(chainId, user, token, spender), + queryKey: queryKeysFactory.approvedAmount(user, token, spender, chainId), + })), + }); +}; + export const useApprovedAmount = ({ - marketData, + chainId, token, spender, }: { - marketData: MarketDataType; + chainId: ChainId; token: string; spender: string; }) => { const { approvedAmountService } = useSharedDependencies(); const user = useRootStore((store) => store.account); return useQuery({ - queryFn: () => approvedAmountService.getApprovedAmount(marketData, user, token, spender), - queryKey: queryKeysFactory.approvedAmount(user, token, spender, marketData), + queryFn: () => approvedAmountService.getApprovedAmount(chainId, user, token, spender), + queryKey: queryKeysFactory.approvedAmount(user, token, spender, chainId), }); }; diff --git a/src/hooks/useModal.tsx b/src/hooks/useModal.tsx index a2409ea26f..c244b9ec31 100644 --- a/src/hooks/useModal.tsx +++ b/src/hooks/useModal.tsx @@ -4,6 +4,7 @@ import { EmodeModalType } from 'src/components/transactions/Emode/EmodeModalCont import { useWeb3Context } from 'src/libs/hooks/useWeb3Context'; import { useRootStore } from 'src/store/root'; import { TxErrorType } from 'src/ui-config/errorMapping'; +import { MarketDataType } from 'src/ui-config/marketsConfig'; import { GENERAL } from 'src/utils/mixPanelEvents'; import { Proposal } from './governance/useProposals'; @@ -46,6 +47,8 @@ export interface ModalArgsType { isFrozen?: boolean; representatives?: Array<{ chainId: ChainId; representative: string }>; chainId?: number; + fromMarket?: MarketDataType; + toMarket?: MarketDataType; } export type TxStateType = { @@ -106,7 +109,7 @@ export interface ModalContextType { openDebtSwitch: (underlyingAsset: string, currentRateMode: InterestRate) => void; openGovDelegation: () => void; openRevokeGovDelegation: () => void; - openV3Migration: () => void; + openV3Migration: (fromMarket: MarketDataType, toMarket: MarketDataType) => void; openGovVote: (proposal: Proposal, support: boolean, power: string) => void; openSwitch: (underlyingAsset?: string, chainId?: number) => void; openStakingMigrate: () => void; @@ -316,8 +319,9 @@ export const ModalContextProvider: React.FC = ({ children }) => { setType(ModalType.GovRepresentatives); setArgs({ representatives }); }, - openV3Migration: () => { + openV3Migration: (fromMarket, toMarket) => { trackEvent(GENERAL.OPEN_MODAL, { modal: 'V2->V3 Migration' }); + setArgs({ fromMarket, toMarket }); setType(ModalType.V3Migration); }, openSwitch: (underlyingAsset, chainId) => { diff --git a/src/modules/migration/MigrationBottomPanel.tsx b/src/modules/migration/MigrationBottomPanel.tsx index fbc9081ead..e391ebe8fe 100644 --- a/src/modules/migration/MigrationBottomPanel.tsx +++ b/src/modules/migration/MigrationBottomPanel.tsx @@ -242,7 +242,7 @@ export const MigrationBottomPanel = ({