/ pages / v3-migration.page.tsx
v3-migration.page.tsx
  1  import { Trans } from '@lingui/macro';
  2  import { Box } from '@mui/material';
  3  import dynamic from 'next/dynamic';
  4  import { useRouter } from 'next/router';
  5  import { useEffect, useState } from 'react';
  6  import { ConnectWalletPaper } from 'src/components/ConnectWalletPaper';
  7  import { ContentContainer } from 'src/components/ContentContainer';
  8  import { getMarketInfoById } from 'src/components/MarketSwitcher';
  9  import { useUserMigrationReserves } from 'src/hooks/migration/useUserMigrationReserves';
 10  import { useUserSummaryAfterMigration } from 'src/hooks/migration/useUserSummaryAfterMigration';
 11  import { useUserPoolReservesHumanized } from 'src/hooks/pool/useUserPoolReserves';
 12  import { useUserSummaryAndIncentives } from 'src/hooks/pool/useUserSummaryAndIncentives';
 13  import { MainLayout } from 'src/layouts/MainLayout';
 14  import { useWeb3Context } from 'src/libs/hooks/useWeb3Context';
 15  import { DashboardContentNoData } from 'src/modules/dashboard/DashboardContentNoData';
 16  import { MigrationBottomPanel } from 'src/modules/migration/MigrationBottomPanel';
 17  import { MigrationListBorrowItem } from 'src/modules/migration/MigrationListBorrowItem';
 18  import { MigrationListItem } from 'src/modules/migration/MigrationListItem';
 19  import { MigrationListItemLoader } from 'src/modules/migration/MigrationListItemLoader';
 20  import { MigrationLists } from 'src/modules/migration/MigrationLists';
 21  import { MigrationTopPanel } from 'src/modules/migration/MigrationTopPanel';
 22  import { selectCurrentChainIdV3MarketData } from 'src/store/poolSelectors';
 23  import { useRootStore } from 'src/store/root';
 24  import {
 25    CustomMarket,
 26    getNetworkConfig,
 27    MarketDataType,
 28    marketsData,
 29  } from 'src/utils/marketsAndNetworksConfig';
 30  import { useShallow } from 'zustand/shallow';
 31  
 32  const MigrateV3Modal = dynamic(() =>
 33    import('src/components/transactions/MigrateV3/MigrateV3Modal').then(
 34      (module) => module.MigrateV3Modal
 35    )
 36  );
 37  
 38  const AAVE_MARKETS_TO_MIGRATE = Object.keys(marketsData)
 39    .map((key) => {
 40      const market = marketsData[key];
 41      return {
 42        ...market,
 43      };
 44    })
 45    .filter((market) => market.addresses.V3_MIGRATOR);
 46  
 47  const selectableMarkets = [
 48    {
 49      title: 'Aave V2 Markets',
 50      markets: AAVE_MARKETS_TO_MIGRATE,
 51    },
 52  ];
 53  
 54  export default function V3Migration() {
 55    const { currentAccount } = useWeb3Context();
 56    const router = useRouter();
 57    const [fromMarketData, setFromMarketData] = useState<MarketDataType>(() => {
 58      if (router.query.market) {
 59        const { market } = getMarketInfoById(router.query.market as CustomMarket);
 60        const migrationMarket = AAVE_MARKETS_TO_MIGRATE.find(
 61          (migrationMarket) =>
 62            migrationMarket.isFork === market.isFork && migrationMarket.chainId === market.chainId
 63        );
 64        if (migrationMarket) {
 65          return market;
 66        }
 67      }
 68      return AAVE_MARKETS_TO_MIGRATE[0];
 69    });
 70    const [
 71      selectAllSupply,
 72      selectAllBorrow,
 73      toggleSelectedSupplyPosition,
 74      selectedSupplyAssets,
 75      toggleSelectedBorrowPosition,
 76      selectedBorrowAssets,
 77      resetMigrationSelectedAssets,
 78      enforceAsCollateral,
 79    ] = useRootStore(
 80      useShallow((store) => [
 81        store.selectAllSupply,
 82        store.selectAllBorrow,
 83        store.toggleMigrationSelectedSupplyAsset,
 84        store.selectedMigrationSupplyAssets,
 85        store.toggleMigrationSelectedBorrowAsset,
 86        store.selectedMigrationBorrowAssets,
 87        store.resetMigrationSelectedAssets,
 88        store.enforceAsCollateral,
 89      ])
 90    );
 91  
 92    const toMarketData = selectCurrentChainIdV3MarketData(
 93      fromMarketData.chainId,
 94      getNetworkConfig(fromMarketData.chainId)
 95    );
 96  
 97    const { data: userMigrationReserves, isPending: userMigrationReservesLoading } =
 98      useUserMigrationReserves(fromMarketData, toMarketData);
 99  
100    const supplyReserves = userMigrationReserves?.supplyReserves || [];
101    const borrowReserves = userMigrationReserves?.borrowReserves || [];
102    const isolatedReserveV3 = userMigrationReserves?.isolatedReserveV3;
103  
104    const { data: fromUserSummaryAndIncentives, isPending: fromUserSummaryAndIncentivesLoading } =
105      useUserSummaryAndIncentives(fromMarketData);
106  
107    const { data: toUserReservesData, isPending: toUserReservesDataLoading } =
108      useUserPoolReservesHumanized(toMarketData);
109    const { data: toUserSummaryForMigration, isPending: toUserSummaryForMigrationLoading } =
110      useUserSummaryAndIncentives(toMarketData);
111    const toUserEModeCategoryId = toUserReservesData?.userEmodeCategoryId || 0;
112  
113    const { data: userSummaryAfterMigration, isPending: userSummaryAfterMigrationLoading } =
114      useUserSummaryAfterMigration(fromMarketData, toMarketData);
115  
116    const loading =
117      userMigrationReservesLoading ||
118      fromUserSummaryAndIncentivesLoading ||
119      toUserReservesDataLoading ||
120      toUserSummaryForMigrationLoading ||
121      userSummaryAfterMigrationLoading;
122  
123    useEffect(() => {
124      if (resetMigrationSelectedAssets) {
125        resetMigrationSelectedAssets();
126      }
127    }, [resetMigrationSelectedAssets]);
128  
129    const enabledAsCollateral = (canBeEnforced: boolean, underlyingAsset: string) => {
130      if (canBeEnforced) {
131        enforceAsCollateral(underlyingAsset);
132      }
133    };
134  
135    const handleToggleAllSupply = () => {
136      selectAllSupply(supplyReserves);
137    };
138  
139    const handleToggleAllBorrow = () => {
140      selectAllBorrow(borrowReserves);
141    };
142  
143    const userControlledCollateral =
144      selectedSupplyAssets.length > 1 &&
145      toUserSummaryForMigration &&
146      toUserSummaryForMigration.totalCollateralMarketReferenceCurrency == '0';
147  
148    const changeFromMarketData = (marketData: MarketDataType) => {
149      resetMigrationSelectedAssets();
150      setFromMarketData(marketData);
151    };
152  
153    const bottomPanelProps = fromUserSummaryAndIncentives &&
154      toUserSummaryForMigration && {
155        fromUserSummaryBeforeMigration: fromUserSummaryAndIncentives,
156        toUserSummaryBeforeMigration: toUserSummaryForMigration,
157      };
158  
159    return (
160      <>
161        <MigrationTopPanel />
162        {currentAccount ? (
163          <ContentContainer>
164            <Box
165              sx={{
166                display: 'flex',
167                gap: 4,
168                alignItems: 'start',
169                flexDirection: { xs: 'column', lg: 'row' },
170              }}
171            >
172              <MigrationBottomPanel
173                userSummaryAfterMigration={userSummaryAfterMigration}
174                userSummaryBeforeMigration={bottomPanelProps}
175                disableButton={selectedSupplyAssets.length === 0 && selectedBorrowAssets.length === 0}
176                enteringIsolationMode={isolatedReserveV3?.enteringIsolationMode || false}
177                loading={loading}
178                fromMarketData={fromMarketData}
179                toMarketData={toMarketData}
180                setFromMarketData={changeFromMarketData}
181                selectableMarkets={selectableMarkets}
182              />
183              <MigrationLists
184                loading={loading}
185                isSupplyPositionsAvailable={supplyReserves.length > 0}
186                isBorrowPositionsAvailable={borrowReserves.length > 0}
187                onSelectAllSupplies={handleToggleAllSupply}
188                onSelectAllBorrows={handleToggleAllBorrow}
189                emodeCategoryId={toUserEModeCategoryId}
190                isolatedReserveV3={isolatedReserveV3}
191                supplyReserves={supplyReserves}
192                borrowReserves={borrowReserves}
193                suppliesPositions={
194                  <>
195                    {loading ? (
196                      <>
197                        <MigrationListItemLoader />
198                        <MigrationListItemLoader />
199                      </>
200                    ) : supplyReserves.length > 0 ? (
201                      supplyReserves.map((reserve) => (
202                        <MigrationListItem
203                          key={reserve.underlyingAsset}
204                          checked={
205                            selectedSupplyAssets.findIndex(
206                              (selectedAsset) =>
207                                selectedAsset.underlyingAsset == reserve.underlyingAsset
208                            ) >= 0
209                          }
210                          enableAsCollateral={() =>
211                            enabledAsCollateral(reserve.canBeEnforced, reserve.underlyingAsset)
212                          }
213                          userControlledCollateral={userControlledCollateral}
214                          canBeEnforced={
215                            toUserSummaryForMigration &&
216                            toUserSummaryForMigration.totalCollateralMarketReferenceCurrency == '0' &&
217                            reserve.canBeEnforced
218                          }
219                          userReserve={reserve}
220                          amount={reserve.underlyingBalance}
221                          amountInUSD={reserve.underlyingBalanceUSD}
222                          onCheckboxClick={() => {
223                            toggleSelectedSupplyPosition(reserve.underlyingAsset);
224                          }}
225                          enabledAsCollateral={reserve.usageAsCollateralEnabledOnUserV3}
226                          isIsolated={reserve.isolatedOnV3}
227                          enteringIsolation={isolatedReserveV3?.enteringIsolationMode || false}
228                          v3Rates={reserve.v3Rates}
229                          disabled={reserve.migrationDisabled}
230                          isSupplyList
231                        />
232                      ))
233                    ) : (
234                      <Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
235                        <DashboardContentNoData text={<Trans>Nothing supplied yet</Trans>} />
236                      </Box>
237                    )}
238                  </>
239                }
240                borrowsPositions={
241                  <>
242                    {loading ? (
243                      <>
244                        <MigrationListItemLoader />
245                        <MigrationListItemLoader />
246                      </>
247                    ) : borrowReserves.length > 0 ? (
248                      borrowReserves.map((reserve) => (
249                        <MigrationListBorrowItem
250                          key={reserve.debtKey}
251                          userReserve={reserve}
252                          selectedBorrowAssets={selectedBorrowAssets}
253                          toggleSelectedBorrowPosition={toggleSelectedBorrowPosition}
254                          v3Rates={reserve.v3Rates}
255                          enteringIsolation={isolatedReserveV3?.enteringIsolationMode || false}
256                        />
257                      ))
258                    ) : (
259                      <Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
260                        <DashboardContentNoData text={<Trans>Nothing borrowed yet</Trans>} />
261                      </Box>
262                    )}
263                  </>
264                }
265              />
266            </Box>
267          </ContentContainer>
268        ) : (
269          <ConnectWalletPaper
270            description={<Trans> Please connect your wallet to see migration tool.</Trans>}
271          />
272        )}
273      </>
274    );
275  }
276  
277  V3Migration.getLayout = function getLayout(page: React.ReactElement) {
278    return (
279      <MainLayout>
280        {page}
281        <MigrateV3Modal />
282      </MainLayout>
283    );
284  };