diff --git a/pages/_app.page.tsx b/pages/_app.page.tsx
index eb79a37f62..06fe45f81f 100644
--- a/pages/_app.page.tsx
+++ b/pages/_app.page.tsx
@@ -16,6 +16,7 @@ import { CollateralChangeModal } from 'src/components/transactions/CollateralCha
import { EmodeModal } from 'src/components/transactions/Emode/EmodeModal';
import { FaucetModal } from 'src/components/transactions/Faucet/FaucetModal';
import { GasStationProvider } from 'src/components/transactions/GasStation/GasStationProvider';
+import { MigrateV3Modal } from 'src/components/transactions/MigrateV3/MigrateV3Modal';
import { RateSwitchModal } from 'src/components/transactions/RateSwitch/RateSwitchModal';
import { RepayModal } from 'src/components/transactions/Repay/RepayModal';
import { SupplyModal } from 'src/components/transactions/Supply/SupplyModal';
@@ -85,6 +86,7 @@ export default function MyApp(props: MyAppProps) {
+
diff --git a/pages/v3-migration.page.tsx b/pages/v3-migration.page.tsx
new file mode 100644
index 0000000000..4b9e3aac22
--- /dev/null
+++ b/pages/v3-migration.page.tsx
@@ -0,0 +1,210 @@
+import { Trans } from '@lingui/macro';
+import { Box, Divider, useMediaQuery, useTheme } from '@mui/material';
+import { useCallback, useEffect } from 'react';
+import { ConnectWalletPaper } from 'src/components/ConnectWalletPaper';
+import { ContentContainer } from 'src/components/ContentContainer';
+import { MigrateV3Modal } from 'src/components/transactions/MigrateV3/MigrateV3Modal';
+import { useAppDataContext } from 'src/hooks/app-data-provider/useAppDataProvider';
+import { useCurrentTimestamp } from 'src/hooks/useCurrentTimestamp';
+import { usePermissions } from 'src/hooks/usePermissions';
+import { MainLayout } from 'src/layouts/MainLayout';
+import { useWeb3Context } from 'src/libs/hooks/useWeb3Context';
+import { DashboardContentNoData } from 'src/modules/dashboard/DashboardContentNoData';
+import { MigrationBottomPanel } from 'src/modules/migration/MigrationBottomPanel';
+import { MigrationListBorrowItem } from 'src/modules/migration/MigrationListBorrowItem';
+import { MigrationListItem } from 'src/modules/migration/MigrationListItem';
+import { MigrationListItemLoader } from 'src/modules/migration/MigrationListItemLoader';
+import { MigrationLists } from 'src/modules/migration/MigrationLists';
+import { MigrationTopPanel } from 'src/modules/migration/MigrationTopPanel';
+import { selectCurrentChainIdV3PoolReserve } from 'src/store/poolSelectors';
+import { usePoolDataV3Subscription, useRootStore } from 'src/store/root';
+import {
+ selectUserReservesForMigration,
+ selectV2UserSummaryAfterMigration,
+ selectV3UserSummary,
+ selectV3UserSummaryAfterMigration,
+} from 'src/store/v3MigrationSelectors';
+
+export default function V3Migration() {
+ const { loading } = useAppDataContext();
+ const { currentAccount, loading: web3Loading } = useWeb3Context();
+ const { isPermissionsLoading } = usePermissions();
+ const theme = useTheme();
+ const downToSM = useMediaQuery(theme.breakpoints.down('sm'));
+
+ const currentTimeStamp = useCurrentTimestamp(10);
+
+ const {
+ totalCollateralUSD,
+ totalBorrowsUSD,
+ supplyReserves,
+ borrowReserves,
+ healthFactor: v2HealthFactorBeforeMigration,
+ } = useRootStore(
+ useCallback(
+ (state) => selectUserReservesForMigration(state, currentTimeStamp),
+ [currentTimeStamp]
+ )
+ );
+
+ // health factor calculation
+ const { v3UserSummaryBeforeMigration, v2UserSummaryAfterMigration, poolReserveV3 } = useRootStore(
+ (state) => ({
+ v2UserSummaryAfterMigration: selectV2UserSummaryAfterMigration(state, currentTimeStamp),
+ v3UserSummaryBeforeMigration: selectV3UserSummary(state, currentTimeStamp),
+ poolReserveV3: selectCurrentChainIdV3PoolReserve(state),
+ })
+ );
+
+ const v3UserSummaryAfterMigration = useRootStore(
+ useCallback(
+ (state) => selectV3UserSummaryAfterMigration(state, currentTimeStamp),
+ [currentTimeStamp]
+ )
+ );
+
+ // actions
+ const {
+ selectAllSupply,
+ selectAllBorrow,
+ toggleMigrationSelectedSupplyAsset: toggleSelectedSupplyPosition,
+ selectedMigrationSupplyAssets: selectedSupplyAssets,
+ toggleMigrationSelectedBorrowAsset: toggleSelectedBorrowPosition,
+ selectedMigrationBorrowAssets: selectedBorrowAssets,
+ resetMigrationSelectedAssets,
+ enforceAsCollateral,
+ } = useRootStore();
+
+ useEffect(() => {
+ if (resetMigrationSelectedAssets) {
+ resetMigrationSelectedAssets();
+ }
+ }, [resetMigrationSelectedAssets]);
+
+ usePoolDataV3Subscription();
+
+ const enabledAsCollateral = (canBeEnforced: boolean, underlyingAsset: string) => {
+ if (canBeEnforced) {
+ enforceAsCollateral(underlyingAsset);
+ }
+ };
+
+ const handleToggleAllSupply = () => {
+ selectAllSupply(currentTimeStamp);
+ };
+
+ const handleToggleAllBorrow = () => {
+ selectAllBorrow(currentTimeStamp);
+ };
+
+ return (
+ <>
+
+ {currentAccount && !isPermissionsLoading ? (
+
+ 0}
+ isBorrowPositionsAvailable={borrowReserves.length > 0}
+ onSelectAllSupplies={handleToggleAllSupply}
+ onSelectAllBorrows={handleToggleAllBorrow}
+ emodeCategoryId={poolReserveV3?.userEmodeCategoryId}
+ suppliesPositions={
+ <>
+ {loading ? (
+ <>
+
+
+ >
+ ) : supplyReserves.length > 0 ? (
+ supplyReserves.map((reserve) => (
+
+ selectedAsset.underlyingAsset == reserve.underlyingAsset
+ ) >= 0
+ }
+ enableAsCollateral={() =>
+ enabledAsCollateral(reserve.canBeEnforced, reserve.underlyingAsset)
+ }
+ canBeEnforced={
+ v3UserSummaryBeforeMigration.totalCollateralMarketReferenceCurrency ==
+ '0' && reserve.canBeEnforced
+ }
+ reserveIconSymbol={reserve.reserve.iconSymbol}
+ reserveName={reserve.reserve.name}
+ reserveSymbol={reserve.reserve.symbol}
+ amount={reserve.underlyingBalance}
+ amountInUSD={reserve.underlyingBalanceUSD}
+ onCheckboxClick={() => toggleSelectedSupplyPosition(reserve.underlyingAsset)}
+ enabledAsCollateral={reserve.usageAsCollateralEnabledOnUser}
+ isIsolated={reserve.isolatedOnV3}
+ />
+ ))
+ ) : (
+
+ Nothing supplied yet} />
+
+ )}
+ >
+ }
+ borrowsPositions={
+ <>
+ {loading ? (
+ <>
+
+
+ >
+ ) : borrowReserves.length > 0 ? (
+ borrowReserves.map((reserve) => (
+
+ ))
+ ) : (
+
+ Nothing borrowed yet} />
+
+ )}
+ >
+ }
+ />
+
+ {!downToSM && }
+
+
+
+ ) : (
+ Please connect your wallet to see migration tool.}
+ />
+ )}
+ >
+ );
+}
+
+V3Migration.getLayout = function getLayout(page: React.ReactElement) {
+ return (
+
+ {page}
+
+
+ );
+};
diff --git a/scripts/populate-cache.js b/scripts/populate-cache.js
index 9e5680307b..60211bdc9b 100644
--- a/scripts/populate-cache.js
+++ b/scripts/populate-cache.js
@@ -11157,15 +11157,8 @@ var require_base = __commonJS({
comb[2] = points[a].toJ().mixedAdd(points[b].neg());
}
var index = [
- -3, /* -1 -1 */
- -1, /* -1 0 */
- -5, /* -1 1 */
- -7, /* 0 -1 */
- 0, /* 0 0 */
- 7, /* 0 1 */
- 5, /* 1 -1 */
- 1, /* 1 0 */
- 3,
+ -3 /* -1 -1 */, -1 /* -1 0 */, -5 /* -1 1 */, -7 /* 0 -1 */, 0 /* 0 0 */, 7 /* 0 1 */,
+ 5 /* 1 -1 */, 1 /* 1 0 */, 3,
/* 1 1 */
];
var jsf = getJSF(coeffs[a], coeffs[b]);
diff --git a/src/components/TopInfoPanel/PageTitle.tsx b/src/components/TopInfoPanel/PageTitle.tsx
index 7c7e709ddc..da7969af68 100644
--- a/src/components/TopInfoPanel/PageTitle.tsx
+++ b/src/components/TopInfoPanel/PageTitle.tsx
@@ -1,16 +1,23 @@
-import { Box, Typography, useMediaQuery, useTheme } from '@mui/material';
+import { Trans } from '@lingui/macro';
+import { Box, Button, Typography, useMediaQuery, useTheme } from '@mui/material';
import { ReactNode } from 'react';
+import { useRootStore } from '../../store/root';
+import { selectIsMigrationAvailable } from '../../store/v3MigrationSelectors';
import { NetworkConfig } from '../../ui-config/networksConfig';
// import { BridgeButton } from '../BridgeButton';
import { MarketSwitcher } from '../MarketSwitcher';
+import { Link, ROUTES } from '../primitives/Link';
export interface PageTitleProps extends Pick {
pageTitle?: ReactNode;
withMarketSwitcher?: boolean;
+ withMigrateButton?: boolean;
}
-export const PageTitle = ({ pageTitle, withMarketSwitcher }: PageTitleProps) => {
+export const PageTitle = ({ pageTitle, withMarketSwitcher, withMigrateButton }: PageTitleProps) => {
+ const isMigrateToV3Available = useRootStore((state) => selectIsMigrationAvailable(state));
+
const theme = useTheme();
const upToLG = useMediaQuery(theme.breakpoints.up('lg'));
// const upToMD = useMediaQuery(theme.breakpoints.up('md'));
@@ -44,12 +51,20 @@ export const PageTitle = ({ pageTitle, withMarketSwitcher }: PageTitleProps) =>
sx={{
display: 'flex',
alignItems: 'flex-start',
+ flexWrap: 'wrap',
mb: !pageTitle ? 4 : 0,
}}
>
{withMarketSwitcher && }
{/* */}
{/* NOTE:// Removing for now */}
+ {isMigrateToV3Available && withMigrateButton && (
+
+
+
+ )}
);
diff --git a/src/components/TopInfoPanel/TopInfoPanel.tsx b/src/components/TopInfoPanel/TopInfoPanel.tsx
index ff0faef577..5563a6f620 100644
--- a/src/components/TopInfoPanel/TopInfoPanel.tsx
+++ b/src/components/TopInfoPanel/TopInfoPanel.tsx
@@ -12,6 +12,7 @@ export const TopInfoPanel = ({
pageTitle,
titleComponent,
withMarketSwitcher,
+ withMigrateButton,
bridge,
children,
}: TopInfoPanelProps) => {
@@ -30,6 +31,7 @@ export const TopInfoPanel = ({
)}
diff --git a/src/components/lists/ListHeaderTitle.tsx b/src/components/lists/ListHeaderTitle.tsx
index 71f6f8b54d..3001c91b3b 100644
--- a/src/components/lists/ListHeaderTitle.tsx
+++ b/src/components/lists/ListHeaderTitle.tsx
@@ -7,6 +7,7 @@ interface ListHeaderTitleProps {
sortKey?: string;
setSortName?: (value: string) => void;
setSortDesc?: (value: boolean) => void;
+ onClick?: () => void;
children: ReactNode;
}
@@ -16,6 +17,7 @@ export const ListHeaderTitle = ({
sortKey,
setSortName,
setSortDesc,
+ onClick,
children,
}: ListHeaderTitleProps) => {
const handleSorting = (name: string) => {
@@ -32,9 +34,9 @@ export const ListHeaderTitle = ({
variant="subheader2"
color="text.secondary"
noWrap
- onClick={() => !!sortKey && handleSorting(sortKey)}
+ onClick={() => (!!onClick ? onClick() : !!sortKey && handleSorting(sortKey))}
sx={{
- cursor: !!sortKey ? 'pointer' : 'default',
+ cursor: !!onClick || !!sortKey ? 'pointer' : 'default',
display: 'inline-flex',
alignItems: 'center',
}}
diff --git a/src/components/primitives/Link.tsx b/src/components/primitives/Link.tsx
index 7db24272e9..594ad67a34 100644
--- a/src/components/primitives/Link.tsx
+++ b/src/components/primitives/Link.tsx
@@ -119,6 +119,7 @@ export const ROUTES = {
staking: '/staking',
governance: '/governance',
faucet: '/faucet',
+ migrationTool: '/v3-migration',
prerenderedProposal: (proposalId: number) => `/governance/proposal/${proposalId}`,
dynamicRenderedProposal: (proposalId: number) => `/governance/proposal?proposalId=${proposalId}`,
reserveOverview: (underlyingAsset: string, marketName: CustomMarket) =>
diff --git a/src/components/primitives/Row.tsx b/src/components/primitives/Row.tsx
index 2506ae7faf..9523e2e69e 100644
--- a/src/components/primitives/Row.tsx
+++ b/src/components/primitives/Row.tsx
@@ -3,7 +3,7 @@ import { ReactNode } from 'react';
interface RowProps extends BoxProps {
caption?: ReactNode;
- captionVariant?: 'secondary16' | 'description' | 'subheader1' | 'caption';
+ captionVariant?: 'secondary16' | 'description' | 'subheader1' | 'caption' | 'h3';
captionColor?: string;
align?: 'center' | 'flex-start';
}
diff --git a/src/components/transactions/Borrow/BorrowActions.tsx b/src/components/transactions/Borrow/BorrowActions.tsx
index ca4219a76c..f1ecbf806c 100644
--- a/src/components/transactions/Borrow/BorrowActions.tsx
+++ b/src/components/transactions/Borrow/BorrowActions.tsx
@@ -57,7 +57,7 @@ export const BorrowActions = ({
handleAction={action}
actionText={Borrow {symbol}}
actionInProgressText={Borrowing {symbol}}
- handleApproval={() => approval({ amount: amountToBorrow, underlyingAsset: poolAddress })}
+ handleApproval={() => approval([{ amount: amountToBorrow, underlyingAsset: poolAddress }])}
requiresApproval={requiresApproval}
preparingTransactions={loadingTxns}
sx={sx}
diff --git a/src/components/transactions/FlowCommons/ModalWrapper.tsx b/src/components/transactions/FlowCommons/ModalWrapper.tsx
index bc324d8696..d7f5c83428 100644
--- a/src/components/transactions/FlowCommons/ModalWrapper.tsx
+++ b/src/components/transactions/FlowCommons/ModalWrapper.tsx
@@ -8,6 +8,7 @@ import {
} from 'src/hooks/app-data-provider/useAppDataProvider';
import { useWalletBalances } from 'src/hooks/app-data-provider/useWalletBalances';
import { AssetCapsProvider } from 'src/hooks/useAssetCaps';
+import { useIsWrongNetwork } from 'src/hooks/useIsWrongNetwork';
import { useModalContext } from 'src/hooks/useModal';
import { usePermissions } from 'src/hooks/usePermissions';
import { useProtocolDataContext } from 'src/hooks/useProtocolDataContext';
@@ -46,17 +47,15 @@ export const ModalWrapper: React.FC<{
requiredPermission,
keepWrappedSymbol,
}) => {
- const { chainId: connectedChainId, readOnlyModeAddress } = useWeb3Context();
+ const { readOnlyModeAddress } = useWeb3Context();
const { walletBalances } = useWalletBalances();
- const {
- currentChainId: marketChainId,
- currentNetworkConfig,
- currentMarketData,
- } = useProtocolDataContext();
+ const { currentNetworkConfig, currentMarketData } = useProtocolDataContext();
const { user, reserves } = useAppDataContext();
const { txError, mainTxState } = useModalContext();
const { permissions } = usePermissions();
+ const { isWrongNetwork, requiredChainId } = useIsWrongNetwork(_requiredChainId);
+
if (txError && txError.blocking) {
return ;
}
@@ -70,9 +69,6 @@ export const ModalWrapper: React.FC<{
return <>{currentMarketData.permissionComponent}>;
}
- const requiredChainId = _requiredChainId ? _requiredChainId : marketChainId;
- const isWrongNetwork = connectedChainId !== requiredChainId;
-
const poolReserve = reserves.find((reserve) => {
if (underlyingAsset.toLowerCase() === API_ETH_MOCK_ADDRESS.toLowerCase())
return reserve.isWrappedBaseAsset;
diff --git a/src/components/transactions/MigrateV3/MigrateV3Actions.tsx b/src/components/transactions/MigrateV3/MigrateV3Actions.tsx
new file mode 100644
index 0000000000..1f9e89849b
--- /dev/null
+++ b/src/components/transactions/MigrateV3/MigrateV3Actions.tsx
@@ -0,0 +1,48 @@
+import { ProtocolAction } from '@aave/contract-helpers';
+import { Trans } from '@lingui/macro';
+import { useTransactionHandler } from 'src/helpers/useTransactionHandler';
+import { useRootStore } from 'src/store/root';
+
+import { TxActionsWrapper } from '../TxActionsWrapper';
+
+export type MigrateV3ActionsProps = {
+ isWrongNetwork: boolean;
+ blocked: boolean;
+};
+
+export const MigrateV3Actions = ({ isWrongNetwork, blocked }: MigrateV3ActionsProps) => {
+ const migrateWithPermits = useRootStore((store) => store.migrateWithPermits);
+ const migrateWithoutPermits = useRootStore((store) => store.migrateWithoutPermits);
+ const getApprovePermitsForSelectedAssets = useRootStore(
+ (store) => store.getApprovePermitsForSelectedAssets
+ );
+ const { approval, action, loadingTxns, requiresApproval, mainTxState, approvalTxState } =
+ useTransactionHandler({
+ handleGetTxns: async () => await migrateWithoutPermits(),
+ handleGetPermitTxns: async (signatures, deadline) =>
+ await migrateWithPermits(signatures, deadline),
+ tryPermit: true,
+ permitAction: ProtocolAction.migrateV3,
+ });
+
+ const handleApproval = async () => {
+ const approvePermitsForSelectedAssets = await getApprovePermitsForSelectedAssets();
+ approval(approvePermitsForSelectedAssets);
+ };
+
+ return (
+ Migrate}
+ actionInProgressText={Migrating}
+ tryPermit
+ />
+ );
+};
diff --git a/src/components/transactions/MigrateV3/MigrateV3Modal.tsx b/src/components/transactions/MigrateV3/MigrateV3Modal.tsx
new file mode 100644
index 0000000000..a10963b10a
--- /dev/null
+++ b/src/components/transactions/MigrateV3/MigrateV3Modal.tsx
@@ -0,0 +1,15 @@
+import React from 'react';
+import { BasicModal } from 'src/components/primitives/BasicModal';
+import { ModalType, useModalContext } from 'src/hooks/useModal';
+
+import { MigrateV3ModalContent } from './MigrateV3ModalContent';
+
+export const MigrateV3Modal = () => {
+ const { type, close } = useModalContext();
+
+ return (
+
+
+
+ );
+};
diff --git a/src/components/transactions/MigrateV3/MigrateV3ModalAssetsList.tsx b/src/components/transactions/MigrateV3/MigrateV3ModalAssetsList.tsx
new file mode 100644
index 0000000000..2234d9bcc5
--- /dev/null
+++ b/src/components/transactions/MigrateV3/MigrateV3ModalAssetsList.tsx
@@ -0,0 +1,61 @@
+import { Box, Typography } from '@mui/material';
+import { ReactNode } from 'react';
+import { FormattedNumber } from 'src/components/primitives/FormattedNumber';
+import { Row } from 'src/components/primitives/Row';
+import { TokenIcon } from 'src/components/primitives/TokenIcon';
+
+export type Asset = {
+ underlyingAsset: string;
+ iconSymbol: string;
+ symbol: string;
+ amount: string;
+ amountInUSD: string;
+};
+
+interface MigrateV3ModalAssetsListProps {
+ caption: ReactNode;
+ assets: (Asset | undefined)[];
+}
+
+export const MigrateV3ModalAssetsList = ({ caption, assets }: MigrateV3ModalAssetsListProps) => {
+ return (
+
+ {!!assets.length ? (
+
+ {assets.map((asset) =>
+ asset ? (
+
+
+
+
+
+ {asset.symbol}
+
+
+
+
+ ) : (
+ <>>
+ )
+ )}
+
+ ) : (
+ —
+ )}
+
+ );
+};
diff --git a/src/components/transactions/MigrateV3/MigrateV3ModalContent.tsx b/src/components/transactions/MigrateV3/MigrateV3ModalContent.tsx
new file mode 100644
index 0000000000..ad13dac212
--- /dev/null
+++ b/src/components/transactions/MigrateV3/MigrateV3ModalContent.tsx
@@ -0,0 +1,91 @@
+import { Trans } from '@lingui/macro';
+import { useCallback } from 'react';
+import { useCurrentTimestamp } from 'src/hooks/useCurrentTimestamp';
+import { useModalContext } from 'src/hooks/useModal';
+import { useProtocolDataContext } from 'src/hooks/useProtocolDataContext';
+import { useWeb3Context } from 'src/libs/hooks/useWeb3Context';
+import { useRootStore } from 'src/store/root';
+import {
+ selectedUserSupplyReservesForMigration,
+ selectSelectedBorrowReservesForMigrationV3,
+} from 'src/store/v3MigrationSelectors';
+import { getNetworkConfig } from 'src/utils/marketsAndNetworksConfig';
+
+import { TxErrorView } from '../FlowCommons/Error';
+import { GasEstimationError } from '../FlowCommons/GasEstimationError';
+import { TxSuccessView } from '../FlowCommons/Success';
+import { TxModalDetails } from '../FlowCommons/TxModalDetails';
+import { TxModalTitle } from '../FlowCommons/TxModalTitle';
+import { ChangeNetworkWarning } from '../Warnings/ChangeNetworkWarning';
+import { MigrateV3Actions } from './MigrateV3Actions';
+import { MigrateV3ModalAssetsList } from './MigrateV3ModalAssetsList';
+
+export const MigrateV3ModalContent = () => {
+ const currentTimeStamp = useCurrentTimestamp(10);
+ const { supplyPositions, borrowPositions } = useRootStore(
+ useCallback(
+ (state) => ({
+ supplyPositions: selectedUserSupplyReservesForMigration(state, currentTimeStamp),
+ borrowPositions: selectSelectedBorrowReservesForMigrationV3(state, currentTimeStamp),
+ }),
+ [currentTimeStamp]
+ )
+ );
+
+ const { gasLimit, mainTxState: migrateTxState, txError } = useModalContext();
+ const { currentChainId } = useProtocolDataContext();
+ const { chainId: connectedChainId, connectReadOnlyMode } = useWeb3Context();
+ const networkConfig = getNetworkConfig(currentChainId);
+
+ 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.underlyingAsset,
+ iconSymbol: asset.reserve.iconSymbol,
+ symbol: asset.reserve.symbol,
+ amount: asset.totalBorrows,
+ amountInUSD: asset.totalBorrowsUSD,
+ };
+ });
+
+ // is Network mismatched
+ const isWrongNetwork = currentChainId !== connectedChainId;
+
+ if (txError && txError.blocking) {
+ return ;
+ }
+ if (migrateTxState.success) return Migrated} />;
+
+ return (
+ <>
+
+ {isWrongNetwork && !connectReadOnlyMode && (
+
+ )}
+
+
+ Selected supply assets}
+ assets={supplyAssets}
+ />
+ Selected borrow assets}
+ assets={borrowsAssets}
+ />
+
+
+ {txError && }
+
+
+ >
+ );
+};
diff --git a/src/components/transactions/Repay/CollateralRepayActions.tsx b/src/components/transactions/Repay/CollateralRepayActions.tsx
index 0d501f0393..348758443e 100644
--- a/src/components/transactions/Repay/CollateralRepayActions.tsx
+++ b/src/components/transactions/Repay/CollateralRepayActions.tsx
@@ -104,7 +104,7 @@ export const CollateralRepayActions = ({
sx={sx}
{...props}
handleAction={action}
- handleApproval={() => approval()}
+ handleApproval={approval}
actionText={Repay {symbol}}
actionInProgressText={Repaying {symbol}}
fetchingData={loading}
diff --git a/src/components/transactions/Repay/RepayActions.tsx b/src/components/transactions/Repay/RepayActions.tsx
index 45a2372868..84be4acee8 100644
--- a/src/components/transactions/Repay/RepayActions.tsx
+++ b/src/components/transactions/Repay/RepayActions.tsx
@@ -49,7 +49,7 @@ export const RepayActions = ({
symbol,
});
},
- handleGetPermitTxns: async (signature, deadline) => {
+ handleGetPermitTxns: async (signatures, deadline) => {
return repayWithPermit({
amountToRepay,
poolReserve,
@@ -58,7 +58,7 @@ export const RepayActions = ({
symbol,
debtType,
repayWithATokens,
- signature,
+ signature: signatures[0],
deadline,
});
},
@@ -80,12 +80,7 @@ export const RepayActions = ({
sx={sx}
{...props}
handleAction={action}
- handleApproval={() =>
- approval({
- amount: amountToRepay,
- underlyingAsset: poolAddress,
- })
- }
+ handleApproval={() => approval([{ amount: amountToRepay, underlyingAsset: poolAddress }])}
actionText={Repay {symbol}}
actionInProgressText={Repaying {symbol}}
tryPermit={usingPermit}
diff --git a/src/components/transactions/Stake/StakeActions.tsx b/src/components/transactions/Stake/StakeActions.tsx
index d092bcdf10..958da220c2 100644
--- a/src/components/transactions/Stake/StakeActions.tsx
+++ b/src/components/transactions/Stake/StakeActions.tsx
@@ -25,7 +25,7 @@ export const StakeActions = ({
}: StakeActionProps) => {
const stake = useRootStore((state) => state.stake);
- const { action, approval, requiresApproval, loadingTxns, approvalTxState, mainTxState } =
+ const { action, requiresApproval, loadingTxns, approvalTxState, mainTxState } =
useTransactionHandler({
tryPermit: false,
handleGetTxns: async () => {
@@ -47,7 +47,6 @@ export const StakeActions = ({
isWrongNetwork={isWrongNetwork}
amount={amountToStake}
handleAction={action}
- handleApproval={() => approval({ amount: amountToStake, underlyingAsset: selectedToken })}
symbol={symbol}
requiresAmount
actionText={Stake}
diff --git a/src/components/transactions/Supply/SupplyActions.tsx b/src/components/transactions/Supply/SupplyActions.tsx
index f6ddcb3673..66caf649f9 100644
--- a/src/components/transactions/Supply/SupplyActions.tsx
+++ b/src/components/transactions/Supply/SupplyActions.tsx
@@ -42,11 +42,11 @@ export const SupplyActions = ({
blocked,
});
},
- handleGetPermitTxns: async (signature, deadline) => {
+ handleGetPermitTxns: async (signatures, deadline) => {
return supplyWithPermit({
reserve: poolAddress,
amount: amountToSupply,
- signature,
+ signature: signatures[0],
deadline,
});
},
@@ -66,12 +66,7 @@ export const SupplyActions = ({
preparingTransactions={loadingTxns}
actionText={Supply {symbol}}
actionInProgressText={Supplying {symbol}}
- handleApproval={() =>
- approval({
- amount: amountToSupply,
- underlyingAsset: poolAddress,
- })
- }
+ handleApproval={() => approval([{ amount: amountToSupply, underlyingAsset: poolAddress }])}
handleAction={action}
requiresApproval={requiresApproval}
tryPermit={usingPermit}
diff --git a/src/components/transactions/Withdraw/WithdrawActions.tsx b/src/components/transactions/Withdraw/WithdrawActions.tsx
index 9d30a2a1a9..8dc41123c0 100644
--- a/src/components/transactions/Withdraw/WithdrawActions.tsx
+++ b/src/components/transactions/Withdraw/WithdrawActions.tsx
@@ -51,7 +51,7 @@ export const WithdrawActions = ({
actionInProgressText={Withdrawing {symbol}}
actionText={Withdraw {symbol}}
handleAction={action}
- handleApproval={() => approval({ amount: amountToWithdraw, underlyingAsset: poolAddress })}
+ handleApproval={() => approval([{ amount: amountToWithdraw, underlyingAsset: poolAddress }])}
requiresApproval={requiresApproval}
sx={sx}
/>
diff --git a/src/helpers/useTransactionHandler.tsx b/src/helpers/useTransactionHandler.tsx
index 0b25ec3ac3..fb9be29232 100644
--- a/src/helpers/useTransactionHandler.tsx
+++ b/src/helpers/useTransactionHandler.tsx
@@ -18,7 +18,7 @@ export const MOCK_SIGNED_HASH = 'Signed correctly';
interface UseTransactionHandlerProps {
handleGetTxns: () => Promise;
handleGetPermitTxns?: (
- signature: SignatureLike,
+ signatures: SignatureLike[],
deadline: string
) => Promise;
tryPermit?: boolean;
@@ -27,10 +27,11 @@ interface UseTransactionHandlerProps {
deps?: DependencyList;
}
-interface ApprovalProps {
- amount?: string;
- underlyingAsset?: string;
-}
+export type Approval = {
+ amount: string;
+ underlyingAsset: string;
+ permitType?: 'POOL' | 'MIGRATOR';
+};
export const useTransactionHandler = ({
handleGetTxns,
@@ -53,11 +54,17 @@ export const useTransactionHandler = ({
const { signTxData, sendTx, getTxError } = useWeb3Context();
const { refetchWalletBalances, refetchPoolData, refetchIncentiveData } =
useBackgroundDataProvider();
- const [signature, setSignature] = useState();
+ const [signatures, setSignatures] = useState([]);
const [signatureDeadline, setSignatureDeadline] = useState();
- const { signERC20Approval, walletApprovalMethodPreference } = useRootStore();
+ const generatePermitPayloadForMigrationAsset = useRootStore(
+ (state) => state.generatePermitPayloadForMigrationAsset
+ );
+ const [signPoolERC20Approval, walletApprovalMethodPreference] = useRootStore((state) => [
+ state.signERC20Approval,
+ state.walletApprovalMethodPreference,
+ ]);
- const [approvalTx, setApprovalTx] = useState();
+ const [approvalTxes, setApprovalTxes] = useState();
const [actionTx, setActionTx] = useState();
const [usePermit, setUsePermit] = useState(false);
const mounted = useRef(false);
@@ -113,90 +120,117 @@ export const useTransactionHandler = ({
}
};
- const approval = async ({ amount, underlyingAsset }: ApprovalProps) => {
- if (usePermit && amount && underlyingAsset) {
- setApprovalTxState({ ...approvalTxState, loading: true });
- try {
- // deadline is an hour after signature
- const deadline = Math.floor(Date.now() / 1000 + 3600).toString();
- const unsingedPayload = await signERC20Approval({
- reserve: underlyingAsset,
- amount,
- deadline,
- });
+ const approval = async (approvals?: Approval[]) => {
+ if (approvalTxes) {
+ if (usePermit && approvals && approvals?.length > 0) {
+ setApprovalTxState({ ...approvalTxState, loading: true });
try {
- const signature = await signTxData(unsingedPayload);
+ // deadline is an hour after signature
+ const deadline = Math.floor(Date.now() / 1000 + 3600).toString();
+ const unsignedPayloads: string[] = [];
+ for (const approval of approvals) {
+ if (!approval.permitType || approval.permitType == 'POOL') {
+ unsignedPayloads.push(
+ await signPoolERC20Approval({
+ reserve: approval.underlyingAsset,
+ amount: approval.amount,
+ deadline,
+ })
+ );
+ } else {
+ unsignedPayloads.push(
+ await generatePermitPayloadForMigrationAsset({ ...approval, deadline })
+ );
+ }
+ }
+ try {
+ const signatures: SignatureLike[] = [];
+ for (const unsignedPayload of unsignedPayloads) {
+ signatures.push(await signTxData(unsignedPayload));
+ }
+ if (!mounted.current) return;
+ setSignatures(signatures);
+ setSignatureDeadline(deadline);
+ setApprovalTxState({
+ txHash: MOCK_SIGNED_HASH,
+ loading: false,
+ success: true,
+ });
+ setTxError(undefined);
+ } catch (error) {
+ if (!mounted.current) return;
+ const parsedError = getErrorTextFromError(error, TxAction.APPROVAL, false);
+ setTxError(parsedError);
+
+ setApprovalTxState({
+ txHash: undefined,
+ loading: false,
+ });
+ }
+ } catch (error) {
if (!mounted.current) return;
- setSignature(signature);
- setSignatureDeadline(deadline);
+
+ const parsedError = getErrorTextFromError(error, TxAction.GAS_ESTIMATION, false);
+ setTxError(parsedError);
setApprovalTxState({
- txHash: MOCK_SIGNED_HASH,
+ txHash: undefined,
+ loading: false,
+ });
+ }
+ } else {
+ try {
+ setApprovalTxState({ ...approvalTxState, loading: true });
+ const params = await Promise.all(approvalTxes.map((approvalTx) => approvalTx.tx()));
+ const approvalResponses = await Promise.all(
+ params.map(
+ (param) =>
+ new Promise(async (resolve, reject) => {
+ delete param.gasPrice;
+ processTx({
+ tx: () => sendTx(param),
+ successCallback: (txnResponse: TransactionResponse) => {
+ resolve(txnResponse);
+ },
+ errorCallback: (error, hash) => {
+ const parsedError = getErrorTextFromError(error, TxAction.APPROVAL, false);
+ setTxError(parsedError);
+ setApprovalTxState({
+ txHash: hash,
+ loading: false,
+ });
+ reject();
+ },
+ // TODO: add error callback
+ action: TxAction.APPROVAL,
+ });
+ })
+ )
+ );
+
+ setApprovalTxState({
+ txHash: approvalResponses[0].hash,
loading: false,
success: true,
});
- setTxError(undefined);
} catch (error) {
if (!mounted.current) return;
- const parsedError = getErrorTextFromError(error, TxAction.APPROVAL, false);
+ const parsedError = getErrorTextFromError(error, TxAction.GAS_ESTIMATION, false);
setTxError(parsedError);
-
setApprovalTxState({
txHash: undefined,
loading: false,
});
}
- } catch (error) {
- if (!mounted.current) return;
- const parsedError = getErrorTextFromError(error, TxAction.GAS_ESTIMATION, false);
- setTxError(parsedError);
- setApprovalTxState({
- txHash: undefined,
- loading: false,
- });
- }
- } else if (approvalTx) {
- try {
- setApprovalTxState({ ...approvalTxState, loading: true });
- const params = await approvalTx.tx();
- delete params.gasPrice;
- await processTx({
- tx: () => sendTx(params),
- successCallback: (txnResponse: TransactionResponse) => {
- setApprovalTxState({
- txHash: txnResponse.hash,
- loading: false,
- success: true,
- });
- setTxError(undefined);
- },
- errorCallback: (error, hash) => {
- const parsedError = getErrorTextFromError(error, TxAction.APPROVAL, false);
- setTxError(parsedError);
- setApprovalTxState({
- txHash: hash,
- loading: false,
- });
- },
- action: TxAction.APPROVAL,
- });
- } catch (error) {
- if (!mounted.current) return;
- const parsedError = getErrorTextFromError(error, TxAction.GAS_ESTIMATION, false);
- setTxError(parsedError);
- setApprovalTxState({
- txHash: undefined,
- loading: false,
- });
}
}
};
const action = async () => {
if (usePermit && handleGetPermitTxns) {
- if (!signature || !signatureDeadline) throw new Error('signature needed');
+ if (!signatures.length || !signatureDeadline) throw new Error('signature needed');
try {
setMainTxState({ ...mainTxState, loading: true });
- const txns = await handleGetPermitTxns(signature, signatureDeadline);
+ const txns = await handleGetPermitTxns(signatures, signatureDeadline);
const params = await txns[0].tx();
delete params.gasPrice;
return processTx({
@@ -220,6 +254,7 @@ export const useTransactionHandler = ({
action: TxAction.MAIN_ACTION,
});
} catch (error) {
+ console.log(error, 'error');
const parsedError = getErrorTextFromError(error, TxAction.GAS_ESTIMATION, false);
setTxError(parsedError);
setMainTxState({
@@ -228,7 +263,7 @@ export const useTransactionHandler = ({
});
}
}
- if ((!usePermit || !approvalTx) && actionTx) {
+ if ((!usePermit || !approvalTxes) && actionTx) {
try {
setMainTxState({ ...mainTxState, loading: true });
const params = await actionTx.tx();
@@ -255,6 +290,7 @@ export const useTransactionHandler = ({
});
} catch (error) {
const parsedError = getErrorTextFromError(error, TxAction.GAS_ESTIMATION, false);
+ console.log(error, parsedError);
setTxError(parsedError);
setMainTxState({
txHash: undefined,
@@ -274,13 +310,16 @@ export const useTransactionHandler = ({
return handleGetTxns()
.then(async (txs) => {
if (!mounted.current) return;
- const approvalTransaction = txs.find((tx) => tx.txType === 'ERC20_APPROVAL');
+ const approvalTransactions = txs.filter((tx) => tx.txType == 'ERC20_APPROVAL');
+ if (approvalTransactions.length > 0) {
+ setApprovalTxes(approvalTransactions);
+ }
const preferPermit =
tryPermit &&
walletApprovalMethodPreference === ApprovalMethod.PERMIT &&
handleGetPermitTxns &&
permitAction;
- if (approvalTransaction && preferPermit) {
+ if (approvalTransactions.length > 0 && preferPermit) {
// For permit flow, jsut use recommendation for gas limit as estimation will always fail without signature and tx must be rebuilt with signature anyways
setUsePermit(true);
const gas = gasLimitRecommendations[permitAction];
@@ -293,7 +332,9 @@ export const useTransactionHandler = ({
} else {
setUsePermit(false);
// For approval flow, set approval/action status and gas limit accordingly
- setApprovalTx(approvalTransaction);
+ if (approvalTransactions.length > 0) {
+ setApprovalTxes(approvalTransactions);
+ }
setActionTx(
txs.find((tx) =>
[
@@ -303,6 +344,7 @@ export const useTransactionHandler = ({
'STAKE_ACTION',
'GOV_DELEGATION_ACTION',
'GOVERNANCE_ACTION',
+ 'V3_MIGRATION_ACTION',
].includes(tx.txType)
)
);
@@ -315,7 +357,7 @@ export const useTransactionHandler = ({
for (const tx of txs) {
const txGas = await tx.gas();
// If permit is available, use regular action for estimation but exclude the approval tx
- if (txGas && txGas.gasLimit && !(tryPermit && tx.txType === 'ERC20_APPROVAL')) {
+ if (txGas && txGas.gasLimit) {
gasLimit = gasLimit + Number(txGas.gasLimit);
}
}
@@ -339,7 +381,7 @@ export const useTransactionHandler = ({
}, 1000);
return () => clearTimeout(timeout);
} else {
- setApprovalTx(undefined);
+ setApprovalTxes(undefined);
setActionTx(undefined);
}
}, [skip, ...deps, tryPermit, walletApprovalMethodPreference]);
@@ -348,7 +390,8 @@ export const useTransactionHandler = ({
approval,
action,
loadingTxns,
- requiresApproval: !!approvalTx || usePermit,
+ setUsePermit,
+ requiresApproval: !!approvalTxes || usePermit,
approvalTxState,
mainTxState,
usePermit,
diff --git a/src/hooks/app-data-provider/useAppDataProvider.tsx b/src/hooks/app-data-provider/useAppDataProvider.tsx
index fdcacc7066..c0fa3c6c2b 100644
--- a/src/hooks/app-data-provider/useAppDataProvider.tsx
+++ b/src/hooks/app-data-provider/useAppDataProvider.tsx
@@ -2,7 +2,6 @@ import { ReserveDataHumanized } from '@aave/contract-helpers';
import {
ComputedUserReserve,
formatReservesAndIncentives,
- formatUserSummaryAndIncentives,
FormatUserSummaryAndIncentivesResponse,
UserReserveData,
} from '@aave/math-utils';
@@ -11,7 +10,6 @@ import React, { useContext } from 'react';
import { EmodeCategory } from 'src/helpers/types';
import { useWeb3Context } from 'src/libs/hooks/useWeb3Context';
import { useRootStore } from 'src/store/root';
-import { fetchIconSymbolAndName } from 'src/ui-config/reservePatches';
import {
reserveSortFn,
@@ -20,9 +18,10 @@ import {
selectCurrentUserEmodeCategoryId,
selectCurrentUserReserves,
selectEmodes,
+ selectFormattedReserves,
+ selectUserSummaryAndIncentives,
} from '../../store/poolSelectors';
import { useCurrentTimestamp } from '../useCurrentTimestamp';
-import { useProtocolDataContext } from '../useProtocolDataContext';
/**
* removes the marketPrefix from a symbol
@@ -74,52 +73,24 @@ const AppDataContext = React.createContext({} as AppDataCont
export const AppDataProvider: React.FC = ({ children }) => {
const currentTimestamp = useCurrentTimestamp(5);
const { currentAccount } = useWeb3Context();
- const { currentNetworkConfig } = useProtocolDataContext();
const [
reserves,
baseCurrencyData,
userReserves,
userEmodeCategoryId,
- reserveIncentiveData,
- userIncentiveData,
eModes,
+ formattedPoolReserves,
+ user,
] = useRootStore((state) => [
selectCurrentReserves(state),
selectCurrentBaseCurrencyData(state),
selectCurrentUserReserves(state),
selectCurrentUserEmodeCategoryId(state),
- state.reserveIncentiveData,
- state.userIncentiveData,
selectEmodes(state),
+ selectFormattedReserves(state, currentTimestamp),
+ selectUserSummaryAndIncentives(state, currentTimestamp),
]);
- const formattedPoolReserves = formatReservesAndIncentives({
- reserves,
- currentTimestamp,
- marketReferenceCurrencyDecimals: baseCurrencyData.marketReferenceCurrencyDecimals,
- marketReferencePriceInUsd: baseCurrencyData.marketReferenceCurrencyPriceInUsd,
- reserveIncentives: reserveIncentiveData || [],
- })
- .map((r) => ({
- ...r,
- ...fetchIconSymbolAndName(r),
- isEmodeEnabled: r.eModeCategoryId !== 0,
- isWrappedBaseAsset:
- r.symbol.toLowerCase() === currentNetworkConfig.wrappedBaseAssetSymbol?.toLowerCase(),
- }))
- .sort(reserveSortFn);
-
- const user = formatUserSummaryAndIncentives({
- currentTimestamp,
- marketReferencePriceInUsd: baseCurrencyData.marketReferenceCurrencyPriceInUsd,
- marketReferenceCurrencyDecimals: baseCurrencyData.marketReferenceCurrencyDecimals,
- userReserves,
- formattedReserves: formattedPoolReserves,
- userEmodeCategoryId: userEmodeCategoryId,
- reserveIncentives: reserveIncentiveData || [],
- userIncentives: userIncentiveData || [],
- });
-
const proportions = user.userReservesData.reduce(
(acc, value) => {
const reserve = formattedPoolReserves.find(
diff --git a/src/hooks/useIsWrongNetwork.tsx b/src/hooks/useIsWrongNetwork.tsx
new file mode 100644
index 0000000000..27679fc196
--- /dev/null
+++ b/src/hooks/useIsWrongNetwork.tsx
@@ -0,0 +1,16 @@
+import { useWeb3Context } from 'src/libs/hooks/useWeb3Context';
+
+import { useProtocolDataContext } from './useProtocolDataContext';
+
+export function useIsWrongNetwork(_requiredChainId?: number) {
+ const { currentChainId } = useProtocolDataContext();
+ const { chainId: connectedChainId } = useWeb3Context();
+
+ const requiredChainId = _requiredChainId ? _requiredChainId : currentChainId;
+ const isWrongNetwork = connectedChainId !== requiredChainId;
+
+ return {
+ isWrongNetwork,
+ requiredChainId,
+ };
+}
diff --git a/src/hooks/useModal.tsx b/src/hooks/useModal.tsx
index 57ab2fa101..d6ed27d2c0 100644
--- a/src/hooks/useModal.tsx
+++ b/src/hooks/useModal.tsx
@@ -21,6 +21,7 @@ export enum ModalType {
Swap,
GovDelegation,
GovVote,
+ V3Migration,
}
export interface ModalArgsType {
@@ -58,6 +59,7 @@ export interface ModalContextType {
openFaucet: (underlyingAsset: string) => void;
openSwap: (underlyingAsset: string) => void;
openGovDelegation: () => void;
+ openV3Migration: () => void;
openGovVote: (proposalId: number, support: boolean, power: string) => void;
close: () => void;
type?: ModalType;
@@ -155,6 +157,9 @@ export const ModalContextProvider: React.FC = ({ children }) => {
setType(ModalType.GovVote);
setArgs({ proposalId, support, power });
},
+ openV3Migration: () => {
+ setType(ModalType.V3Migration);
+ },
close: () => {
setType(undefined);
setArgs({});
diff --git a/src/hooks/useUserReserves.tsx b/src/hooks/useUserReserves.tsx
new file mode 100644
index 0000000000..86bdd70b3b
--- /dev/null
+++ b/src/hooks/useUserReserves.tsx
@@ -0,0 +1,20 @@
+import {
+ selectNonEmptyUserBorrowPositions,
+ selectUserNonEmtpySummaryAndIncentive,
+} from 'src/store/poolSelectors';
+import { useRootStore } from 'src/store/root';
+
+import { useCurrentTimestamp } from './useCurrentTimestamp';
+
+//TODO: move that to selectors once appDataContext is removed
+export const useUserReserves = () => {
+ const currentTimestamp = useCurrentTimestamp(5);
+ const user = useRootStore((state) =>
+ selectUserNonEmtpySummaryAndIncentive(state, currentTimestamp)
+ );
+ const borrowPositions = useRootStore((state) =>
+ selectNonEmptyUserBorrowPositions(state, currentTimestamp)
+ );
+
+ return { user, borrowPositions };
+};
diff --git a/src/locales/en/messages.js b/src/locales/en/messages.js
index de59b02eb3..a169b22952 100644
--- a/src/locales/en/messages.js
+++ b/src/locales/en/messages.js
@@ -1 +1 @@
-/*eslint-disable*/module.exports={messages:{"<0>Ampleforth0> is a rebasing asset. Visit the <1>documentation1> to learn more.":"<0>Ampleforth0> is a rebasing asset. Visit the <1>documentation1> to learn more.","<0>Attention:0> Parameter changes via governance can alter your account health factor and risk of liquidation. Follow the <1>Aave governance forum1> for updates.":"<0>Attention:0> Parameter changes via governance can alter your account health factor and risk of liquidation. Follow the <1>Aave governance forum1> for updates.","<0>Slippage tolerance 0><1>{selectedSlippage}% 1><2>{0}2>":["<0>Slippage tolerance 0><1>",["selectedSlippage"],"% 1><2>",["0"],"2>"],"AAVE holders can stake their AAVE in the Safety Module (Ethereum Network only) to add more security to the protocol and earn Safety Incentives. In the case of a shortfall event, up to 30% of your stake can be slashed to cover the deficit, providing an additional layer of protection for the protocol.":"AAVE holders can stake their AAVE in the Safety Module (Ethereum Network only) to add more security to the protocol and earn Safety Incentives. In the case of a shortfall event, up to 30% of your stake can be slashed to cover the deficit, providing an additional layer of protection for the protocol.","ACTIVATE COOLDOWN":"ACTIVATE COOLDOWN","APR":"APR","APY":"APY","APY type":"APY type","APY, stable":"APY, stable","APY, variable":"APY, variable","AToken supply is not zero":"AToken supply is not zero","Aave Governance":"Aave Governance","Aave is a fully decentralized, community governed protocol by the AAVE token-holders. AAVE token-holders collectively discuss, propose, and vote on upgrades to the protocol. AAVE token-holders (Ethereum network only) can either vote themselves on new proposals or delagate to an address of choice. To learn more check out the Governance documentation":"Aave is a fully decentralized, community governed protocol by the AAVE token-holders. AAVE token-holders collectively discuss, propose, and vote on upgrades to the protocol. AAVE token-holders (Ethereum network only) can either vote themselves on new proposals or delagate to an address of choice. To learn more check out the Governance documentation","Aave per month":"Aave per month","Account":"Account","Action cannot be performed because the reserve is frozen":"Action cannot be performed because the reserve is frozen","Action cannot be performed because the reserve is paused":"Action cannot be performed because the reserve is paused","Action requires an active reserve":"Action requires an active reserve","Add to wallet":"Add to wallet","Add {0} to wallet to track your balance.":["Add ",["0"]," to wallet to track your balance."],"Address is not a contract":"Address is not a contract","Addresses ({0})":["Addresses (",["0"],")"],"All Assets":"All Assets","All done!":"All done!","All proposals":"All proposals","Allowance required action":"Allowance required action","Allows you to decide whether to use a supplied asset as collateral. An asset used as collateral will affect your borrowing power and health factor.":"Allows you to decide whether to use a supplied asset as collateral. An asset used as collateral will affect your borrowing power and health factor.","Allows you to switch between <0>variable0> and <1>stable1> interest rates, where variable rate can increase and decrease depending on the amount of liquidity in the reserve, and stable rate will stay the same for the duration of your loan.":"Allows you to switch between <0>variable0> and <1>stable1> interest rates, where variable rate can increase and decrease depending on the amount of liquidity in the reserve, and stable rate will stay the same for the duration of your loan.","Already on cooldown":"Already on cooldown","Amount":"Amount","Amount must be greater than 0":"Amount must be greater than 0","An error has occurred fetching the proposal metadata from IPFS.":"An error has occurred fetching the proposal metadata from IPFS.","Approve Confirmed":"Approve Confirmed","Approve with":"Approve with","Approve {symbol} to continue":["Approve ",["symbol"]," to continue"],"Approving {symbol}...":["Approving ",["symbol"],"..."],"Array parameters that should be equal length are not":"Array parameters that should be equal length are not","Asset":"Asset","Asset can only be used as collateral in isolation mode only.":"Asset can only be used as collateral in isolation mode only.","Asset cannot be used as collateral.":"Asset cannot be used as collateral.","Asset category":"Asset category","Asset is not borrowable in isolation mode":"Asset is not borrowable in isolation mode","Asset is not listed":"Asset is not listed","Asset supply is limited to a certain amount to reduce protocol exposure to the asset and to help manage risks involved.":"Asset supply is limited to a certain amount to reduce protocol exposure to the asset and to help manage risks involved.","Asset to delegate":"Asset to delegate","Assets":"Assets","Assets to borrow":"Assets to borrow","Assets to supply":"Assets to supply","Author":"Author","Available":"Available","Available assets":"Available assets","Available liquidity":"Available liquidity","Available rewards":"Available rewards","Available to borrow":"Available to borrow","Available to supply":"Available to supply","Back to Dashboard":"Back to Dashboard","Balance":"Balance","Be careful - You are very close to liquidation. Consider depositing more collateral or paying down some of your borrowed positions":"Be careful - You are very close to liquidation. Consider depositing more collateral or paying down some of your borrowed positions","Before supplying":"Before supplying","Blocked Address":"Blocked Address","Borrow":"Borrow","Borrow APY rate":"Borrow APY rate","Borrow APY, stable":"Borrow APY, stable","Borrow APY, variable":"Borrow APY, variable","Borrow and repay in same block is not allowed":"Borrow and repay in same block is not allowed","Borrow balance":"Borrow balance","Borrow balance after repay":"Borrow balance after repay","Borrow cap":"Borrow cap","Borrow cap is exceeded":"Borrow cap is exceeded","Borrow power used":"Borrow power used","Borrow {symbol}":["Borrow ",["symbol"]],"Borrowed":"Borrowed","Borrowing is currently unavailable for {0}.":["Borrowing is currently unavailable for ",["0"],"."],"Borrowing is disabled due to an Aave community decision. <0>More details0>":"Borrowing is disabled due to an Aave community decision. <0>More details0>","Borrowing is not enabled":"Borrowing is not enabled","Borrowing is unavailable because you’re using Isolation mode. To manage Isolation mode visit your <0>Dashboard0>.":"Borrowing is unavailable because you’re using Isolation mode. To manage Isolation mode visit your <0>Dashboard0>.","Borrowing is unavailable because you’ve enabled Efficiency Mode (E-Mode) and Isolation mode. To manage E-Mode and Isolation mode visit your <0>Dashboard0>.":"Borrowing is unavailable because you’ve enabled Efficiency Mode (E-Mode) and Isolation mode. To manage E-Mode and Isolation mode visit your <0>Dashboard0>.","Borrowing is unavailable because you’ve enabled Efficiency Mode (E-Mode) for {0} category. To manage E-Mode categories visit your <0>Dashboard0>.":["Borrowing is unavailable because you’ve enabled Efficiency Mode (E-Mode) for ",["0"]," category. To manage E-Mode categories visit your <0>Dashboard0>."],"Borrowing of this asset is limited to a certain amount to minimize liquidity pool insolvency.":"Borrowing of this asset is limited to a certain amount to minimize liquidity pool insolvency.","Borrowing power and assets are limited due to Isolation mode.":"Borrowing power and assets are limited due to Isolation mode.","Borrowing this amount will reduce your health factor and increase risk of liquidation.":"Borrowing this amount will reduce your health factor and increase risk of liquidation.","Borrowing {symbol}":["Borrowing ",["symbol"]],"Buy Crypto With Fiat":"Buy Crypto With Fiat","Buy Crypto with Fiat":"Buy Crypto with Fiat","Buy {cryptoSymbol} with Fiat":["Buy ",["cryptoSymbol"]," with Fiat"],"CLAIM {symbol}":["CLAIM ",["symbol"]],"CLAIMING {symbol}":["CLAIMING ",["symbol"]],"Can be collateral":"Can be collateral","Can be executed":"Can be executed","Cancel":"Cancel","Cannot disable E-Mode":"Cannot disable E-Mode","Cap reached. Lower supply amount":"Cap reached. Lower supply amount","Choose one of the on-ramp services":"Choose one of the on-ramp services","Claim":"Claim","Claim AAVE":"Claim AAVE","Claim all":"Claim all","Claim all rewards":"Claim all rewards","Claim {0}":["Claim ",["0"]],"Claimable AAVE":"Claimable AAVE","Claimed":"Claimed","Claiming":"Claiming","Close":"Close","Collateral":"Collateral","Collateral balance after repay":"Collateral balance after repay","Collateral is (mostly) the same currency that is being borrowed":"Collateral is (mostly) the same currency that is being borrowed","Collateral to repay with":"Collateral to repay with","Collateral usage":"Collateral usage","Collateral usage is limited because of Isolation mode.":"Collateral usage is limited because of Isolation mode.","Collateral usage is limited because of isolation mode. <0>Learn More0>":"Collateral usage is limited because of isolation mode. <0>Learn More0>","Collateralization":"Collateralization","Collector Contract":"Collector Contract","Collector Info":"Collector Info","Connect wallet":"Connect wallet","Cooldown period":"Cooldown period","Cooldown period warning":"Cooldown period warning","Cooldown time left":"Cooldown time left","Cooldown to unstake":"Cooldown to unstake","Cooling down...":"Cooling down...","Copy address":"Copy address","Copy error message":"Copy error message","Copy error text":"Copy error text","Created":"Created","Current LTV":"Current LTV","Current differential":"Current differential","Current votes":"Current votes","Dark mode":"Dark mode","Dashboard":"Dashboard","Data couldn't be fetched, please reload graph.":"Data couldn't be fetched, please reload graph.","Debt":"Debt","Debt ceiling is exceeded":"Debt ceiling is exceeded","Debt ceiling is not zero":"Debt ceiling is not zero","Debt ceiling limits the amount possible to borrow against this asset by protocol users. Debt ceiling is specific to assets in isolation mode and is denoted in USD.":"Debt ceiling limits the amount possible to borrow against this asset by protocol users. Debt ceiling is specific to assets in isolation mode and is denoted in USD.","Delegate":"Delegate","Delegating":"Delegating","Delegation":"Delegation","Details":"Details","Developers":"Developers","Differential":"Differential","Disable E-Mode":"Disable E-Mode","Disable testnet":"Disable testnet","Disable {symbol} as collateral":["Disable ",["symbol"]," as collateral"],"Disabled":"Disabled","Disabling E-Mode":"Disabling E-Mode","Disabling this asset as collateral affects your borrowing power and Health Factor.":"Disabling this asset as collateral affects your borrowing power and Health Factor.","Disconnect Wallet":"Disconnect Wallet","Discord":"Discord","Discord channel":"Discord channel","Due to a precision bug in the stETH contract, this asset can not be used in flashloan transactions":"Due to a precision bug in the stETH contract, this asset can not be used in flashloan transactions","Due to the Horizon bridge exploit, certain assets on the Harmony network are not at parity with Ethereum, which affects the Aave V3 Harmony market.":"Due to the Horizon bridge exploit, certain assets on the Harmony network are not at parity with Ethereum, which affects the Aave V3 Harmony market.","E-Mode":"E-Mode","E-Mode Category":"E-Mode Category","E-Mode category":"E-Mode category","E-Mode increases your LTV for a selected category of assets up to 97%. <0>Learn more0>":"E-Mode increases your LTV for a selected category of assets up to 97%. <0>Learn more0>","E-Mode increases your LTV for a selected category of assets up to<0/>. <1>Learn more1>":"E-Mode increases your LTV for a selected category of assets up to<0/>. <1>Learn more1>","E-Mode increases your LTV for a selected category of assets, meaning that when E-mode is enabled, you will have higher borrowing power over assets of the same E-mode category which are defined by Aave Governance. You can enter E-Mode from your <0>Dashboard0>. To learn more about E-Mode and applied restrictions in <1>FAQ1> or <2>Aave V3 Technical Paper2>.":"E-Mode increases your LTV for a selected category of assets, meaning that when E-mode is enabled, you will have higher borrowing power over assets of the same E-mode category which are defined by Aave Governance. You can enter E-Mode from your <0>Dashboard0>. To learn more about E-Mode and applied restrictions in <1>FAQ1> or <2>Aave V3 Technical Paper2>.","Efficiency mode (E-Mode)":"Efficiency mode (E-Mode)","Emode":"Emode","Enable E-Mode":"Enable E-Mode","Enable {symbol} as collateral":["Enable ",["symbol"]," as collateral"],"Enabled":"Enabled","Enabled in isolation":"Enabled in isolation","Enabling E-Mode":"Enabling E-Mode","Enabling E-Mode only allows you to borrow assets belonging to the selected category. Please visit our <0>FAQ guide0> to learn more about how it works and the applied restrictions.":"Enabling E-Mode only allows you to borrow assets belonging to the selected category. Please visit our <0>FAQ guide0> to learn more about how it works and the applied restrictions.","Enabling this asset as collateral increases your borrowing power and Health Factor. However, it can get liquidated if your health factor drops below 1.":"Enabling this asset as collateral increases your borrowing power and Health Factor. However, it can get liquidated if your health factor drops below 1.","Ended":"Ended","Ends":"Ends","English":"English","Enter ETH address":"Enter ETH address","Enter an amount":"Enter an amount","Error connecting. Try refreshing the page.":"Error connecting. Try refreshing the page.","Executed":"Executed","Expected amount to repay":"Expected amount to repay","Expires":"Expires","FAQ":"FAQ","Failed to load proposal voters. Please refresh the page.":"Failed to load proposal voters. Please refresh the page.","Faucet":"Faucet","Faucet {0}":["Faucet ",["0"]],"Fetching data...":"Fetching data...","Filter":"Filter","For repayment of a specific type of debt, the user needs to have debt that type":"For repayment of a specific type of debt, the user needs to have debt that type","Forum discussion":"Forum discussion","French":"French","Frozen assets":"Frozen assets","Funds in the Safety Module":"Funds in the Safety Module","Get ABP Token":"Get ABP Token","Github":"Github","Global settings":"Global settings","Go Back":"Go Back","Go to Balancer Pool":"Go to Balancer Pool","Governance":"Governance","Greek":"Greek","Health factor":"Health factor","Health factor is lesser than the liquidation threshold":"Health factor is lesser than the liquidation threshold","Health factor is not below the threshold":"Health factor is not below the threshold","Hide":"Hide","I acknowledge the risks involved.":"I acknowledge the risks involved.","I understand how cooldown ({0}) and unstaking ({1}) work":["I understand how cooldown (",["0"],") and unstaking (",["1"],") work"],"If the error continues to happen,<0/> you may report it to this":"If the error continues to happen,<0/> you may report it to this","If the health factor goes below 1, the liquidation of your collateral might be triggered.":"If the health factor goes below 1, the liquidation of your collateral might be triggered.","If you DO NOT unstake within {0} of unstake window, you will need to activate cooldown process again.":["If you DO NOT unstake within ",["0"]," of unstake window, you will need to activate cooldown process again."],"If your loan to value goes above the liquidation threshold your collateral supplied may be liquidated.":"If your loan to value goes above the liquidation threshold your collateral supplied may be liquidated.","In E-Mode some assets are not borrowable. Exit E-Mode to get access to all assets":"In E-Mode some assets are not borrowable. Exit E-Mode to get access to all assets","In Isolation mode, you cannot supply other assets as collateral. A global debt ceiling limits the borrowing power of the isolated asset. To exit isolation mode disable {0} as collateral before borrowing another asset. Read more in our <0>FAQ0>":["In Isolation mode, you cannot supply other assets as collateral. A global debt ceiling limits the borrowing power of the isolated asset. To exit isolation mode disable ",["0"]," as collateral before borrowing another asset. Read more in our <0>FAQ0>"],"Inconsistent flashloan parameters":"Inconsistent flashloan parameters","Interest rate rebalance conditions were not met":"Interest rate rebalance conditions were not met","Interest rate strategy":"Interest rate strategy","Invalid amount to burn":"Invalid amount to burn","Invalid amount to mint":"Invalid amount to mint","Invalid bridge protocol fee":"Invalid bridge protocol fee","Invalid expiration":"Invalid expiration","Invalid flashloan premium":"Invalid flashloan premium","Invalid return value of the flashloan executor function":"Invalid return value of the flashloan executor function","Invalid signature":"Invalid signature","Isolated":"Isolated","Isolated Debt Ceiling":"Isolated Debt Ceiling","Isolated assets have limited borrowing power and other assets cannot be used as collateral.":"Isolated assets have limited borrowing power and other assets cannot be used as collateral.","Join the community discussion":"Join the community discussion","Language":"Language","Learn more":"Learn more","Learn more about risks involved":"Learn more about risks involved","Learn more in our <0>FAQ guide0>":"Learn more in our <0>FAQ guide0>","Links":"Links","Liquidation <0/> threshold":"Liquidation <0/> threshold","Liquidation at":"Liquidation at","Liquidation penalty":"Liquidation penalty","Liquidation risk":"Liquidation risk","Liquidation risk parameters":"Liquidation risk parameters","Liquidation threshold":"Liquidation threshold","Liquidation value":"Liquidation value","Loading data...":"Loading data...","Ltv validation failed":"Ltv validation failed","MAX":"MAX","Market":"Market","Markets":"Markets","Max":"Max","Max LTV":"Max LTV","Max slashing":"Max slashing","Maximum amount available to borrow against this asset is limited because debt ceiling is at {0}%.":["Maximum amount available to borrow against this asset is limited because debt ceiling is at ",["0"],"%."],"Maximum amount available to borrow is limited because protocol borrow cap is nearly reached.":"Maximum amount available to borrow is limited because protocol borrow cap is nearly reached.","Maximum amount available to supply is <0/> {0} (<1/>).":["Maximum amount available to supply is <0/> ",["0"]," (<1/>)."],"Maximum amount available to supply is limited because protocol supply cap is at {0}%.":["Maximum amount available to supply is limited because protocol supply cap is at ",["0"],"%."],"Maximum loan to value":"Maximum loan to value","Menu":"Menu","More":"More","NAY":"NAY","Need help connecting a wallet? <0>Read our FAQ0>":"Need help connecting a wallet? <0>Read our FAQ0>","Net APR":"Net APR","Net APY":"Net APY","Net APY is the combined effect of all supply and borrow positions on net worth, including incentives. It is possible to have a negative net APY if debt APY is higher than supply APY.":"Net APY is the combined effect of all supply and borrow positions on net worth, including incentives. It is possible to have a negative net APY if debt APY is higher than supply APY.","Net worth":"Net worth","Network":"Network","Network not supported for this wallet":"Network not supported for this wallet","New APY":"New APY","No":"No","No rewards to claim":"No rewards to claim","No search results for":"No search results for","No voting power":"No voting power","None":"None","Not a valid address":"Not a valid address","Not enough balance on your wallet":"Not enough balance on your wallet","Not enough collateral to repay this amount of debt with":"Not enough collateral to repay this amount of debt with","Not enough staked balance":"Not enough staked balance","Not enough voting power to participate in this proposal":"Not enough voting power to participate in this proposal","Not reached":"Not reached","Nothing borrowed yet":"Nothing borrowed yet","Nothing staked":"Nothing staked","Nothing supplied yet":"Nothing supplied yet","Notify":"Notify","Ok, Close":"Ok, Close","Ok, I got it":"Ok, I got it","Operation not supported":"Operation not supported","Oracle price":"Oracle price","Overview":"Overview","Page not found":"Page not found","Participating in this {symbol} reserve gives annualized rewards.":["Participating in this ",["symbol"]," reserve gives annualized rewards."],"Pending...":"Pending...","Per the community, the Fantom market has been frozen.":"Per the community, the Fantom market has been frozen.","Please connect a wallet to view your personal information here.":"Please connect a wallet to view your personal information here.","Please connect your wallet to get free testnet assets.":"Please connect your wallet to get free testnet assets.","Please connect your wallet to see your supplies, borrowings, and open positions.":"Please connect your wallet to see your supplies, borrowings, and open positions.","Please enter a valid wallet address.":"Please enter a valid wallet address.","Please switch to {networkName}.":["Please switch to ",["networkName"],"."],"Please, connect your wallet":"Please, connect your wallet","Pool addresses provider is not registered":"Pool addresses provider is not registered","Powered by":"Powered by","Price impact is the spread between the total value of the entry tokens swapped and the destination tokens obtained (in USD), which results from the limited liquidity of the trading pair.":"Price impact is the spread between the total value of the entry tokens swapped and the destination tokens obtained (in USD), which results from the limited liquidity of the trading pair.","Price impact {0}%":["Price impact ",["0"],"%"],"Proposal details":"Proposal details","Proposal overview":"Proposal overview","Proposals":"Proposals","Proposition power":"Proposition power","Protocol borrow cap at 100% for this asset. Further borrowing unavailable.":"Protocol borrow cap at 100% for this asset. Further borrowing unavailable.","Protocol borrow cap is at 100% for this asset. Further borrowing unavailable.":"Protocol borrow cap is at 100% for this asset. Further borrowing unavailable.","Protocol debt ceiling is at 100% for this asset. Further borrowing against this asset is unavailable.":"Protocol debt ceiling is at 100% for this asset. Further borrowing against this asset is unavailable.","Protocol debt ceiling is at 100% for this asset. Futher borrowing against this asset is unavailable.":"Protocol debt ceiling is at 100% for this asset. Futher borrowing against this asset is unavailable.","Protocol supply cap at 100% for this asset. Further supply unavailable.":"Protocol supply cap at 100% for this asset. Further supply unavailable.","Protocol supply cap is at 100% for this asset. Further supply unavailable.":"Protocol supply cap is at 100% for this asset. Further supply unavailable.","Quorum":"Quorum","Raw-Ipfs":"Raw-Ipfs","Reached":"Reached","Read-only mode allows to see address positions in Aave, but you won't be able to perform transactions.":"Read-only mode allows to see address positions in Aave, but you won't be able to perform transactions.","Read-only mode.":"Read-only mode.","Read-only mode. Connect to a wallet to perform transactions.":"Read-only mode. Connect to a wallet to perform transactions.","Received":"Received","Recipient address":"Recipient address","Rejected connection request":"Rejected connection request","Reload":"Reload","Reload the page":"Reload the page","Remaining debt":"Remaining debt","Remaining supply":"Remaining supply","Repaid":"Repaid","Repay":"Repay","Repay with":"Repay with","Repay {symbol}":["Repay ",["symbol"]],"Repaying {symbol}":["Repaying ",["symbol"]],"Reserve Size":"Reserve Size","Reserve factor":"Reserve factor","Reserve factor is a percentage of interest which goes to a {0} that is controlled by Aave governance to promote ecosystem growth.":["Reserve factor is a percentage of interest which goes to a ",["0"]," that is controlled by Aave governance to promote ecosystem growth."],"Reserve status & configuration":"Reserve status & configuration","Review approval tx details":"Review approval tx details","Review tx":"Review tx","Review tx details":"Review tx details","Reward(s) to claim":"Reward(s) to claim","Rewards APR":"Rewards APR","Risk details":"Risk details","SEE CHARTS":"SEE CHARTS","Safety of your deposited collateral against the borrowed assets and its underlying value.":"Safety of your deposited collateral against the borrowed assets and its underlying value.","Seatbelt report":"Seatbelt report","Seems like we can't switch the network automatically. Please check if you can change it from the wallet.":"Seems like we can't switch the network automatically. Please check if you can change it from the wallet.","Select":"Select","Select APY type to switch":"Select APY type to switch","Select language":"Select language","Select slippage tolerance":"Select slippage tolerance","Select token to add":"Select token to add","Select token to view in block explorer":"Select token to view in block explorer","Setup notifications about your Health Factor using the Hal app.":"Setup notifications about your Health Factor using the Hal app.","Share on twitter":"Share on twitter","Show":"Show","Show assets with 0 balance":"Show assets with 0 balance","Since this asset is frozen, the only available actions are withdraw and repay which can be accessed from the <0>Dashboard0>":"Since this asset is frozen, the only available actions are withdraw and repay which can be accessed from the <0>Dashboard0>","Since this is a test network, you can get any of the assets if you have ETH on your wallet":"Since this is a test network, you can get any of the assets if you have ETH on your wallet","Slippage is the difference between the quoted and received amounts from changing market conditions between the moment the transaction is submitted and its verification.":"Slippage is the difference between the quoted and received amounts from changing market conditions between the moment the transaction is submitted and its verification.","Something went wrong":"Something went wrong","Sorry, an unexpected error happened. In the meantime you may try reloading the page, or come back later.":"Sorry, an unexpected error happened. In the meantime you may try reloading the page, or come back later.","Sorry, we couldn't find the page you were looking for.":"Sorry, we couldn't find the page you were looking for.","Spanish":"Spanish","Stable":"Stable","Stable Interest Type is disabled for this currency":"Stable Interest Type is disabled for this currency","Stable borrowing is enabled":"Stable borrowing is enabled","Stable borrowing is not enabled":"Stable borrowing is not enabled","Stable debt supply is not zero":"Stable debt supply is not zero","Stable interest rate will <0>stay the same0> for the duration of your loan. Recommended for long-term loan periods and for users who prefer predictability.":"Stable interest rate will <0>stay the same0> for the duration of your loan. Recommended for long-term loan periods and for users who prefer predictability.","Stablecoin":"Stablecoin","Stake":"Stake","Stake AAVE":"Stake AAVE","Stake ABPT":"Stake ABPT","Stake cooldown activated":"Stake cooldown activated","Staked":"Staked","Staking":"Staking","Staking APR":"Staking APR","Staking Rewards":"Staking Rewards","Staking balance":"Staking balance","Started":"Started","State":"State","Supplied":"Supplied","Supplied asset amount":"Supplied asset amount","Supply":"Supply","Supply APY":"Supply APY","Supply apy":"Supply apy","Supply balance":"Supply balance","Supply balance after swap":"Supply balance after swap","Supply cap is exceeded":"Supply cap is exceeded","Supply cap on target reserve reached. Try lowering the amount.":"Supply cap on target reserve reached. Try lowering the amount.","Supply {symbol}":["Supply ",["symbol"]],"Supplying your":"Supplying your","Supplying {symbol}":["Supplying ",["symbol"]],"Swap":"Swap","Swap to":"Swap to","Swapped":"Swapped","Swapping":"Swapping","Switch APY type":"Switch APY type","Switch E-Mode":"Switch E-Mode","Switch E-Mode category":"Switch E-Mode category","Switch Network":"Switch Network","Switch rate":"Switch rate","Switching E-Mode":"Switching E-Mode","Switching rate":"Switching rate","Test Assets":"Test Assets","Testnet mode":"Testnet mode","Testnet mode is ON":"Testnet mode is ON","The % of your total borrowing power used. This is based on the amount of your collateral supplied and the total amount that you can borrow.":"The % of your total borrowing power used. This is based on the amount of your collateral supplied and the total amount that you can borrow.","The Aave Balancer Pool Token (ABPT) is a liquidity pool token. You can receive ABPT by depositing a combination of AAVE + ETH in the Balancer liquidity pool. You can then stake your BPT in the Safety Module to secure the protocol and earn Safety Incentives.":"The Aave Balancer Pool Token (ABPT) is a liquidity pool token. You can receive ABPT by depositing a combination of AAVE + ETH in the Balancer liquidity pool. You can then stake your BPT in the Safety Module to secure the protocol and earn Safety Incentives.","The Maximum LTV ratio represents the maximum borrowing power of a specific collateral. For example, if a collateral has an LTV of 75%, the user can borrow up to 0.75 worth of ETH in the principal currency for every 1 ETH worth of collateral.":"The Maximum LTV ratio represents the maximum borrowing power of a specific collateral. For example, if a collateral has an LTV of 75%, the user can borrow up to 0.75 worth of ETH in the principal currency for every 1 ETH worth of collateral.","The Stable Rate is not enabled for this currency":"The Stable Rate is not enabled for this currency","The address of the pool addresses provider is invalid":"The address of the pool addresses provider is invalid","The app is running in testnet mode. Learn how it works in":"The app is running in testnet mode. Learn how it works in","The caller of the function is not an AToken":"The caller of the function is not an AToken","The caller of this function must be a pool":"The caller of this function must be a pool","The collateral balance is 0":"The collateral balance is 0","The collateral chosen cannot be liquidated":"The collateral chosen cannot be liquidated","The cooldown period is the time required prior to unstaking your tokens(10 days). You can only withdraw your assets from the Security Module after the cooldown period and within the active the unstake window.<0>Learn more0>":"The cooldown period is the time required prior to unstaking your tokens(10 days). You can only withdraw your assets from the Security Module after the cooldown period and within the active the unstake window.<0>Learn more0>","The cooldown period is {0}. After {1} of cooldown, you will enter unstake window of {2}. You will continue receiving rewards during cooldown and unstake window.":["The cooldown period is ",["0"],". After ",["1"]," of cooldown, you will enter unstake window of ",["2"],". You will continue receiving rewards during cooldown and unstake window."],"The effects on the health factor would cause liquidation. Try lowering the amount.":"The effects on the health factor would cause liquidation. Try lowering the amount.","The requested amount is greater than the max loan size in stable rate mode":"The requested amount is greater than the max loan size in stable rate mode","The total amount of your assets denominated in USD that can be used as collateral for borrowing assets.":"The total amount of your assets denominated in USD that can be used as collateral for borrowing assets.","The underlying asset cannot be rescued":"The underlying asset cannot be rescued","The underlying balance needs to be greater than 0":"The underlying balance needs to be greater than 0","The weighted average of APY for all borrowed assets, including incentives.":"The weighted average of APY for all borrowed assets, including incentives.","The weighted average of APY for all supplied assets, including incentives.":"The weighted average of APY for all supplied assets, including incentives.","There are not enough funds in the{0}reserve to borrow":["There are not enough funds in the",["0"],"reserve to borrow"],"There is not enough collateral to cover a new borrow":"There is not enough collateral to cover a new borrow","There was some error. Please try changing the parameters or <0><1>copy the error1>0>":"There was some error. Please try changing the parameters or <0><1>copy the error1>0>","These assets are temporarily frozen by Aave community decisions, meaning that further supply / borrow, or rate swap of these assets are unavailable. Withdrawals and debt repayments are allowed. Follow the <0>Aave governance forum0> for further updates.":"These assets are temporarily frozen by Aave community decisions, meaning that further supply / borrow, or rate swap of these assets are unavailable. Withdrawals and debt repayments are allowed. Follow the <0>Aave governance forum0> for further updates.","These funds have been borrowed and are not available for withdrawal at this time.":"These funds have been borrowed and are not available for withdrawal at this time.","This action will reduce your health factor. Please be mindful of the increased risk of collateral liquidation.":"This action will reduce your health factor. Please be mindful of the increased risk of collateral liquidation.","This address is blocked on app.aave.com because it is associated with one or more":"This address is blocked on app.aave.com because it is associated with one or more","This asset has almost reached its borrow cap. There is only {messageValue} available to be borrowed from this market.":["This asset has almost reached its borrow cap. There is only ",["messageValue"]," available to be borrowed from this market."],"This asset has almost reached its supply cap. There can only be {messageValue} supplied to this market.":["This asset has almost reached its supply cap. There can only be ",["messageValue"]," supplied to this market."],"This asset has reached its borrow cap. Nothing is available to be borrowed from this market.":"This asset has reached its borrow cap. Nothing is available to be borrowed from this market.","This asset has reached its supply cap. Nothing is available to be supplied from this market.":"This asset has reached its supply cap. Nothing is available to be supplied from this market.","This asset is frozen due to an Aave Protocol Governance decision. <0>More details0>":"This asset is frozen due to an Aave Protocol Governance decision. <0>More details0>","This asset is frozen due to an Aave Protocol Governance decision. On the 20th of December 2022, renFIL will no longer be supported and cannot be bridged back to its native network. It is recommended to withdraw supply positions and repay borrow positions so that renFIL can be bridged back to FIL before the deadline. After this date, it will no longer be possible to convert renFIL to FIL. <0>More details0>":"This asset is frozen due to an Aave Protocol Governance decision. On the 20th of December 2022, renFIL will no longer be supported and cannot be bridged back to its native network. It is recommended to withdraw supply positions and repay borrow positions so that renFIL can be bridged back to FIL before the deadline. After this date, it will no longer be possible to convert renFIL to FIL. <0>More details0>","This asset is frozen due to an Aave community decision. <0>More details0>":"This asset is frozen due to an Aave community decision. <0>More details0>","This gas calculation is only an estimation. Your wallet will set the price of the transaction. You can modify the gas settings directly from your wallet provider.":"This gas calculation is only an estimation. Your wallet will set the price of the transaction. You can modify the gas settings directly from your wallet provider.","This integration was<0>proposed and approved0>by the community.":"This integration was<0>proposed and approved0>by the community.","This is the total amount available for you to borrow. You can borrow based on your collateral and until the borrow cap is reached.":"This is the total amount available for you to borrow. You can borrow based on your collateral and until the borrow cap is reached.","This is the total amount that you are able to supply to in this reserve. You are able to supply your wallet balance up until the supply cap is reached.":"This is the total amount that you are able to supply to in this reserve. You are able to supply your wallet balance up until the supply cap is reached.","This represents the threshold at which a borrow position will be considered undercollateralized and subject to liquidation for each collateral. For example, if a collateral has a liquidation threshold of 80%, it means that the position will be liquidated when the debt value is worth 80% of the collateral value.":"This represents the threshold at which a borrow position will be considered undercollateralized and subject to liquidation for each collateral. For example, if a collateral has a liquidation threshold of 80%, it means that the position will be liquidated when the debt value is worth 80% of the collateral value.","Time left to be able to withdraw your staked asset.":"Time left to be able to withdraw your staked asset.","Time left to unstake":"Time left to unstake","Time left until the withdrawal window closes.":"Time left until the withdrawal window closes.","To borrow you need to supply any asset to be used as collateral.":"To borrow you need to supply any asset to be used as collateral.","To continue, you need to grant Aave smart contracts permission to move your funds from your wallet. Depending on the asset and wallet you use, it is done by signing the permission message (gas free), or by submitting an approval transaction (requires gas). <0>Learn more0>":"To continue, you need to grant Aave smart contracts permission to move your funds from your wallet. Depending on the asset and wallet you use, it is done by signing the permission message (gas free), or by submitting an approval transaction (requires gas). <0>Learn more0>","To enable E-mode for the {0} category, all borrow positions outside of this cateogry must be closed.":["To enable E-mode for the ",["0"]," category, all borrow positions outside of this cateogry must be closed."],"To repay on behalf of a user an explicit amount to repay is needed":"To repay on behalf of a user an explicit amount to repay is needed","To request access for this permissioned market, please visit: <0>Acces Provider Name0>":"To request access for this permissioned market, please visit: <0>Acces Provider Name0>","Top 10 addresses":"Top 10 addresses","Total available":"Total available","Total borrowed":"Total borrowed","Total borrows":"Total borrows","Total emission per day":"Total emission per day","Total market size":"Total market size","Total supplied":"Total supplied","Total voting power":"Total voting power","Total worth":"Total worth","Track wallet":"Track wallet","Track wallet balance in read-only mode":"Track wallet balance in read-only mode","Transaction failed":"Transaction failed","Transaction overview":"Transaction overview","Type of delegation":"Type of delegation","UNSTAKE {symbol}":["UNSTAKE ",["symbol"]],"UNSTAKING {symbol}":["UNSTAKING ",["symbol"]],"Unavailable":"Unavailable","Unbacked":"Unbacked","Unbacked mint cap is exceeded":"Unbacked mint cap is exceeded","Unstake now":"Unstake now","Unstake window":"Unstake window","Unstaked":"Unstaked","Used as collateral":"Used as collateral","User cannot withdraw more than the available balance":"User cannot withdraw more than the available balance","User did not borrow the specified currency":"User did not borrow the specified currency","User does not have outstanding stable rate debt on this reserve":"User does not have outstanding stable rate debt on this reserve","User does not have outstanding variable rate debt on this reserve":"User does not have outstanding variable rate debt on this reserve","User is in isolation mode":"User is in isolation mode","User is trying to borrow multiple assets including a siloed one":"User is trying to borrow multiple assets including a siloed one","Utilization Rate":"Utilization Rate","VOTE NAY":"VOTE NAY","VOTE YAE":"VOTE YAE","Variable":"Variable","Variable debt supply is not zero":"Variable debt supply is not zero","Variable interest rate will <0>fluctuate0> based on the market conditions. Recommended for short-term positions.":"Variable interest rate will <0>fluctuate0> based on the market conditions. Recommended for short-term positions.","Version 2":"Version 2","Version 3":"Version 3","View all votes":"View all votes","View contract":"View contract","View details":"View details","View on Explorer":"View on Explorer","Vote":"Vote","Vote NAY":"Vote NAY","Vote YAE":"Vote YAE","Voted NAY":"Voted NAY","Voted YAE":"Voted YAE","Votes":"Votes","Voting power":"Voting power","Voting results":"Voting results","Wallet Balance":"Wallet Balance","Wallet balance":"Wallet balance","Wallet not detected. Connect or install wallet and retry":"Wallet not detected. Connect or install wallet and retry","Wallets are provided by External Providers and by selecting you agree to Terms of those Providers. Your access to the wallet might be reliant on the External Provider being operational.":"Wallets are provided by External Providers and by selecting you agree to Terms of those Providers. Your access to the wallet might be reliant on the External Provider being operational.","We couldn't find any assets related to your search. Try again with a different asset name, symbol, or address.":"We couldn't find any assets related to your search. Try again with a different asset name, symbol, or address.","We couldn’t detect a wallet. Connect a wallet to stake and view your balance.":"We couldn’t detect a wallet. Connect a wallet to stake and view your balance.","We suggest you go back to the Dashboard.":"We suggest you go back to the Dashboard.","When a liquidation occurs, liquidators repay up to 50% of the outstanding borrowed amount on behalf of the borrower. In return, they can buy the collateral at a discount and keep the difference (liquidation penalty) as a bonus.":"When a liquidation occurs, liquidators repay up to 50% of the outstanding borrowed amount on behalf of the borrower. In return, they can buy the collateral at a discount and keep the difference (liquidation penalty) as a bonus.","With a voting power of <0/>":"With a voting power of <0/>","With testnet Faucet you can get free assets to test the Aave Protocol. Make sure to switch your wallet provider to the appropriate testnet network, select desired asset, and click ‘Faucet’ to get tokens transferred to your wallet. The assets on a testnet are not “real,” meaning they have no monetary value. <0>Learn more0>":"With testnet Faucet you can get free assets to test the Aave Protocol. Make sure to switch your wallet provider to the appropriate testnet network, select desired asset, and click ‘Faucet’ to get tokens transferred to your wallet. The assets on a testnet are not “real,” meaning they have no monetary value. <0>Learn more0>","Withdraw":"Withdraw","Withdraw {symbol}":["Withdraw ",["symbol"]],"Withdrawing this amount will reduce your health factor and increase risk of liquidation.":"Withdrawing this amount will reduce your health factor and increase risk of liquidation.","Withdrawing {symbol}":["Withdrawing ",["symbol"]],"Wrong Network":"Wrong Network","YAE":"YAE","Yes":"Yes","You are entering Isolation mode":"You are entering Isolation mode","You can borrow this asset with a stable rate only if you borrow more than the amount you are supplying as collateral.":"You can borrow this asset with a stable rate only if you borrow more than the amount you are supplying as collateral.","You can not change Interest Type to stable as your borrowings are higher than your collateral":"You can not change Interest Type to stable as your borrowings are higher than your collateral","You can not disable E-Mode as your current collateralization level is above 80%, disabling E-Mode can cause liquidation. To exit E-Mode supply or repay borrowed positions.":"You can not disable E-Mode as your current collateralization level is above 80%, disabling E-Mode can cause liquidation. To exit E-Mode supply or repay borrowed positions.","You can not switch usage as collateral mode for this currency, because it will cause collateral call":"You can not switch usage as collateral mode for this currency, because it will cause collateral call","You can not use this currency as collateral":"You can not use this currency as collateral","You can not withdraw this amount because it will cause collateral call":"You can not withdraw this amount because it will cause collateral call","You can only withdraw your assets from the Security Module after the cooldown period ends and the unstake window is active.":"You can only withdraw your assets from the Security Module after the cooldown period ends and the unstake window is active.","You can report incident to our <0>Discord0> or <1>Github1>.":"You can report incident to our <0>Discord0> or <1>Github1>.","You cancelled the transaction.":"You cancelled the transaction.","You did not participate in this proposal":"You did not participate in this proposal","You do not have supplies in this currency":"You do not have supplies in this currency","You don’t have enough funds in your wallet to repay the full amount. If you proceed to repay with your current amount of funds, you will still have a small borrowing position in your dashboard.":"You don’t have enough funds in your wallet to repay the full amount. If you proceed to repay with your current amount of funds, you will still have a small borrowing position in your dashboard.","You have not borrow yet using this currency":"You have not borrow yet using this currency","You switched to {0} rate":["You switched to ",["0"]," rate"],"You unstake here":"You unstake here","You voted {0}":["You voted ",["0"]],"You will exit isolation mode and other tokens can now be used as collateral":"You will exit isolation mode and other tokens can now be used as collateral","You {action} <0/> {symbol}":["You ",["action"]," <0/> ",["symbol"]],"Your borrows":"Your borrows","Your current loan to value based on your collateral supplied.":"Your current loan to value based on your collateral supplied.","Your health factor and loan to value determine the assurance of your collateral. To avoid liquidations you can supply more collateral or repay borrow positions.":"Your health factor and loan to value determine the assurance of your collateral. To avoid liquidations you can supply more collateral or repay borrow positions.","Your info":"Your info","Your reward balance is 0":"Your reward balance is 0","Your supplies":"Your supplies","Your voting info":"Your voting info","Your {name} wallet is empty. Purchase or transfer assets or use <0>{0}0> to transfer your {network} assets.":["Your ",["name"]," wallet is empty. Purchase or transfer assets or use <0>",["0"],"0> to transfer your ",["network"]," assets."],"Your {name} wallet is empty. Purchase or transfer assets.":["Your ",["name"]," wallet is empty. Purchase or transfer assets."],"Your {networkName} wallet is empty. Get free test assets at":["Your ",["networkName"]," wallet is empty. Get free test assets at"],"Your {networkName} wallet is empty. Get free test {0} at":["Your ",["networkName"]," wallet is empty. Get free test ",["0"]," at"],"Zero address not valid":"Zero address not valid","assets":"assets","blocked activities":"blocked activities","copy the error":"copy the error","ends":"ends","here.":"here.","of":"of","on":"on","please check that the amount you want to supply is not currently being used for staking. If it is being used for staking, your transaction might fail.":"please check that the amount you want to supply is not currently being used for staking. If it is being used for staking, your transaction might fail.","repaid":"repaid","stETH supplied as collateral will continue to accrue staking rewards provided by daily rebases.":"stETH supplied as collateral will continue to accrue staking rewards provided by daily rebases.","staking view":"staking view","starts":"starts","tokens is not the same as staking them. If you wish to stake your":"tokens is not the same as staking them. If you wish to stake your","tokens, please go to the":"tokens, please go to the","withdrew":"withdrew","{0}":[["0"]],"{0} Balance":[["0"]," Balance"],"{0} Faucet":[["0"]," Faucet"],"{0} on-ramp service is provided by External Provider and by selecting you agree to Terms of the Provider. Your access to the service might be reliant on the External Provider being operational.":[["0"]," on-ramp service is provided by External Provider and by selecting you agree to Terms of the Provider. Your access to the service might be reliant on the External Provider being operational."],"{0}{name}":[["0"],["name"]],"{currentMethod}":[["currentMethod"]],"{d}d":[["d"],"d"],"{h}h":[["h"],"h"],"{m}m":[["m"],"m"],"{networkName} Faucet":[["networkName"]," Faucet"],"{s}s":[["s"],"s"],"{tooltipText}":[["tooltipText"]]}};
\ No newline at end of file
+/*eslint-disable*/module.exports={messages:{"<0>Ampleforth0> is a rebasing asset. Visit the <1>documentation1> to learn more.":"<0>Ampleforth0> is a rebasing asset. Visit the <1>documentation1> to learn more.","<0>Attention:0> Parameter changes via governance can alter your account health factor and risk of liquidation. Follow the <1>Aave governance forum1> for updates.":"<0>Attention:0> Parameter changes via governance can alter your account health factor and risk of liquidation. Follow the <1>Aave governance forum1> for updates.","<0>Slippage tolerance 0><1>{selectedSlippage}% 1><2>{0}2>":["<0>Slippage tolerance 0><1>",["selectedSlippage"],"% 1><2>",["0"],"2>"],"AAVE holders can stake their AAVE in the Safety Module (Ethereum Network only) to add more security to the protocol and earn Safety Incentives. In the case of a shortfall event, up to 30% of your stake can be slashed to cover the deficit, providing an additional layer of protection for the protocol.":"AAVE holders can stake their AAVE in the Safety Module (Ethereum Network only) to add more security to the protocol and earn Safety Incentives. In the case of a shortfall event, up to 30% of your stake can be slashed to cover the deficit, providing an additional layer of protection for the protocol.","ACTIVATE COOLDOWN":"ACTIVATE COOLDOWN","APR":"APR","APY":"APY","APY type":"APY type","APY, stable":"APY, stable","APY, variable":"APY, variable","AToken supply is not zero":"AToken supply is not zero","Aave Governance":"Aave Governance","Aave is a fully decentralized, community governed protocol by the AAVE token-holders. AAVE token-holders collectively discuss, propose, and vote on upgrades to the protocol. AAVE token-holders (Ethereum network only) can either vote themselves on new proposals or delagate to an address of choice. To learn more check out the Governance documentation":"Aave is a fully decentralized, community governed protocol by the AAVE token-holders. AAVE token-holders collectively discuss, propose, and vote on upgrades to the protocol. AAVE token-holders (Ethereum network only) can either vote themselves on new proposals or delagate to an address of choice. To learn more check out the Governance documentation","Aave per month":"Aave per month","Account":"Account","Action cannot be performed because the reserve is frozen":"Action cannot be performed because the reserve is frozen","Action cannot be performed because the reserve is paused":"Action cannot be performed because the reserve is paused","Action requires an active reserve":"Action requires an active reserve","Add to wallet":"Add to wallet","Add {0} to wallet to track your balance.":["Add ",["0"]," to wallet to track your balance."],"Address is not a contract":"Address is not a contract","Addresses ({0})":["Addresses (",["0"],")"],"All Assets":"All Assets","All done!":"All done!","All proposals":"All proposals","Allowance required action":"Allowance required action","Allows you to decide whether to use a supplied asset as collateral. An asset used as collateral will affect your borrowing power and health factor.":"Allows you to decide whether to use a supplied asset as collateral. An asset used as collateral will affect your borrowing power and health factor.","Allows you to switch between <0>variable0> and <1>stable1> interest rates, where variable rate can increase and decrease depending on the amount of liquidity in the reserve, and stable rate will stay the same for the duration of your loan.":"Allows you to switch between <0>variable0> and <1>stable1> interest rates, where variable rate can increase and decrease depending on the amount of liquidity in the reserve, and stable rate will stay the same for the duration of your loan.","Already on cooldown":"Already on cooldown","Amount":"Amount","Amount must be greater than 0":"Amount must be greater than 0","An error has occurred fetching the proposal metadata from IPFS.":"An error has occurred fetching the proposal metadata from IPFS.","Approve Confirmed":"Approve Confirmed","Approve with":"Approve with","Approve {symbol} to continue":["Approve ",["symbol"]," to continue"],"Approving {symbol}...":["Approving ",["symbol"],"..."],"Array parameters that should be equal length are not":"Array parameters that should be equal length are not","Asset":"Asset","Asset can only be used as collateral in isolation mode only.":"Asset can only be used as collateral in isolation mode only.","Asset cannot be used as collateral.":"Asset cannot be used as collateral.","Asset category":"Asset category","Asset is not borrowable in isolation mode":"Asset is not borrowable in isolation mode","Asset is not listed":"Asset is not listed","Asset supply is limited to a certain amount to reduce protocol exposure to the asset and to help manage risks involved.":"Asset supply is limited to a certain amount to reduce protocol exposure to the asset and to help manage risks involved.","Asset to delegate":"Asset to delegate","Assets":"Assets","Assets to borrow":"Assets to borrow","Assets to supply":"Assets to supply","Author":"Author","Available":"Available","Available assets":"Available assets","Available liquidity":"Available liquidity","Available rewards":"Available rewards","Available to borrow":"Available to borrow","Available to supply":"Available to supply","Back to Dashboard":"Back to Dashboard","Balance":"Balance","Be careful - You are very close to liquidation. Consider depositing more collateral or paying down some of your borrowed positions":"Be careful - You are very close to liquidation. Consider depositing more collateral or paying down some of your borrowed positions","Be mindful of the network congestion and gas prices.":"Be mindful of the network congestion and gas prices.","Before supplying":"Before supplying","Blocked Address":"Blocked Address","Borrow":"Borrow","Borrow APY rate":"Borrow APY rate","Borrow APY, stable":"Borrow APY, stable","Borrow APY, variable":"Borrow APY, variable","Borrow and repay in same block is not allowed":"Borrow and repay in same block is not allowed","Borrow balance":"Borrow balance","Borrow balance after repay":"Borrow balance after repay","Borrow cap":"Borrow cap","Borrow cap is exceeded":"Borrow cap is exceeded","Borrow power used":"Borrow power used","Borrow {symbol}":["Borrow ",["symbol"]],"Borrowed":"Borrowed","Borrowing is currently unavailable for {0}.":["Borrowing is currently unavailable for ",["0"],"."],"Borrowing is disabled due to an Aave community decision. <0>More details0>":"Borrowing is disabled due to an Aave community decision. <0>More details0>","Borrowing is not enabled":"Borrowing is not enabled","Borrowing is unavailable because you’re using Isolation mode. To manage Isolation mode visit your <0>Dashboard0>.":"Borrowing is unavailable because you’re using Isolation mode. To manage Isolation mode visit your <0>Dashboard0>.","Borrowing is unavailable because you’ve enabled Efficiency Mode (E-Mode) and Isolation mode. To manage E-Mode and Isolation mode visit your <0>Dashboard0>.":"Borrowing is unavailable because you’ve enabled Efficiency Mode (E-Mode) and Isolation mode. To manage E-Mode and Isolation mode visit your <0>Dashboard0>.","Borrowing is unavailable because you’ve enabled Efficiency Mode (E-Mode) for {0} category. To manage E-Mode categories visit your <0>Dashboard0>.":["Borrowing is unavailable because you’ve enabled Efficiency Mode (E-Mode) for ",["0"]," category. To manage E-Mode categories visit your <0>Dashboard0>."],"Borrowing of this asset is limited to a certain amount to minimize liquidity pool insolvency.":"Borrowing of this asset is limited to a certain amount to minimize liquidity pool insolvency.","Borrowing power and assets are limited due to Isolation mode.":"Borrowing power and assets are limited due to Isolation mode.","Borrowing this amount will reduce your health factor and increase risk of liquidation.":"Borrowing this amount will reduce your health factor and increase risk of liquidation.","Borrowing {symbol}":["Borrowing ",["symbol"]],"Buy Crypto With Fiat":"Buy Crypto With Fiat","Buy Crypto with Fiat":"Buy Crypto with Fiat","Buy {cryptoSymbol} with Fiat":["Buy ",["cryptoSymbol"]," with Fiat"],"CLAIM {symbol}":["CLAIM ",["symbol"]],"CLAIMING {symbol}":["CLAIMING ",["symbol"]],"Can be collateral":"Can be collateral","Can be executed":"Can be executed","Cancel":"Cancel","Cannot disable E-Mode":"Cannot disable E-Mode","Cap reached. Lower supply amount":"Cap reached. Lower supply amount","Choose one of the on-ramp services":"Choose one of the on-ramp services","Claim":"Claim","Claim AAVE":"Claim AAVE","Claim all":"Claim all","Claim all rewards":"Claim all rewards","Claim {0}":["Claim ",["0"]],"Claimable AAVE":"Claimable AAVE","Claimed":"Claimed","Claiming":"Claiming","Close":"Close","Collateral":"Collateral","Collateral balance after repay":"Collateral balance after repay","Collateral is (mostly) the same currency that is being borrowed":"Collateral is (mostly) the same currency that is being borrowed","Collateral to repay with":"Collateral to repay with","Collateral usage":"Collateral usage","Collateral usage is limited because of Isolation mode.":"Collateral usage is limited because of Isolation mode.","Collateral usage is limited because of isolation mode. <0>Learn More0>":"Collateral usage is limited because of isolation mode. <0>Learn More0>","Collateralization":"Collateralization","Collector Contract":"Collector Contract","Collector Info":"Collector Info","Connect wallet":"Connect wallet","Cooldown period":"Cooldown period","Cooldown period warning":"Cooldown period warning","Cooldown time left":"Cooldown time left","Cooldown to unstake":"Cooldown to unstake","Cooling down...":"Cooling down...","Copy address":"Copy address","Copy error message":"Copy error message","Copy error text":"Copy error text","Created":"Created","Current LTV":"Current LTV","Current balance":"Current balance","Current differential":"Current differential","Current votes":"Current votes","Dark mode":"Dark mode","Dashboard":"Dashboard","Data couldn't be fetched, please reload graph.":"Data couldn't be fetched, please reload graph.","Debt":"Debt","Debt ceiling is exceeded":"Debt ceiling is exceeded","Debt ceiling is not zero":"Debt ceiling is not zero","Debt ceiling limits the amount possible to borrow against this asset by protocol users. Debt ceiling is specific to assets in isolation mode and is denoted in USD.":"Debt ceiling limits the amount possible to borrow against this asset by protocol users. Debt ceiling is specific to assets in isolation mode and is denoted in USD.","Delegate":"Delegate","Delegating":"Delegating","Delegation":"Delegation","Details":"Details","Developers":"Developers","Differential":"Differential","Disable E-Mode":"Disable E-Mode","Disable testnet":"Disable testnet","Disable {symbol} as collateral":["Disable ",["symbol"]," as collateral"],"Disabled":"Disabled","Disabling E-Mode":"Disabling E-Mode","Disabling this asset as collateral affects your borrowing power and Health Factor.":"Disabling this asset as collateral affects your borrowing power and Health Factor.","Disconnect Wallet":"Disconnect Wallet","Discord":"Discord","Discord channel":"Discord channel","Due to a precision bug in the stETH contract, this asset can not be used in flashloan transactions":"Due to a precision bug in the stETH contract, this asset can not be used in flashloan transactions","Due to the Horizon bridge exploit, certain assets on the Harmony network are not at parity with Ethereum, which affects the Aave V3 Harmony market.":"Due to the Horizon bridge exploit, certain assets on the Harmony network are not at parity with Ethereum, which affects the Aave V3 Harmony market.","E-Mode":"E-Mode","E-Mode Category":"E-Mode Category","E-Mode category":"E-Mode category","E-Mode increases your LTV for a selected category of assets up to 97%. <0>Learn more0>":"E-Mode increases your LTV for a selected category of assets up to 97%. <0>Learn more0>","E-Mode increases your LTV for a selected category of assets up to<0/>. <1>Learn more1>":"E-Mode increases your LTV for a selected category of assets up to<0/>. <1>Learn more1>","E-Mode increases your LTV for a selected category of assets, meaning that when E-mode is enabled, you will have higher borrowing power over assets of the same E-mode category which are defined by Aave Governance. You can enter E-Mode from your <0>Dashboard0>. To learn more about E-Mode and applied restrictions in <1>FAQ1> or <2>Aave V3 Technical Paper2>.":"E-Mode increases your LTV for a selected category of assets, meaning that when E-mode is enabled, you will have higher borrowing power over assets of the same E-mode category which are defined by Aave Governance. You can enter E-Mode from your <0>Dashboard0>. To learn more about E-Mode and applied restrictions in <1>FAQ1> or <2>Aave V3 Technical Paper2>.","Efficiency mode (E-Mode)":"Efficiency mode (E-Mode)","Emode":"Emode","Enable E-Mode":"Enable E-Mode","Enable {symbol} as collateral":["Enable ",["symbol"]," as collateral"],"Enabled":"Enabled","Enabled in isolation":"Enabled in isolation","Enabling E-Mode":"Enabling E-Mode","Enabling E-Mode only allows you to borrow assets belonging to the selected category. Please visit our <0>FAQ guide0> to learn more about how it works and the applied restrictions.":"Enabling E-Mode only allows you to borrow assets belonging to the selected category. Please visit our <0>FAQ guide0> to learn more about how it works and the applied restrictions.","Enabling this asset as collateral increases your borrowing power and Health Factor. However, it can get liquidated if your health factor drops below 1.":"Enabling this asset as collateral increases your borrowing power and Health Factor. However, it can get liquidated if your health factor drops below 1.","Ended":"Ended","Ends":"Ends","English":"English","Enter ETH address":"Enter ETH address","Enter an amount":"Enter an amount","Error connecting. Try refreshing the page.":"Error connecting. Try refreshing the page.","Executed":"Executed","Expected amount to repay":"Expected amount to repay","Expires":"Expires","FAQ":"FAQ","Failed to load proposal voters. Please refresh the page.":"Failed to load proposal voters. Please refresh the page.","Faucet":"Faucet","Faucet {0}":["Faucet ",["0"]],"Fetching data...":"Fetching data...","Filter":"Filter","For repayment of a specific type of debt, the user needs to have debt that type":"For repayment of a specific type of debt, the user needs to have debt that type","Forum discussion":"Forum discussion","French":"French","Frozen assets":"Frozen assets","Funds in the Safety Module":"Funds in the Safety Module","Get ABP Token":"Get ABP Token","Github":"Github","Global settings":"Global settings","Go Back":"Go Back","Go to Balancer Pool":"Go to Balancer Pool","Governance":"Governance","Greek":"Greek","Health Factor ({0} v2)":["Health Factor (",["0"]," v2)"],"Health Factor ({0} v3)":["Health Factor (",["0"]," v3)"],"Health factor":"Health factor","Health factor is lesser than the liquidation threshold":"Health factor is lesser than the liquidation threshold","Health factor is not below the threshold":"Health factor is not below the threshold","Hide":"Hide","I acknowledge the risks involved.":"I acknowledge the risks involved.","I fully understand the risks of migrating.":"I fully understand the risks of migrating.","I understand how cooldown ({0}) and unstaking ({1}) work":["I understand how cooldown (",["0"],") and unstaking (",["1"],") work"],"If the error continues to happen,<0/> you may report it to this":"If the error continues to happen,<0/> you may report it to this","If the health factor goes below 1, the liquidation of your collateral might be triggered.":"If the health factor goes below 1, the liquidation of your collateral might be triggered.","If you DO NOT unstake within {0} of unstake window, you will need to activate cooldown process again.":["If you DO NOT unstake within ",["0"]," of unstake window, you will need to activate cooldown process again."],"If your loan to value goes above the liquidation threshold your collateral supplied may be liquidated.":"If your loan to value goes above the liquidation threshold your collateral supplied may be liquidated.","In E-Mode some assets are not borrowable. Exit E-Mode to get access to all assets":"In E-Mode some assets are not borrowable. Exit E-Mode to get access to all assets","In Isolation mode, you cannot supply other assets as collateral. A global debt ceiling limits the borrowing power of the isolated asset. To exit isolation mode disable {0} as collateral before borrowing another asset. Read more in our <0>FAQ0>":["In Isolation mode, you cannot supply other assets as collateral. A global debt ceiling limits the borrowing power of the isolated asset. To exit isolation mode disable ",["0"]," as collateral before borrowing another asset. Read more in our <0>FAQ0>"],"Inconsistent flashloan parameters":"Inconsistent flashloan parameters","Interest rate rebalance conditions were not met":"Interest rate rebalance conditions were not met","Interest rate strategy":"Interest rate strategy","Invalid amount to burn":"Invalid amount to burn","Invalid amount to mint":"Invalid amount to mint","Invalid bridge protocol fee":"Invalid bridge protocol fee","Invalid expiration":"Invalid expiration","Invalid flashloan premium":"Invalid flashloan premium","Invalid return value of the flashloan executor function":"Invalid return value of the flashloan executor function","Invalid signature":"Invalid signature","Isolated":"Isolated","Isolated Debt Ceiling":"Isolated Debt Ceiling","Isolated assets have limited borrowing power and other assets cannot be used as collateral.":"Isolated assets have limited borrowing power and other assets cannot be used as collateral.","Join the community discussion":"Join the community discussion","Language":"Language","Learn more":"Learn more","Learn more about risks involved":"Learn more about risks involved","Learn more in our <0>FAQ guide0>":"Learn more in our <0>FAQ guide0>","Links":"Links","Liquidation <0/> threshold":"Liquidation <0/> threshold","Liquidation at":"Liquidation at","Liquidation penalty":"Liquidation penalty","Liquidation risk":"Liquidation risk","Liquidation risk parameters":"Liquidation risk parameters","Liquidation threshold":"Liquidation threshold","Liquidation value":"Liquidation value","Loading data...":"Loading data...","Ltv validation failed":"Ltv validation failed","MAX":"MAX","Market":"Market","Markets":"Markets","Max":"Max","Max LTV":"Max LTV","Max slashing":"Max slashing","Maximum amount available to borrow against this asset is limited because debt ceiling is at {0}%.":["Maximum amount available to borrow against this asset is limited because debt ceiling is at ",["0"],"%."],"Maximum amount available to borrow is limited because protocol borrow cap is nearly reached.":"Maximum amount available to borrow is limited because protocol borrow cap is nearly reached.","Maximum amount available to supply is <0/> {0} (<1/>).":["Maximum amount available to supply is <0/> ",["0"]," (<1/>)."],"Maximum amount available to supply is limited because protocol supply cap is at {0}%.":["Maximum amount available to supply is limited because protocol supply cap is at ",["0"],"%."],"Maximum loan to value":"Maximum loan to value","Menu":"Menu","Migrate":"Migrate","Migrate from {0} V2 to {1} V3":["Migrate from ",["0"]," V2 to ",["1"]," V3"],"Migrate to V3":"Migrate to V3","Migrate to v3":"Migrate to v3","Migrate to {0} v3 Market":["Migrate to ",["0"]," v3 Market"],"Migrated":"Migrated","Migrating":"Migrating","Migrating multiple collaterals and borrowed assets at the same time can be an expensive operation and might fail in certain situations.<0>Therefore it’s not recommended to migrate positions with more than 5 assets (deposited + borrowed) at the same time.0>":"Migrating multiple collaterals and borrowed assets at the same time can be an expensive operation and might fail in certain situations.<0>Therefore it’s not recommended to migrate positions with more than 5 assets (deposited + borrowed) at the same time.0>","Migration risks":"Migration risks","More":"More","NAY":"NAY","Need help connecting a wallet? <0>Read our FAQ0>":"Need help connecting a wallet? <0>Read our FAQ0>","Net APR":"Net APR","Net APY":"Net APY","Net APY is the combined effect of all supply and borrow positions on net worth, including incentives. It is possible to have a negative net APY if debt APY is higher than supply APY.":"Net APY is the combined effect of all supply and borrow positions on net worth, including incentives. It is possible to have a negative net APY if debt APY is higher than supply APY.","Net worth":"Net worth","Network":"Network","Network not supported for this wallet":"Network not supported for this wallet","New APY":"New APY","No":"No","No assets selected to migrate.":"No assets selected to migrate.","No rewards to claim":"No rewards to claim","No search results for":"No search results for","No voting power":"No voting power","None":"None","Not a valid address":"Not a valid address","Not enough balance on your wallet":"Not enough balance on your wallet","Not enough collateral to repay this amount of debt with":"Not enough collateral to repay this amount of debt with","Not enough staked balance":"Not enough staked balance","Not enough voting power to participate in this proposal":"Not enough voting power to participate in this proposal","Not reached":"Not reached","Nothing borrowed yet":"Nothing borrowed yet","Nothing staked":"Nothing staked","Nothing supplied yet":"Nothing supplied yet","Notify":"Notify","Ok, Close":"Ok, Close","Ok, I got it":"Ok, I got it","Operation not supported":"Operation not supported","Oracle price":"Oracle price","Overview":"Overview","Page not found":"Page not found","Participating in this {symbol} reserve gives annualized rewards.":["Participating in this ",["symbol"]," reserve gives annualized rewards."],"Pending...":"Pending...","Per the community, the Fantom market has been frozen.":"Per the community, the Fantom market has been frozen.","Please always be aware of your <0>Health Factor (HF)0> when partially migrating a position and that your rates will be updated to V3 rates.":"Please always be aware of your <0>Health Factor (HF)0> when partially migrating a position and that your rates will be updated to V3 rates.","Please connect a wallet to view your personal information here.":"Please connect a wallet to view your personal information here.","Please connect your wallet to get free testnet assets.":"Please connect your wallet to get free testnet assets.","Please connect your wallet to see migration tool.":"Please connect your wallet to see migration tool.","Please connect your wallet to see your supplies, borrowings, and open positions.":"Please connect your wallet to see your supplies, borrowings, and open positions.","Please enter a valid wallet address.":"Please enter a valid wallet address.","Please switch to {networkName}.":["Please switch to ",["networkName"],"."],"Please, connect your wallet":"Please, connect your wallet","Pool addresses provider is not registered":"Pool addresses provider is not registered","Powered by":"Powered by","Preview tx and migrate":"Preview tx and migrate","Price impact is the spread between the total value of the entry tokens swapped and the destination tokens obtained (in USD), which results from the limited liquidity of the trading pair.":"Price impact is the spread between the total value of the entry tokens swapped and the destination tokens obtained (in USD), which results from the limited liquidity of the trading pair.","Price impact {0}%":["Price impact ",["0"],"%"],"Proposal details":"Proposal details","Proposal overview":"Proposal overview","Proposals":"Proposals","Proposition power":"Proposition power","Protocol borrow cap at 100% for this asset. Further borrowing unavailable.":"Protocol borrow cap at 100% for this asset. Further borrowing unavailable.","Protocol borrow cap is at 100% for this asset. Further borrowing unavailable.":"Protocol borrow cap is at 100% for this asset. Further borrowing unavailable.","Protocol debt ceiling is at 100% for this asset. Further borrowing against this asset is unavailable.":"Protocol debt ceiling is at 100% for this asset. Further borrowing against this asset is unavailable.","Protocol debt ceiling is at 100% for this asset. Futher borrowing against this asset is unavailable.":"Protocol debt ceiling is at 100% for this asset. Futher borrowing against this asset is unavailable.","Protocol supply cap at 100% for this asset. Further supply unavailable.":"Protocol supply cap at 100% for this asset. Further supply unavailable.","Protocol supply cap is at 100% for this asset. Further supply unavailable.":"Protocol supply cap is at 100% for this asset. Further supply unavailable.","Quorum":"Quorum","Raw-Ipfs":"Raw-Ipfs","Reached":"Reached","Read-only mode allows to see address positions in Aave, but you won't be able to perform transactions.":"Read-only mode allows to see address positions in Aave, but you won't be able to perform transactions.","Read-only mode.":"Read-only mode.","Read-only mode. Connect to a wallet to perform transactions.":"Read-only mode. Connect to a wallet to perform transactions.","Received":"Received","Recipient address":"Recipient address","Rejected connection request":"Rejected connection request","Reload":"Reload","Reload the page":"Reload the page","Remaining debt":"Remaining debt","Remaining supply":"Remaining supply","Repaid":"Repaid","Repay":"Repay","Repay with":"Repay with","Repay {symbol}":["Repay ",["symbol"]],"Repaying {symbol}":["Repaying ",["symbol"]],"Reserve Size":"Reserve Size","Reserve factor":"Reserve factor","Reserve factor is a percentage of interest which goes to a {0} that is controlled by Aave governance to promote ecosystem growth.":["Reserve factor is a percentage of interest which goes to a ",["0"]," that is controlled by Aave governance to promote ecosystem growth."],"Reserve status & configuration":"Reserve status & configuration","Review approval tx details":"Review approval tx details","Review changes to continue":"Review changes to continue","Review tx":"Review tx","Review tx details":"Review tx details","Reward(s) to claim":"Reward(s) to claim","Rewards APR":"Rewards APR","Risk details":"Risk details","SEE CHARTS":"SEE CHARTS","Safety of your deposited collateral against the borrowed assets and its underlying value.":"Safety of your deposited collateral against the borrowed assets and its underlying value.","Seatbelt report":"Seatbelt report","Seems like we can't switch the network automatically. Please check if you can change it from the wallet.":"Seems like we can't switch the network automatically. Please check if you can change it from the wallet.","Select":"Select","Select APY type to switch":"Select APY type to switch","Select all":"Select all","Select language":"Select language","Select slippage tolerance":"Select slippage tolerance","Select token to add":"Select token to add","Select token to view in block explorer":"Select token to view in block explorer","Selected borrow assets":"Selected borrow assets","Selected supply assets":"Selected supply assets","Setup notifications about your Health Factor using the Hal app.":"Setup notifications about your Health Factor using the Hal app.","Share on twitter":"Share on twitter","Show":"Show","Show assets with 0 balance":"Show assets with 0 balance","Since this asset is frozen, the only available actions are withdraw and repay which can be accessed from the <0>Dashboard0>":"Since this asset is frozen, the only available actions are withdraw and repay which can be accessed from the <0>Dashboard0>","Since this is a test network, you can get any of the assets if you have ETH on your wallet":"Since this is a test network, you can get any of the assets if you have ETH on your wallet","Slippage is the difference between the quoted and received amounts from changing market conditions between the moment the transaction is submitted and its verification.":"Slippage is the difference between the quoted and received amounts from changing market conditions between the moment the transaction is submitted and its verification.","Something went wrong":"Something went wrong","Sorry, an unexpected error happened. In the meantime you may try reloading the page, or come back later.":"Sorry, an unexpected error happened. In the meantime you may try reloading the page, or come back later.","Sorry, we couldn't find the page you were looking for.":"Sorry, we couldn't find the page you were looking for.","Spanish":"Spanish","Stable":"Stable","Stable Interest Type is disabled for this currency":"Stable Interest Type is disabled for this currency","Stable borrowing is enabled":"Stable borrowing is enabled","Stable borrowing is not enabled":"Stable borrowing is not enabled","Stable debt supply is not zero":"Stable debt supply is not zero","Stable interest rate will <0>stay the same0> for the duration of your loan. Recommended for long-term loan periods and for users who prefer predictability.":"Stable interest rate will <0>stay the same0> for the duration of your loan. Recommended for long-term loan periods and for users who prefer predictability.","Stablecoin":"Stablecoin","Stake":"Stake","Stake AAVE":"Stake AAVE","Stake ABPT":"Stake ABPT","Stake cooldown activated":"Stake cooldown activated","Staked":"Staked","Staking":"Staking","Staking APR":"Staking APR","Staking Rewards":"Staking Rewards","Staking balance":"Staking balance","Started":"Started","State":"State","Supplied":"Supplied","Supplied asset amount":"Supplied asset amount","Supply":"Supply","Supply APY":"Supply APY","Supply apy":"Supply apy","Supply balance":"Supply balance","Supply balance after swap":"Supply balance after swap","Supply cap is exceeded":"Supply cap is exceeded","Supply cap on target reserve reached. Try lowering the amount.":"Supply cap on target reserve reached. Try lowering the amount.","Supply {symbol}":["Supply ",["symbol"]],"Supplying your":"Supplying your","Supplying {symbol}":["Supplying ",["symbol"]],"Swap":"Swap","Swap to":"Swap to","Swapped":"Swapped","Swapping":"Swapping","Switch APY type":"Switch APY type","Switch E-Mode":"Switch E-Mode","Switch E-Mode category":"Switch E-Mode category","Switch Network":"Switch Network","Switch rate":"Switch rate","Switching E-Mode":"Switching E-Mode","Switching rate":"Switching rate","Test Assets":"Test Assets","Testnet mode":"Testnet mode","Testnet mode is ON":"Testnet mode is ON","The % of your total borrowing power used. This is based on the amount of your collateral supplied and the total amount that you can borrow.":"The % of your total borrowing power used. This is based on the amount of your collateral supplied and the total amount that you can borrow.","The Aave Balancer Pool Token (ABPT) is a liquidity pool token. You can receive ABPT by depositing a combination of AAVE + ETH in the Balancer liquidity pool. You can then stake your BPT in the Safety Module to secure the protocol and earn Safety Incentives.":"The Aave Balancer Pool Token (ABPT) is a liquidity pool token. You can receive ABPT by depositing a combination of AAVE + ETH in the Balancer liquidity pool. You can then stake your BPT in the Safety Module to secure the protocol and earn Safety Incentives.","The Maximum LTV ratio represents the maximum borrowing power of a specific collateral. For example, if a collateral has an LTV of 75%, the user can borrow up to 0.75 worth of ETH in the principal currency for every 1 ETH worth of collateral.":"The Maximum LTV ratio represents the maximum borrowing power of a specific collateral. For example, if a collateral has an LTV of 75%, the user can borrow up to 0.75 worth of ETH in the principal currency for every 1 ETH worth of collateral.","The Stable Rate is not enabled for this currency":"The Stable Rate is not enabled for this currency","The address of the pool addresses provider is invalid":"The address of the pool addresses provider is invalid","The app is running in testnet mode. Learn how it works in":"The app is running in testnet mode. Learn how it works in","The caller of the function is not an AToken":"The caller of the function is not an AToken","The caller of this function must be a pool":"The caller of this function must be a pool","The collateral balance is 0":"The collateral balance is 0","The collateral chosen cannot be liquidated":"The collateral chosen cannot be liquidated","The cooldown period is the time required prior to unstaking your tokens(10 days). You can only withdraw your assets from the Security Module after the cooldown period and within the active the unstake window.<0>Learn more0>":"The cooldown period is the time required prior to unstaking your tokens(10 days). You can only withdraw your assets from the Security Module after the cooldown period and within the active the unstake window.<0>Learn more0>","The cooldown period is {0}. After {1} of cooldown, you will enter unstake window of {2}. You will continue receiving rewards during cooldown and unstake window.":["The cooldown period is ",["0"],". After ",["1"]," of cooldown, you will enter unstake window of ",["2"],". You will continue receiving rewards during cooldown and unstake window."],"The effects on the health factor would cause liquidation. Try lowering the amount.":"The effects on the health factor would cause liquidation. Try lowering the amount.","The requested amount is greater than the max loan size in stable rate mode":"The requested amount is greater than the max loan size in stable rate mode","The total amount of your assets denominated in USD that can be used as collateral for borrowing assets.":"The total amount of your assets denominated in USD that can be used as collateral for borrowing assets.","The underlying asset cannot be rescued":"The underlying asset cannot be rescued","The underlying balance needs to be greater than 0":"The underlying balance needs to be greater than 0","The weighted average of APY for all borrowed assets, including incentives.":"The weighted average of APY for all borrowed assets, including incentives.","The weighted average of APY for all supplied assets, including incentives.":"The weighted average of APY for all supplied assets, including incentives.","There are not enough funds in the{0}reserve to borrow":["There are not enough funds in the",["0"],"reserve to borrow"],"There is not enough collateral to cover a new borrow":"There is not enough collateral to cover a new borrow","There was some error. Please try changing the parameters or <0><1>copy the error1>0>":"There was some error. Please try changing the parameters or <0><1>copy the error1>0>","These assets are temporarily frozen by Aave community decisions, meaning that further supply / borrow, or rate swap of these assets are unavailable. Withdrawals and debt repayments are allowed. Follow the <0>Aave governance forum0> for further updates.":"These assets are temporarily frozen by Aave community decisions, meaning that further supply / borrow, or rate swap of these assets are unavailable. Withdrawals and debt repayments are allowed. Follow the <0>Aave governance forum0> for further updates.","These funds have been borrowed and are not available for withdrawal at this time.":"These funds have been borrowed and are not available for withdrawal at this time.","This action will reduce V2 health factor below liquidation threshold. retain collateral or migrate borrow position to continue.":"This action will reduce V2 health factor below liquidation threshold. retain collateral or migrate borrow position to continue.","This action will reduce health factor of V3 below liquidation threshold. Increase migrated collateral or reduce migrated borrow to continue.":"This action will reduce health factor of V3 below liquidation threshold. Increase migrated collateral or reduce migrated borrow to continue.","This action will reduce your health factor. Please be mindful of the increased risk of collateral liquidation.":"This action will reduce your health factor. Please be mindful of the increased risk of collateral liquidation.","This address is blocked on app.aave.com because it is associated with one or more":"This address is blocked on app.aave.com because it is associated with one or more","This asset has almost reached its borrow cap. There is only {messageValue} available to be borrowed from this market.":["This asset has almost reached its borrow cap. There is only ",["messageValue"]," available to be borrowed from this market."],"This asset has almost reached its supply cap. There can only be {messageValue} supplied to this market.":["This asset has almost reached its supply cap. There can only be ",["messageValue"]," supplied to this market."],"This asset has reached its borrow cap. Nothing is available to be borrowed from this market.":"This asset has reached its borrow cap. Nothing is available to be borrowed from this market.","This asset has reached its supply cap. Nothing is available to be supplied from this market.":"This asset has reached its supply cap. Nothing is available to be supplied from this market.","This asset is frozen due to an Aave Protocol Governance decision. <0>More details0>":"This asset is frozen due to an Aave Protocol Governance decision. <0>More details0>","This asset is frozen due to an Aave Protocol Governance decision. On the 20th of December 2022, renFIL will no longer be supported and cannot be bridged back to its native network. It is recommended to withdraw supply positions and repay borrow positions so that renFIL can be bridged back to FIL before the deadline. After this date, it will no longer be possible to convert renFIL to FIL. <0>More details0>":"This asset is frozen due to an Aave Protocol Governance decision. On the 20th of December 2022, renFIL will no longer be supported and cannot be bridged back to its native network. It is recommended to withdraw supply positions and repay borrow positions so that renFIL can be bridged back to FIL before the deadline. After this date, it will no longer be possible to convert renFIL to FIL. <0>More details0>","This asset is frozen due to an Aave community decision. <0>More details0>":"This asset is frozen due to an Aave community decision. <0>More details0>","This gas calculation is only an estimation. Your wallet will set the price of the transaction. You can modify the gas settings directly from your wallet provider.":"This gas calculation is only an estimation. Your wallet will set the price of the transaction. You can modify the gas settings directly from your wallet provider.","This integration was<0>proposed and approved0>by the community.":"This integration was<0>proposed and approved0>by the community.","This is the total amount available for you to borrow. You can borrow based on your collateral and until the borrow cap is reached.":"This is the total amount available for you to borrow. You can borrow based on your collateral and until the borrow cap is reached.","This is the total amount that you are able to supply to in this reserve. You are able to supply your wallet balance up until the supply cap is reached.":"This is the total amount that you are able to supply to in this reserve. You are able to supply your wallet balance up until the supply cap is reached.","This represents the threshold at which a borrow position will be considered undercollateralized and subject to liquidation for each collateral. For example, if a collateral has a liquidation threshold of 80%, it means that the position will be liquidated when the debt value is worth 80% of the collateral value.":"This represents the threshold at which a borrow position will be considered undercollateralized and subject to liquidation for each collateral. For example, if a collateral has a liquidation threshold of 80%, it means that the position will be liquidated when the debt value is worth 80% of the collateral value.","Time left to be able to withdraw your staked asset.":"Time left to be able to withdraw your staked asset.","Time left to unstake":"Time left to unstake","Time left until the withdrawal window closes.":"Time left until the withdrawal window closes.","To borrow you need to supply any asset to be used as collateral.":"To borrow you need to supply any asset to be used as collateral.","To continue, you need to grant Aave smart contracts permission to move your funds from your wallet. Depending on the asset and wallet you use, it is done by signing the permission message (gas free), or by submitting an approval transaction (requires gas). <0>Learn more0>":"To continue, you need to grant Aave smart contracts permission to move your funds from your wallet. Depending on the asset and wallet you use, it is done by signing the permission message (gas free), or by submitting an approval transaction (requires gas). <0>Learn more0>","To enable E-mode for the {0} category, all borrow positions outside of this cateogry must be closed.":["To enable E-mode for the ",["0"]," category, all borrow positions outside of this cateogry must be closed."],"To repay on behalf of a user an explicit amount to repay is needed":"To repay on behalf of a user an explicit amount to repay is needed","To request access for this permissioned market, please visit: <0>Acces Provider Name0>":"To request access for this permissioned market, please visit: <0>Acces Provider Name0>","Top 10 addresses":"Top 10 addresses","Total available":"Total available","Total borrowed":"Total borrowed","Total borrows":"Total borrows","Total emission per day":"Total emission per day","Total market size":"Total market size","Total supplied":"Total supplied","Total voting power":"Total voting power","Total worth":"Total worth","Track wallet":"Track wallet","Track wallet balance in read-only mode":"Track wallet balance in read-only mode","Transaction failed":"Transaction failed","Transaction overview":"Transaction overview","Type of delegation":"Type of delegation","UNSTAKE {symbol}":["UNSTAKE ",["symbol"]],"UNSTAKING {symbol}":["UNSTAKING ",["symbol"]],"Unavailable":"Unavailable","Unbacked":"Unbacked","Unbacked mint cap is exceeded":"Unbacked mint cap is exceeded","Unselect all":"Unselect all","Unstake now":"Unstake now","Unstake window":"Unstake window","Unstaked":"Unstaked","Used as collateral":"Used as collateral","User cannot withdraw more than the available balance":"User cannot withdraw more than the available balance","User did not borrow the specified currency":"User did not borrow the specified currency","User does not have outstanding stable rate debt on this reserve":"User does not have outstanding stable rate debt on this reserve","User does not have outstanding variable rate debt on this reserve":"User does not have outstanding variable rate debt on this reserve","User is in isolation mode":"User is in isolation mode","User is trying to borrow multiple assets including a siloed one":"User is trying to borrow multiple assets including a siloed one","Utilization Rate":"Utilization Rate","VOTE NAY":"VOTE NAY","VOTE YAE":"VOTE YAE","Variable":"Variable","Variable debt supply is not zero":"Variable debt supply is not zero","Variable interest rate will <0>fluctuate0> based on the market conditions. Recommended for short-term positions.":"Variable interest rate will <0>fluctuate0> based on the market conditions. Recommended for short-term positions.","Version 2":"Version 2","Version 3":"Version 3","View all votes":"View all votes","View contract":"View contract","View details":"View details","View on Explorer":"View on Explorer","Vote":"Vote","Vote NAY":"Vote NAY","Vote YAE":"Vote YAE","Voted NAY":"Voted NAY","Voted YAE":"Voted YAE","Votes":"Votes","Voting power":"Voting power","Voting results":"Voting results","Wallet Balance":"Wallet Balance","Wallet balance":"Wallet balance","Wallet not detected. Connect or install wallet and retry":"Wallet not detected. Connect or install wallet and retry","Wallets are provided by External Providers and by selecting you agree to Terms of those Providers. Your access to the wallet might be reliant on the External Provider being operational.":"Wallets are provided by External Providers and by selecting you agree to Terms of those Providers. Your access to the wallet might be reliant on the External Provider being operational.","We couldn't find any assets related to your search. Try again with a different asset name, symbol, or address.":"We couldn't find any assets related to your search. Try again with a different asset name, symbol, or address.","We couldn’t detect a wallet. Connect a wallet to stake and view your balance.":"We couldn’t detect a wallet. Connect a wallet to stake and view your balance.","We suggest you go back to the Dashboard.":"We suggest you go back to the Dashboard.","When a liquidation occurs, liquidators repay up to 50% of the outstanding borrowed amount on behalf of the borrower. In return, they can buy the collateral at a discount and keep the difference (liquidation penalty) as a bonus.":"When a liquidation occurs, liquidators repay up to 50% of the outstanding borrowed amount on behalf of the borrower. In return, they can buy the collateral at a discount and keep the difference (liquidation penalty) as a bonus.","With a voting power of <0/>":"With a voting power of <0/>","With testnet Faucet you can get free assets to test the Aave Protocol. Make sure to switch your wallet provider to the appropriate testnet network, select desired asset, and click ‘Faucet’ to get tokens transferred to your wallet. The assets on a testnet are not “real,” meaning they have no monetary value. <0>Learn more0>":"With testnet Faucet you can get free assets to test the Aave Protocol. Make sure to switch your wallet provider to the appropriate testnet network, select desired asset, and click ‘Faucet’ to get tokens transferred to your wallet. The assets on a testnet are not “real,” meaning they have no monetary value. <0>Learn more0>","Withdraw":"Withdraw","Withdraw {symbol}":["Withdraw ",["symbol"]],"Withdrawing this amount will reduce your health factor and increase risk of liquidation.":"Withdrawing this amount will reduce your health factor and increase risk of liquidation.","Withdrawing {symbol}":["Withdrawing ",["symbol"]],"Wrong Network":"Wrong Network","YAE":"YAE","Yes":"Yes","You are entering Isolation mode":"You are entering Isolation mode","You can borrow this asset with a stable rate only if you borrow more than the amount you are supplying as collateral.":"You can borrow this asset with a stable rate only if you borrow more than the amount you are supplying as collateral.","You can not change Interest Type to stable as your borrowings are higher than your collateral":"You can not change Interest Type to stable as your borrowings are higher than your collateral","You can not disable E-Mode as your current collateralization level is above 80%, disabling E-Mode can cause liquidation. To exit E-Mode supply or repay borrowed positions.":"You can not disable E-Mode as your current collateralization level is above 80%, disabling E-Mode can cause liquidation. To exit E-Mode supply or repay borrowed positions.","You can not switch usage as collateral mode for this currency, because it will cause collateral call":"You can not switch usage as collateral mode for this currency, because it will cause collateral call","You can not use this currency as collateral":"You can not use this currency as collateral","You can not withdraw this amount because it will cause collateral call":"You can not withdraw this amount because it will cause collateral call","You can only withdraw your assets from the Security Module after the cooldown period ends and the unstake window is active.":"You can only withdraw your assets from the Security Module after the cooldown period ends and the unstake window is active.","You can report incident to our <0>Discord0> or <1>Github1>.":"You can report incident to our <0>Discord0> or <1>Github1>.","You cancelled the transaction.":"You cancelled the transaction.","You did not participate in this proposal":"You did not participate in this proposal","You do not have supplies in this currency":"You do not have supplies in this currency","You don’t have enough funds in your wallet to repay the full amount. If you proceed to repay with your current amount of funds, you will still have a small borrowing position in your dashboard.":"You don’t have enough funds in your wallet to repay the full amount. If you proceed to repay with your current amount of funds, you will still have a small borrowing position in your dashboard.","You have not borrow yet using this currency":"You have not borrow yet using this currency","You switched to {0} rate":["You switched to ",["0"]," rate"],"You unstake here":"You unstake here","You voted {0}":["You voted ",["0"]],"You will exit isolation mode and other tokens can now be used as collateral":"You will exit isolation mode and other tokens can now be used as collateral","You {action} <0/> {symbol}":["You ",["action"]," <0/> ",["symbol"]],"Your borrows":"Your borrows","Your current loan to value based on your collateral supplied.":"Your current loan to value based on your collateral supplied.","Your health factor and loan to value determine the assurance of your collateral. To avoid liquidations you can supply more collateral or repay borrow positions.":"Your health factor and loan to value determine the assurance of your collateral. To avoid liquidations you can supply more collateral or repay borrow positions.","Your info":"Your info","Your reward balance is 0":"Your reward balance is 0","Your supplies":"Your supplies","Your voting info":"Your voting info","Your {name} wallet is empty. Purchase or transfer assets or use <0>{0}0> to transfer your {network} assets.":["Your ",["name"]," wallet is empty. Purchase or transfer assets or use <0>",["0"],"0> to transfer your ",["network"]," assets."],"Your {name} wallet is empty. Purchase or transfer assets.":["Your ",["name"]," wallet is empty. Purchase or transfer assets."],"Your {networkName} wallet is empty. Get free test assets at":["Your ",["networkName"]," wallet is empty. Get free test assets at"],"Your {networkName} wallet is empty. Get free test {0} at":["Your ",["networkName"]," wallet is empty. Get free test ",["0"]," at"],"Zero address not valid":"Zero address not valid","assets":"assets","blocked activities":"blocked activities","copy the error":"copy the error","ends":"ends","here.":"here.","of":"of","on":"on","please check that the amount you want to supply is not currently being used for staking. If it is being used for staking, your transaction might fail.":"please check that the amount you want to supply is not currently being used for staking. If it is being used for staking, your transaction might fail.","repaid":"repaid","stETH supplied as collateral will continue to accrue staking rewards provided by daily rebases.":"stETH supplied as collateral will continue to accrue staking rewards provided by daily rebases.","staking view":"staking view","starts":"starts","tokens is not the same as staking them. If you wish to stake your":"tokens is not the same as staking them. If you wish to stake your","tokens, please go to the":"tokens, please go to the","withdrew":"withdrew","{0}":[["0"]],"{0} Balance":[["0"]," Balance"],"{0} Faucet":[["0"]," Faucet"],"{0} on-ramp service is provided by External Provider and by selecting you agree to Terms of the Provider. Your access to the service might be reliant on the External Provider being operational.":[["0"]," on-ramp service is provided by External Provider and by selecting you agree to Terms of the Provider. Your access to the service might be reliant on the External Provider being operational."],"{0}{name}":[["0"],["name"]],"{currentMethod}":[["currentMethod"]],"{d}d":[["d"],"d"],"{h}h":[["h"],"h"],"{m}m":[["m"],"m"],"{networkName} Faucet":[["networkName"]," Faucet"],"{s}s":[["s"],"s"],"{tooltipText}":[["tooltipText"]]}};
\ No newline at end of file
diff --git a/src/locales/en/messages.po b/src/locales/en/messages.po
index f0869ab1a9..81d656d233 100644
--- a/src/locales/en/messages.po
+++ b/src/locales/en/messages.po
@@ -185,6 +185,7 @@ msgstr "Array parameters that should be equal length are not"
#: src/modules/dashboard/lists/SuppliedPositionsList/SuppliedPositionsList.tsx
#: src/modules/faucet/FaucetAssetsList.tsx
#: src/modules/markets/MarketAssetsList.tsx
+#: src/modules/migration/MigrationList.tsx
msgid "Asset"
msgstr "Asset"
@@ -274,6 +275,7 @@ msgstr "Back to Dashboard"
#: src/modules/dashboard/lists/BorrowedPositionsList/BorrowedPositionsList.tsx
#: src/modules/dashboard/lists/SuppliedPositionsList/SuppliedPositionsList.tsx
#: src/modules/dashboard/lists/SuppliedPositionsList/SuppliedPositionsList.tsx
+#: src/modules/migration/MigrationList.tsx
msgid "Balance"
msgstr "Balance"
@@ -281,6 +283,10 @@ msgstr "Balance"
msgid "Be careful - You are very close to liquidation. Consider depositing more collateral or paying down some of your borrowed positions"
msgstr "Be careful - You are very close to liquidation. Consider depositing more collateral or paying down some of your borrowed positions"
+#: src/modules/migration/MigrationBottomPanel.tsx
+msgid "Be mindful of the network congestion and gas prices."
+msgstr "Be mindful of the network congestion and gas prices."
+
#: src/components/transactions/Warnings/SNXWarning.tsx
msgid "Before supplying"
msgstr "Before supplying"
@@ -475,6 +481,7 @@ msgstr "Close"
#: src/components/transactions/Repay/RepayTypeSelector.tsx
#: src/modules/dashboard/lists/SuppliedPositionsList/SuppliedPositionsList.tsx
#: src/modules/dashboard/lists/SuppliedPositionsList/SuppliedPositionsList.tsx
+#: src/modules/migration/MigrationList.tsx
msgid "Collateral"
msgstr "Collateral"
@@ -562,6 +569,10 @@ msgstr "Created"
msgid "Current LTV"
msgstr "Current LTV"
+#: src/modules/migration/MigrationList.tsx
+msgid "Current balance"
+msgstr "Current balance"
+
#: pages/governance/proposal/[proposalId].governance.tsx
msgid "Current differential"
msgstr "Current differential"
@@ -679,6 +690,7 @@ msgid "Due to the Horizon bridge exploit, certain assets on the Harmony network
msgstr "Due to the Horizon bridge exploit, certain assets on the Harmony network are not at parity with Ethereum, which affects the Aave V3 Harmony market."
#: src/modules/dashboard/DashboardEModeButton.tsx
+#: src/modules/migration/EmodeInfo.tsx
msgid "E-Mode"
msgstr "E-Mode"
@@ -840,6 +852,7 @@ msgid "Global settings"
msgstr "Global settings"
#: src/modules/governance/proposal/ProposalTopPanel.tsx
+#: src/modules/migration/MigrationTopPanel.tsx
#: src/modules/reserve-overview/ReserveTopDetails.tsx
msgid "Go Back"
msgstr "Go Back"
@@ -856,6 +869,14 @@ msgstr "Governance"
msgid "Greek"
msgstr "Greek"
+#: src/modules/migration/MigrationBottomPanel.tsx
+msgid "Health Factor ({0} v2)"
+msgstr "Health Factor ({0} v2)"
+
+#: src/modules/migration/MigrationBottomPanel.tsx
+msgid "Health Factor ({0} v3)"
+msgstr "Health Factor ({0} v3)"
+
#: src/components/transactions/FlowCommons/TxModalDetails.tsx
#: src/modules/dashboard/DashboardTopPanel.tsx
#: src/modules/dashboard/LiquidationRiskParametresModal/LiquidationRiskParametresModal.tsx
@@ -879,6 +900,10 @@ msgstr "Hide"
msgid "I acknowledge the risks involved."
msgstr "I acknowledge the risks involved."
+#: src/modules/migration/MigrationBottomPanel.tsx
+msgid "I fully understand the risks of migrating."
+msgstr "I fully understand the risks of migrating."
+
#: src/components/transactions/StakeCooldown/StakeCooldownModalContent.tsx
msgid "I understand how cooldown ({0}) and unstaking ({1}) work"
msgstr "I understand how cooldown ({0}) and unstaking ({1}) work"
@@ -1000,6 +1025,7 @@ msgid "Liquidation <0/> threshold"
msgstr "Liquidation <0/> threshold"
#: src/components/transactions/FlowCommons/TxModalDetails.tsx
+#: src/modules/migration/HFChange.tsx
msgid "Liquidation at"
msgstr "Liquidation at"
@@ -1085,6 +1111,42 @@ msgstr "Maximum loan to value"
msgid "Menu"
msgstr "Menu"
+#: src/components/transactions/MigrateV3/MigrateV3Actions.tsx
+msgid "Migrate"
+msgstr "Migrate"
+
+#: src/modules/migration/MigrationTopPanel.tsx
+msgid "Migrate from {0} V2 to {1} V3"
+msgstr "Migrate from {0} V2 to {1} V3"
+
+#: src/components/TopInfoPanel/PageTitle.tsx
+msgid "Migrate to V3"
+msgstr "Migrate to V3"
+
+#: src/modules/dashboard/DashboardTopPanel.tsx
+msgid "Migrate to v3"
+msgstr "Migrate to v3"
+
+#: src/modules/dashboard/DashboardTopPanel.tsx
+msgid "Migrate to {0} v3 Market"
+msgstr "Migrate to {0} v3 Market"
+
+#: src/components/transactions/MigrateV3/MigrateV3ModalContent.tsx
+msgid "Migrated"
+msgstr "Migrated"
+
+#: src/components/transactions/MigrateV3/MigrateV3Actions.tsx
+msgid "Migrating"
+msgstr "Migrating"
+
+#: src/modules/migration/MigrationBottomPanel.tsx
+msgid "Migrating multiple collaterals and borrowed assets at the same time can be an expensive operation and might fail in certain situations.<0>Therefore it’s not recommended to migrate positions with more than 5 assets (deposited + borrowed) at the same time.0>"
+msgstr "Migrating multiple collaterals and borrowed assets at the same time can be an expensive operation and might fail in certain situations.<0>Therefore it’s not recommended to migrate positions with more than 5 assets (deposited + borrowed) at the same time.0>"
+
+#: src/modules/migration/MigrationBottomPanel.tsx
+msgid "Migration risks"
+msgstr "Migration risks"
+
#: src/layouts/MoreMenu.tsx
msgid "More"
msgstr "More"
@@ -1129,6 +1191,10 @@ msgstr "New APY"
msgid "No"
msgstr "No"
+#: src/modules/migration/MigrationBottomPanel.tsx
+msgid "No assets selected to migrate."
+msgstr "No assets selected to migrate."
+
#: src/components/transactions/StakeRewardClaim/StakeRewardClaimModalContent.tsx
msgid "No rewards to claim"
msgstr "No rewards to claim"
@@ -1173,6 +1239,7 @@ msgstr "Not enough voting power to participate in this proposal"
msgid "Not reached"
msgstr "Not reached"
+#: pages/v3-migration.page.tsx
#: src/modules/dashboard/lists/BorrowedPositionsList/BorrowedPositionsList.tsx
msgid "Nothing borrowed yet"
msgstr "Nothing borrowed yet"
@@ -1181,6 +1248,7 @@ msgstr "Nothing borrowed yet"
msgid "Nothing staked"
msgstr "Nothing staked"
+#: pages/v3-migration.page.tsx
#: src/modules/dashboard/lists/SuppliedPositionsList/SuppliedPositionsList.tsx
msgid "Nothing supplied yet"
msgstr "Nothing supplied yet"
@@ -1226,6 +1294,10 @@ msgstr "Pending..."
msgid "Per the community, the Fantom market has been frozen."
msgstr "Per the community, the Fantom market has been frozen."
+#: src/modules/migration/MigrationBottomPanel.tsx
+msgid "Please always be aware of your <0>Health Factor (HF)0> when partially migrating a position and that your rates will be updated to V3 rates."
+msgstr "Please always be aware of your <0>Health Factor (HF)0> when partially migrating a position and that your rates will be updated to V3 rates."
+
#: src/modules/reserve-overview/ReserveActions.tsx
msgid "Please connect a wallet to view your personal information here."
msgstr "Please connect a wallet to view your personal information here."
@@ -1234,6 +1306,10 @@ msgstr "Please connect a wallet to view your personal information here."
msgid "Please connect your wallet to get free testnet assets."
msgstr "Please connect your wallet to get free testnet assets."
+#: pages/v3-migration.page.tsx
+msgid "Please connect your wallet to see migration tool."
+msgstr "Please connect your wallet to see migration tool."
+
#: src/components/ConnectWalletPaper.tsx
#: src/components/ConnectWalletPaperStaking.tsx
msgid "Please connect your wallet to see your supplies, borrowings, and open positions."
@@ -1260,6 +1336,10 @@ msgstr "Pool addresses provider is not registered"
msgid "Powered by"
msgstr "Powered by"
+#: src/modules/migration/MigrationBottomPanel.tsx
+msgid "Preview tx and migrate"
+msgstr "Preview tx and migrate"
+
#: src/components/infoTooltips/PriceImpactTooltip.tsx
msgid "Price impact is the spread between the total value of the entry tokens swapped and the destination tokens obtained (in USD), which results from the limited liquidity of the trading pair."
msgstr "Price impact is the spread between the total value of the entry tokens swapped and the destination tokens obtained (in USD), which results from the limited liquidity of the trading pair."
@@ -1408,6 +1488,10 @@ msgstr "Reserve status & configuration"
msgid "Review approval tx details"
msgstr "Review approval tx details"
+#: src/modules/migration/MigrationBottomPanel.tsx
+msgid "Review changes to continue"
+msgstr "Review changes to continue"
+
#: src/components/transactions/CollateralChange/CollateralChangeModal.tsx
msgid "Review tx"
msgstr "Review tx"
@@ -1452,6 +1536,10 @@ msgstr "Select"
msgid "Select APY type to switch"
msgstr "Select APY type to switch"
+#: src/modules/migration/MigrationList.tsx
+msgid "Select all"
+msgstr "Select all"
+
#: src/layouts/components/LanguageSwitcher.tsx
msgid "Select language"
msgstr "Select language"
@@ -1468,6 +1556,14 @@ msgstr "Select token to add"
msgid "Select token to view in block explorer"
msgstr "Select token to view in block explorer"
+#: src/components/transactions/MigrateV3/MigrateV3ModalContent.tsx
+msgid "Selected borrow assets"
+msgstr "Selected borrow assets"
+
+#: src/components/transactions/MigrateV3/MigrateV3ModalContent.tsx
+msgid "Selected supply assets"
+msgstr "Selected supply assets"
+
#: src/components/HALLink.tsx
msgid "Setup notifications about your Health Factor using the Hal app."
msgstr "Setup notifications about your Health Factor using the Hal app."
@@ -1812,6 +1908,14 @@ msgstr "These assets are temporarily frozen by Aave community decisions, meaning
msgid "These funds have been borrowed and are not available for withdrawal at this time."
msgstr "These funds have been borrowed and are not available for withdrawal at this time."
+#: src/modules/migration/MigrationBottomPanel.tsx
+msgid "This action will reduce V2 health factor below liquidation threshold. retain collateral or migrate borrow position to continue."
+msgstr "This action will reduce V2 health factor below liquidation threshold. retain collateral or migrate borrow position to continue."
+
+#: src/modules/migration/MigrationBottomPanel.tsx
+msgid "This action will reduce health factor of V3 below liquidation threshold. Increase migrated collateral or reduce migrated borrow to continue."
+msgstr "This action will reduce health factor of V3 below liquidation threshold. Increase migrated collateral or reduce migrated borrow to continue."
+
#: src/components/transactions/Emode/EmodeModalContent.tsx
msgid "This action will reduce your health factor. Please be mindful of the increased risk of collateral liquidation."
msgstr "This action will reduce your health factor. Please be mindful of the increased risk of collateral liquidation."
@@ -1983,6 +2087,10 @@ msgstr "Unbacked"
msgid "Unbacked mint cap is exceeded"
msgstr "Unbacked mint cap is exceeded"
+#: src/modules/migration/MigrationList.tsx
+msgid "Unselect all"
+msgstr "Unselect all"
+
#: src/modules/staking/StakingPanel.tsx
msgid "Unstake now"
msgstr "Unstake now"
@@ -2267,6 +2375,7 @@ msgstr "You {action} <0/> {symbol}"
#: src/modules/dashboard/lists/BorrowedPositionsList/BorrowedPositionsList.tsx
#: src/modules/dashboard/lists/BorrowedPositionsList/BorrowedPositionsList.tsx
+#: src/modules/migration/MigrationLists.tsx
msgid "Your borrows"
msgstr "Your borrows"
@@ -2291,6 +2400,7 @@ msgstr "Your reward balance is 0"
#: src/modules/dashboard/lists/SuppliedPositionsList/SuppliedPositionsList.tsx
#: src/modules/dashboard/lists/SuppliedPositionsList/SuppliedPositionsList.tsx
+#: src/modules/migration/MigrationLists.tsx
msgid "Your supplies"
msgstr "Your supplies"
@@ -2388,6 +2498,7 @@ msgstr "withdrew"
#: src/components/transactions/StakeCooldown/StakeCooldownModalContent.tsx
#: src/components/transactions/StakeCooldown/StakeCooldownModalContent.tsx
#: src/modules/dashboard/DashboardEModeButton.tsx
+#: src/modules/migration/EmodeInfo.tsx
#: src/modules/reserve-overview/ReserveTopDetails.tsx
msgid "{0}"
msgstr "{0}"
diff --git a/src/modules/dashboard/DashboardTopPanel.tsx b/src/modules/dashboard/DashboardTopPanel.tsx
index 8f1a515c95..656eb31c66 100644
--- a/src/modules/dashboard/DashboardTopPanel.tsx
+++ b/src/modules/dashboard/DashboardTopPanel.tsx
@@ -1,13 +1,19 @@
import { ChainId } from '@aave/contract-helpers';
import { normalize, UserIncentiveData, valueToBigNumber } from '@aave/math-utils';
import { Trans } from '@lingui/macro';
-import { Box, Button, useMediaQuery, useTheme } from '@mui/material';
+import { Box, Button, Typography, useMediaQuery, useTheme } from '@mui/material';
+import Link from 'next/link';
import * as React from 'react';
import { useState } from 'react';
import { NetAPYTooltip } from 'src/components/infoTooltips/NetAPYTooltip';
+import { getMarketInfoById } from 'src/components/MarketSwitcher';
+import { ROUTES } from 'src/components/primitives/Link';
+import { PageTitle } from 'src/components/TopInfoPanel/PageTitle';
import { useModalContext } from 'src/hooks/useModal';
import { useProtocolDataContext } from 'src/hooks/useProtocolDataContext';
import { useWeb3Context } from 'src/libs/hooks/useWeb3Context';
+import { useRootStore } from 'src/store/root';
+import { selectIsMigrationAvailable } from 'src/store/v3MigrationSelectors';
import ClaimGiftIcon from '../../../public/icons/markets/claim-gift-icon.svg';
import EmptyHeartIcon from '../../../public/icons/markets/empty-heart-icon.svg';
@@ -28,12 +34,16 @@ import { useAppDataContext } from '../../hooks/app-data-provider/useAppDataProvi
import { LiquidationRiskParametresInfoModal } from './LiquidationRiskParametresModal/LiquidationRiskParametresModal';
export const DashboardTopPanel = () => {
- const { currentNetworkConfig, currentMarketData } = useProtocolDataContext();
+ const { currentNetworkConfig, currentMarketData, currentMarket } = useProtocolDataContext();
+ const { market } = getMarketInfoById(currentMarket);
const { user, reserves, loading } = useAppDataContext();
const { currentAccount } = useWeb3Context();
const [open, setOpen] = useState(false);
const { openClaimRewards } = useModalContext();
+ const isMigrateToV3Available = useRootStore((state) => selectIsMigrationAvailable(state));
+ const showMigrateButton =
+ isMigrateToV3Available && currentAccount !== '' && Number(user.totalLiquidityUSD) > 0;
const theme = useTheme();
const downToSM = useMediaQuery(theme.breakpoints.down('sm'));
@@ -86,10 +96,44 @@ export const DashboardTopPanel = () => {
return (
<>
+ {showMigrateButton && downToSM && (
+
+
+
+
+
+ )}
Dashboard}
- withMarketSwitcher
- bridge={currentNetworkConfig.bridge}
+ titleComponent={
+
+ Dashboard}
+ withMarketSwitcher={true}
+ bridge={currentNetworkConfig.bridge}
+ />
+ {showMigrateButton && !downToSM && (
+
+
+
+
+
+ )}
+
+ }
>
} title={Net worth} loading={loading}>
{currentAccount ? (
diff --git a/src/modules/dashboard/lists/ListItemUsedAsCollateral.tsx b/src/modules/dashboard/lists/ListItemUsedAsCollateral.tsx
index 088a595142..43ecd7d1eb 100644
--- a/src/modules/dashboard/lists/ListItemUsedAsCollateral.tsx
+++ b/src/modules/dashboard/lists/ListItemUsedAsCollateral.tsx
@@ -8,6 +8,8 @@ interface ListItemUsedAsCollateralProps {
usageAsCollateralEnabledOnUser: boolean;
canBeEnabledAsCollateral: boolean;
onToggleSwitch: () => void;
+ // directly disable without additional canBeEnabledAsCollateral check for migration page
+ disabled?: boolean;
}
export const ListItemUsedAsCollateral = ({
@@ -15,7 +17,9 @@ export const ListItemUsedAsCollateral = ({
usageAsCollateralEnabledOnUser,
canBeEnabledAsCollateral,
onToggleSwitch,
+ disabled,
}: ListItemUsedAsCollateralProps) => {
+ // TODO: fix this for migration
const isEnabled = usageAsCollateralEnabledOnUser && canBeEnabledAsCollateral;
return (
<>
@@ -24,7 +28,7 @@ export const ListItemUsedAsCollateral = ({
onClick={onToggleSwitch}
disableRipple
checked={isEnabled}
- disabled={!canBeEnabledAsCollateral}
+ disabled={!canBeEnabledAsCollateral || disabled}
/>
) : (
@@ -32,7 +36,7 @@ export const ListItemUsedAsCollateral = ({
onClick={onToggleSwitch}
disableRipple
checked={isEnabled}
- disabled={!canBeEnabledAsCollateral}
+ disabled={!canBeEnabledAsCollateral || disabled}
/>
)}
diff --git a/src/modules/migration/EmodeInfo.tsx b/src/modules/migration/EmodeInfo.tsx
new file mode 100644
index 0000000000..72e589aefe
--- /dev/null
+++ b/src/modules/migration/EmodeInfo.tsx
@@ -0,0 +1,91 @@
+import { LightningBoltIcon } from '@heroicons/react/solid';
+import { Trans } from '@lingui/macro';
+import { Box, Button, SvgIcon, Typography } from '@mui/material';
+import React from 'react';
+import { TypographyGradient } from 'src/components/primitives/TypographyGradient';
+import { getEmodeMessage } from 'src/components/transactions/Emode/EmodeNaming';
+import { selectEmodesV3 } from 'src/store/poolSelectors';
+import { useRootStore } from 'src/store/root';
+
+import LightningBoltGradient from '/public/lightningBoltGradient.svg';
+
+interface EmodeInfoProps {
+ userEmodeCategoryId: number;
+}
+
+export const EmodeInfo = ({ userEmodeCategoryId }: EmodeInfoProps) => {
+ const eModesV3 = useRootStore(selectEmodesV3);
+ const iconButtonSize = 12;
+
+ const isEModeDisabled = userEmodeCategoryId === 0;
+
+ const EModeLabelMessage = () => (
+ {getEmodeMessage(eModesV3[userEmodeCategoryId]?.label)}
+ );
+
+ return (
+
+
+ E-Mode
+
+
+
+
+ );
+};
diff --git a/src/modules/migration/HFChange.tsx b/src/modules/migration/HFChange.tsx
new file mode 100644
index 0000000000..719ef46690
--- /dev/null
+++ b/src/modules/migration/HFChange.tsx
@@ -0,0 +1,37 @@
+import { ArrowNarrowRightIcon } from '@heroicons/react/solid';
+import { Trans } from '@lingui/macro';
+import { Box, Skeleton, SvgIcon, Typography } from '@mui/material';
+import { ReactNode } from 'react';
+import { HealthFactorNumber } from 'src/components/HealthFactorNumber';
+import { Row } from 'src/components/primitives/Row';
+
+interface HFChangeProps {
+ caption: ReactNode;
+ hfCurrent: string;
+ hfAfter: string;
+ loading?: boolean;
+}
+
+export const HFChange = ({ caption, hfCurrent, hfAfter, loading }: HFChangeProps) => {
+ return (
+
+
+
+ {!loading ? : }
+
+
+
+ {!loading ? : }
+
+
+ Liquidation at
+ {' <1.0'}
+
+
+
+ );
+};
diff --git a/src/modules/migration/MigrationBottomPanel.tsx b/src/modules/migration/MigrationBottomPanel.tsx
new file mode 100644
index 0000000000..09a62e0963
--- /dev/null
+++ b/src/modules/migration/MigrationBottomPanel.tsx
@@ -0,0 +1,209 @@
+import { ExclamationIcon } from '@heroicons/react/outline';
+import { Trans } from '@lingui/macro';
+import {
+ Box,
+ Button,
+ Checkbox,
+ FormControlLabel,
+ Paper,
+ SvgIcon,
+ Typography,
+ useMediaQuery,
+ useTheme,
+} from '@mui/material';
+import { useState } from 'react';
+import { getMarketInfoById } from 'src/components/MarketSwitcher';
+import { Row } from 'src/components/primitives/Row';
+import { Warning } from 'src/components/primitives/Warning';
+import { useModalContext } from 'src/hooks/useModal';
+import { useProtocolDataContext } from 'src/hooks/useProtocolDataContext';
+
+import { HFChange } from './HFChange';
+
+interface MigrationBottomPanelProps {
+ hfV2Current: string;
+ hfV2AfterChange: string;
+ hfV3Current: string;
+ hfV3AfterChange: string;
+ disableButton?: boolean;
+ loading?: boolean;
+}
+
+enum ErrorType {
+ NO_SELECTION,
+ V2_HF_TOO_LOW,
+ V3_HF_TOO_LOW,
+}
+
+export const MigrationBottomPanel = ({
+ hfV2Current,
+ hfV2AfterChange,
+ hfV3Current,
+ hfV3AfterChange,
+ disableButton,
+ loading,
+}: MigrationBottomPanelProps) => {
+ const { breakpoints } = useTheme();
+ const downToSM = useMediaQuery(breakpoints.down('sm'));
+ const { currentMarket } = useProtocolDataContext();
+ const { market } = getMarketInfoById(currentMarket);
+
+ const { openV3Migration } = useModalContext();
+ const [isChecked, setIsChecked] = useState(false);
+
+ // error types handling
+ let blockingError: ErrorType | undefined = undefined;
+ if (disableButton && isChecked) {
+ blockingError = ErrorType.NO_SELECTION;
+ } else if (Number(hfV2AfterChange) < 1.005 && hfV2AfterChange !== '-1') {
+ blockingError = ErrorType.V2_HF_TOO_LOW;
+ } else if (Number(hfV3AfterChange) < 1.005 && hfV3AfterChange !== '-1') {
+ blockingError = ErrorType.V3_HF_TOO_LOW;
+ }
+
+ // error render handling
+ const Blocked = () => {
+ switch (blockingError) {
+ case ErrorType.NO_SELECTION:
+ return No assets selected to migrate.;
+ case ErrorType.V2_HF_TOO_LOW:
+ return (
+
+ This action will reduce V2 health factor below liquidation threshold. retain collateral
+ or migrate borrow position to continue.
+
+ );
+ case ErrorType.V3_HF_TOO_LOW:
+ return (
+ <>
+
+ This action will reduce health factor of V3 below liquidation threshold. Increase
+ migrated collateral or reduce migrated borrow to continue.
+
+ >
+ );
+ default:
+ return <>>;
+ }
+ };
+
+ return (
+
+
+ Review changes to continue}
+ captionVariant="h3"
+ sx={{ mb: 6 }}
+ />
+
+ Health Factor ({market.marketTitle} v2)}
+ hfCurrent={hfV2Current}
+ hfAfter={hfV2AfterChange}
+ loading={loading}
+ />
+
+ Health Factor ({market.marketTitle} v3)}
+ hfCurrent={hfV3Current}
+ hfAfter={hfV3AfterChange}
+ loading={loading}
+ />
+
+ {blockingError !== undefined && (
+
+
+
+ )}
+
+
+ setIsChecked(!isChecked)}
+ size="small"
+ />
+ }
+ label={
+
+ I fully understand the risks of migrating.
+
+ }
+ />
+
+
+
+
+
+
+
+
+
+
+
+ Migration risks
+
+
+
+ Please always be aware of your Health Factor (HF) when partially migrating a
+ position and that your rates will be updated to V3 rates.
+
+
+
+
+ Migrating multiple collaterals and borrowed assets at the same time can be an expensive
+ operation and might fail in certain situations.
+
+ Therefore it’s not recommended to migrate positions with more than 5 assets (deposited
+ + borrowed) at the same time.
+
+
+
+
+ Be mindful of the network congestion and gas prices.
+
+
+
+ );
+};
diff --git a/src/modules/migration/MigrationList.tsx b/src/modules/migration/MigrationList.tsx
new file mode 100644
index 0000000000..b0cd25957a
--- /dev/null
+++ b/src/modules/migration/MigrationList.tsx
@@ -0,0 +1,105 @@
+import { Trans } from '@lingui/macro';
+import { Box, Typography, useMediaQuery, useTheme } from '@mui/material';
+import { ReactNode } from 'react';
+import { CollateralSwitchTooltip } from 'src/components/infoTooltips/CollateralSwitchTooltip';
+import { ListColumn } from 'src/components/lists/ListColumn';
+import { ListHeaderTitle } from 'src/components/lists/ListHeaderTitle';
+import { ListHeaderWrapper } from 'src/components/lists/ListHeaderWrapper';
+import { ListWrapper } from 'src/components/lists/ListWrapper';
+import { ListTopInfoItem } from 'src/modules/dashboard/lists/ListTopInfoItem';
+
+import { EmodeInfo } from './EmodeInfo';
+
+interface MigrationListProps {
+ titleComponent: ReactNode;
+ totalAmount: string;
+ isBottomOnMobile?: boolean;
+ children: ReactNode;
+ onSelectAllClick: () => void;
+ loading?: boolean;
+ isAvailable: boolean;
+ withCollateral?: boolean;
+ emodeCategoryId?: number;
+ allSelected: boolean;
+}
+
+export const MigrationList = ({
+ titleComponent,
+ totalAmount,
+ isBottomOnMobile,
+ children,
+ onSelectAllClick,
+ loading,
+ isAvailable,
+ withCollateral,
+ emodeCategoryId,
+ allSelected,
+}: MigrationListProps) => {
+ const { breakpoints } = useTheme();
+ const isDesktop = useMediaQuery(breakpoints.up('lg'));
+ const isTablet = useMediaQuery(breakpoints.up('xsm'));
+ const isMobile = useMediaQuery(breakpoints.up('xs'));
+
+ const assetColumnWidth =
+ isMobile && !isTablet ? 75 : isTablet && !isDesktop ? 140 : isDesktop ? 240 : 140;
+
+ const paperWidth = isDesktop ? 'calc(50% - 8px)' : '100%';
+
+ return (
+
+
+ {titleComponent}
+
+ }
+ subTitleComponent={
+ typeof emodeCategoryId !== 'undefined' ? (
+
+ ) : undefined
+ }
+ topInfo={
+ !(loading || +totalAmount <= 0) && (
+ Balance} value={totalAmount || 0} />
+ )
+ }
+ >
+ {(isAvailable || loading) && (
+
+
+
+
+ {allSelected ? Unselect all : Select all}
+
+
+
+
+
+
+ Asset
+
+
+
+ {withCollateral && (
+
+ Collateral}
+ key="Collateral"
+ variant="subheader2"
+ />
+
+ )}
+
+
+
+ Current balance
+
+
+
+ )}
+
+ {children}
+
+
+ );
+};
diff --git a/src/modules/migration/MigrationListBorrowItem.tsx b/src/modules/migration/MigrationListBorrowItem.tsx
new file mode 100644
index 0000000000..f3318cb6d3
--- /dev/null
+++ b/src/modules/migration/MigrationListBorrowItem.tsx
@@ -0,0 +1,60 @@
+import { InterestRate } from '@aave/contract-helpers';
+import { useMemo } from 'react';
+import { SplittedUserReserveIncreasedAmount } from 'src/store/v3MigrationSelectors';
+import { MigrationSelectedBorrowAsset } from 'src/store/v3MigrationSlice';
+
+import { MigrationListItem } from './MigrationListItem';
+
+type MigrationListBorrowItemProps = {
+ userReserve: SplittedUserReserveIncreasedAmount & {
+ disabledForMigration: boolean;
+ };
+ selectedBorrowAssets: MigrationSelectedBorrowAsset[];
+ toggleSelectedBorrowPosition: (asset: MigrationSelectedBorrowAsset) => void;
+};
+
+export const MigrationListBorrowItem = ({
+ selectedBorrowAssets,
+ userReserve,
+ toggleSelectedBorrowPosition,
+}: MigrationListBorrowItemProps) => {
+ const isChecked = useMemo(() => {
+ return (
+ !userReserve.disabledForMigration &&
+ selectedBorrowAssets.findIndex((selectedAsset) =>
+ userReserve.interestRate == InterestRate.Stable
+ ? selectedAsset.debtKey == userReserve.reserve.stableDebtTokenAddress
+ : selectedAsset.debtKey == userReserve.reserve.variableDebtTokenAddress
+ ) >= 0
+ );
+ }, [selectedBorrowAssets]);
+
+ const handleCheckboxClick = () => {
+ toggleSelectedBorrowPosition(userReserve);
+ };
+
+ const amount =
+ userReserve.interestRate == InterestRate.Stable
+ ? userReserve.stableBorrows
+ : userReserve.variableBorrows;
+
+ const amountInUSD =
+ userReserve.interestRate == InterestRate.Stable
+ ? userReserve.stableBorrowsUSD
+ : userReserve.variableBorrowsUSD;
+
+ return (
+
+ );
+};
diff --git a/src/modules/migration/MigrationListItem.tsx b/src/modules/migration/MigrationListItem.tsx
new file mode 100644
index 0000000000..e29a613095
--- /dev/null
+++ b/src/modules/migration/MigrationListItem.tsx
@@ -0,0 +1,120 @@
+import { CheckIcon } from '@heroicons/react/solid';
+import { Box, SvgIcon, Typography, useMediaQuery, useTheme } from '@mui/material';
+import { ListColumn } from 'src/components/lists/ListColumn';
+import { ListItem } from 'src/components/lists/ListItem';
+import { FormattedNumber } from 'src/components/primitives/FormattedNumber';
+import { Row } from 'src/components/primitives/Row';
+import { TokenIcon } from 'src/components/primitives/TokenIcon';
+
+import { ListItemUsedAsCollateral } from '../dashboard/lists/ListItemUsedAsCollateral';
+
+interface MigrationListItemProps {
+ checked: boolean;
+ reserveIconSymbol: string;
+ reserveName: string;
+ reserveSymbol: string;
+ amount: string;
+ amountInUSD: string;
+ onCheckboxClick: () => void;
+ disabled?: boolean;
+ enabledAsCollateral?: boolean;
+ canBeEnforced?: boolean;
+ enableAsCollateral?: () => void;
+ isIsolated?: boolean;
+}
+
+export const MigrationListItem = ({
+ checked,
+ reserveIconSymbol,
+ reserveName,
+ reserveSymbol,
+ amount,
+ amountInUSD,
+ onCheckboxClick,
+ enabledAsCollateral,
+ disabled,
+ enableAsCollateral,
+ canBeEnforced,
+ isIsolated,
+}: MigrationListItemProps) => {
+ const { breakpoints } = useTheme();
+ const isDesktop = useMediaQuery(breakpoints.up('lg'));
+ const isTablet = useMediaQuery(breakpoints.up('xsm'));
+ const isMobile = useMediaQuery(breakpoints.up('xs'));
+
+ const assetColumnWidth =
+ isMobile && !isTablet ? 75 : isTablet && !isDesktop ? 140 : isDesktop ? 240 : 140;
+
+ return (
+
+
+ ({
+ border: `2px solid ${
+ Boolean(disabled) ? theme.palette.action.disabled : theme.palette.text.secondary
+ }`,
+ background: checked ? theme.palette.text.secondary : theme.palette.background.paper,
+ width: 16,
+ height: 16,
+ borderRadius: '2px',
+ cursor: Boolean(disabled) ? 'default' : 'pointer',
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+ })}
+ onClick={Boolean(disabled) ? undefined : onCheckboxClick}
+ >
+
+
+
+
+
+
+
+
+ {isTablet && }
+
+
+
+ {isDesktop ? reserveName : reserveSymbol}
+
+
+ {reserveSymbol}
+
+
+
+
+
+ {!!enableAsCollateral && (
+
+
+
+ )}
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/src/modules/migration/MigrationListItemLoader.tsx b/src/modules/migration/MigrationListItemLoader.tsx
new file mode 100644
index 0000000000..1fbcbd4765
--- /dev/null
+++ b/src/modules/migration/MigrationListItemLoader.tsx
@@ -0,0 +1,28 @@
+import { Box, Skeleton, useMediaQuery, useTheme } from '@mui/material';
+import { ListColumn } from 'src/components/lists/ListColumn';
+import { ListItem } from 'src/components/lists/ListItem';
+
+export const MigrationListItemLoader = () => {
+ const { breakpoints } = useTheme();
+ const isTablet = useMediaQuery(breakpoints.up('md'));
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/src/modules/migration/MigrationLists.tsx b/src/modules/migration/MigrationLists.tsx
new file mode 100644
index 0000000000..bacb0d2ef7
--- /dev/null
+++ b/src/modules/migration/MigrationLists.tsx
@@ -0,0 +1,82 @@
+import { Trans } from '@lingui/macro';
+import { Box, useMediaQuery, useTheme } from '@mui/material';
+import { ReactNode } from 'react';
+import { useUserReserves } from 'src/hooks/useUserReserves';
+import { useRootStore } from 'src/store/root';
+
+import { MigrationList } from './MigrationList';
+
+interface MigrationListsProps {
+ totalSuppliesUSD: string;
+ totalBorrowsUSD: string;
+ onSelectAllSupplies: () => void;
+ onSelectAllBorrows: () => void;
+ suppliesPositions: ReactNode;
+ borrowsPositions: ReactNode;
+ loading?: boolean;
+ isSupplyPositionsAvailable: boolean;
+ isBorrowPositionsAvailable: boolean;
+ emodeCategoryId?: number;
+}
+
+export const MigrationLists = ({
+ totalSuppliesUSD,
+ totalBorrowsUSD,
+ onSelectAllSupplies,
+ onSelectAllBorrows,
+ suppliesPositions,
+ borrowsPositions,
+ loading,
+ isSupplyPositionsAvailable,
+ isBorrowPositionsAvailable,
+ emodeCategoryId,
+}: MigrationListsProps) => {
+ const { breakpoints } = useTheme();
+ const isDesktop = useMediaQuery(breakpoints.up('lg'));
+
+ const { user, borrowPositions } = useUserReserves();
+
+ const {
+ selectedMigrationSupplyAssets: selectedSupplyAssets,
+ selectedMigrationBorrowAssets: selectedBorrowAssets,
+ } = useRootStore();
+
+ const allSuppliesSelected =
+ Object.keys(selectedSupplyAssets).length === user.userReservesData.length;
+ const allBorrowsSelected = Object.keys(selectedBorrowAssets).length === borrowPositions.length;
+ return (
+
+ Your supplies}
+ totalAmount={totalSuppliesUSD}
+ withCollateral
+ emodeCategoryId={emodeCategoryId}
+ >
+ {suppliesPositions}
+
+
+ Your borrows}
+ totalAmount={totalBorrowsUSD}
+ // withEmode TODO: uncomment when emode logic for migration will fix
+ >
+ {borrowsPositions}
+
+
+ );
+};
diff --git a/src/modules/migration/MigrationTopPanel.tsx b/src/modules/migration/MigrationTopPanel.tsx
new file mode 100644
index 0000000000..5cb0471a44
--- /dev/null
+++ b/src/modules/migration/MigrationTopPanel.tsx
@@ -0,0 +1,62 @@
+import { Trans } from '@lingui/macro';
+import ArrowBackRoundedIcon from '@mui/icons-material/ArrowBackOutlined';
+import { Box, Button, SvgIcon, useMediaQuery, useTheme } from '@mui/material';
+import { useRouter } from 'next/router';
+import { ROUTES } from 'src/components/primitives/Link';
+import { PageTitle } from 'src/components/TopInfoPanel/PageTitle';
+import { TopInfoPanel } from 'src/components/TopInfoPanel/TopInfoPanel';
+
+import { getMarketInfoById } from '../../components/MarketSwitcher';
+import { useProtocolDataContext } from '../../hooks/useProtocolDataContext';
+
+export const MigrationTopPanel = () => {
+ const router = useRouter();
+ const { currentMarket } = useProtocolDataContext();
+ const { market } = getMarketInfoById(currentMarket);
+
+ const theme = useTheme();
+ const downToSM = useMediaQuery(theme.breakpoints.down('sm'));
+
+ return (
+
+
+
+
+
+ Migrate from {market.marketTitle} V2 to {market.marketTitle} V3
+
+ }
+ />
+
+ }
+ />
+ );
+};
diff --git a/src/store/poolSelectors.ts b/src/store/poolSelectors.ts
index c764627a78..fdf228a9cc 100644
--- a/src/store/poolSelectors.ts
+++ b/src/store/poolSelectors.ts
@@ -1,30 +1,100 @@
-import { formatReservesAndIncentives } from '@aave/math-utils';
+import { ReserveDataHumanized } from '@aave/contract-helpers';
+import { formatReservesAndIncentives, formatUserSummaryAndIncentives } from '@aave/math-utils';
import { EmodeCategory } from 'src/helpers/types';
import { fetchIconSymbolAndName, STABLE_ASSETS } from 'src/ui-config/reservePatches';
+import { CustomMarket, MarketDataType, marketsData } from 'src/utils/marketsAndNetworksConfig';
+import { PoolReserve } from './poolSlice';
import { RootStore } from './root';
+export const selectCurrentChainIdMarkets = (state: RootStore) => {
+ const marketNames = Object.keys(marketsData);
+ return Object.values(marketsData)
+ .map((marketData, index) => ({
+ ...marketData,
+ marketName: marketNames[index] as CustomMarket,
+ }))
+ .filter(
+ (marketData) =>
+ marketData.chainId == state.currentChainId &&
+ state.currentNetworkConfig.isFork == marketData.isFork
+ );
+};
+
+export const selectCurrentChainIdV2MarketData = (state: RootStore) => {
+ const currentChainIdMarkets = selectCurrentChainIdMarkets(state);
+ const marketData = currentChainIdMarkets.filter((marketData) => !marketData.v3);
+ return marketData[0];
+};
+
+export const selectCurrentChainIdV3MarketData = (state: RootStore) => {
+ const currentChainIdMarkets = selectCurrentChainIdMarkets(state);
+ const marketData = currentChainIdMarkets.filter((marketData) => marketData.v3);
+ return marketData[0];
+};
+
+export const selectCurrentChainIdV2PoolReserve = (state: RootStore) => {
+ const marketData = selectCurrentChainIdV2MarketData(state);
+ const v2MarketAddressProvider = marketData
+ ? marketData.addresses.LENDING_POOL_ADDRESS_PROVIDER
+ : undefined;
+ const currentChainId = state.currentChainId;
+ if (v2MarketAddressProvider && currentChainId) {
+ return state.data.get(state.currentChainId)?.get(v2MarketAddressProvider);
+ }
+ return undefined;
+};
+
+export const selectCurrentChainIdV3PoolReserve = (state: RootStore) => {
+ const marketData = selectCurrentChainIdV3MarketData(state);
+ const v3MarketAddressProvider = marketData
+ ? marketData.addresses.LENDING_POOL_ADDRESS_PROVIDER
+ : undefined;
+ const currentChainId = state.currentChainId;
+ if (v3MarketAddressProvider && currentChainId) {
+ return state.data.get(state.currentChainId)?.get(v3MarketAddressProvider);
+ }
+ return undefined;
+};
+
export const selectCurrentUserLendingPoolData = (state: RootStore) => {
- return state.data
- .get(state.currentChainId)
- ?.get(state.currentMarketData.addresses.LENDING_POOL_ADDRESS_PROVIDER);
+ const marketAddressProvider = state.currentMarketData
+ ? state.currentMarketData.addresses.LENDING_POOL_ADDRESS_PROVIDER
+ : undefined;
+ const currentChainId = state.currentChainId;
+ if (marketAddressProvider && currentChainId) {
+ return state.data.get(state.currentChainId)?.get(marketAddressProvider);
+ }
+ return undefined;
+};
+
+export const selectFormatUserEmodeCategoryId = (reserve?: PoolReserve) => {
+ return reserve?.userEmodeCategoryId || 0;
};
export const selectCurrentUserEmodeCategoryId = (state: RootStore): number => {
- return selectCurrentUserLendingPoolData(state)?.userEmodeCategoryId || 0;
+ return selectFormatUserEmodeCategoryId(selectCurrentUserLendingPoolData(state));
+};
+
+export const selectFormatUserReserves = (reserve?: PoolReserve) => {
+ return reserve?.userReserves || [];
};
export const selectCurrentUserReserves = (state: RootStore) => {
- return selectCurrentUserLendingPoolData(state)?.userReserves || [];
+ return selectFormatUserReserves(selectCurrentUserLendingPoolData(state));
+};
+
+export const selectFormatReserves = (reserve?: PoolReserve) => {
+ return reserve?.reserves || [];
};
export const selectCurrentReserves = (state: RootStore) => {
- return selectCurrentUserLendingPoolData(state)?.reserves || [];
+ return selectFormatReserves(selectCurrentUserLendingPoolData(state));
};
-export const selectCurrentBaseCurrencyData = (state: RootStore) => {
+export const selectFormatBaseCurrencyData = (reserve?: PoolReserve) => {
return (
- selectCurrentUserLendingPoolData(state)?.baseCurrencyData || {
+ reserve?.baseCurrencyData || {
marketReferenceCurrencyDecimals: 0,
marketReferenceCurrencyPriceInUsd: '0',
networkBaseTokenPriceInUsd: '0',
@@ -33,6 +103,10 @@ export const selectCurrentBaseCurrencyData = (state: RootStore) => {
);
};
+export const selectCurrentBaseCurrencyData = (state: RootStore) => {
+ return selectFormatBaseCurrencyData(selectCurrentUserLendingPoolData(state));
+};
+
export const reserveSortFn = (a: { iconSymbol: string }, b: { iconSymbol: string }) => {
const aIsStable = STABLE_ASSETS.includes(a.iconSymbol.toUpperCase());
const bIsStable = STABLE_ASSETS.includes(b.iconSymbol.toUpperCase());
@@ -68,9 +142,50 @@ export const selectFormattedReserves = (state: RootStore, currentTimestamp: numb
return formattedPoolReserves;
};
-export const selectEmodes = (state: RootStore) => {
- const reserves = selectCurrentReserves(state);
+export const selectUserSummaryAndIncentives = (state: RootStore, currentTimestamp: number) => {
+ const baseCurrencyData = selectCurrentBaseCurrencyData(state);
+ const userReserves = selectCurrentUserReserves(state);
+ const formattedPoolReserves = selectFormattedReserves(state, currentTimestamp);
+ const userEmodeCategoryId = selectCurrentUserEmodeCategoryId(state);
+ const reserveIncentiveData = state.reserveIncentiveData;
+ const userIncentiveData = state.userIncentiveData;
+
+ // TODO: why
+ return formatUserSummaryAndIncentives({
+ currentTimestamp,
+ marketReferencePriceInUsd: baseCurrencyData.marketReferenceCurrencyPriceInUsd,
+ marketReferenceCurrencyDecimals: baseCurrencyData.marketReferenceCurrencyDecimals,
+ userReserves,
+ formattedReserves: formattedPoolReserves,
+ userEmodeCategoryId: userEmodeCategoryId,
+ reserveIncentives: reserveIncentiveData || [],
+ userIncentives: userIncentiveData || [],
+ });
+};
+
+export const selectUserNonEmtpySummaryAndIncentive = (
+ state: RootStore,
+ currentTimestamp: number
+) => {
+ const user = selectUserSummaryAndIncentives(state, currentTimestamp);
+ const userReservesData = user.userReservesData.filter(
+ (userReserve) => userReserve.underlyingBalance !== '0'
+ );
+ return {
+ ...user,
+ userReservesData,
+ };
+};
+export const selectNonEmptyUserBorrowPositions = (state: RootStore, currentTimestamp: number) => {
+ const user = selectUserSummaryAndIncentives(state, currentTimestamp);
+ const borrowedPositions = user.userReservesData.filter(
+ (reserve) => reserve.variableBorrows != '0' || reserve.stableBorrows != '0'
+ );
+ return borrowedPositions;
+};
+
+export const formatEmodes = (reserves: ReserveDataHumanized[]) => {
const eModes = reserves?.reduce((acc, r) => {
if (!acc[r.eModeCategoryId])
acc[r.eModeCategoryId] = {
@@ -88,3 +203,13 @@ export const selectEmodes = (state: RootStore) => {
return eModes;
};
+
+export const selectEmodes = (state: RootStore) => {
+ const reserves = selectCurrentReserves(state);
+ return formatEmodes(reserves);
+};
+
+export const selectEmodesV3 = (state: RootStore) => {
+ const reserves = selectFormatReserves(selectCurrentChainIdV3PoolReserve(state));
+ return formatEmodes(reserves);
+};
diff --git a/src/store/poolSlice.ts b/src/store/poolSlice.ts
index 22ce9deb87..d472b257b6 100644
--- a/src/store/poolSlice.ts
+++ b/src/store/poolSlice.ts
@@ -31,27 +31,26 @@ import { CollateralRepayActionProps } from 'src/components/transactions/Repay/Co
import { RepayActionProps } from 'src/components/transactions/Repay/RepayActions';
import { SupplyActionProps } from 'src/components/transactions/Supply/SupplyActions';
import { SwapActionProps } from 'src/components/transactions/Swap/SwapActions';
+import { MarketDataType } from 'src/ui-config/marketsConfig';
import { minBaseTokenRemainingByNetwork, optimizedPath } from 'src/utils/utils';
import { StateCreator } from 'zustand';
-import { selectFormattedReserves } from './poolSelectors';
+import { selectCurrentChainIdV3MarketData, selectFormattedReserves } from './poolSelectors';
import { RootStore } from './root';
+// TODO: what is the better name for this type?
+export type PoolReserve = {
+ reserves?: ReserveDataHumanized[];
+ baseCurrencyData?: PoolBaseCurrencyHumanized;
+ userEmodeCategoryId?: number;
+ userReserves?: UserReserveDataHumanized[];
+};
+
// TODO: add chain/provider/account mapping
export interface PoolSlice {
- data: Map<
- number,
- Map<
- string,
- {
- reserves?: ReserveDataHumanized[];
- baseCurrencyData?: PoolBaseCurrencyHumanized;
- userEmodeCategoryId?: number;
- userReserves?: UserReserveDataHumanized[];
- }
- >
- >;
- refreshPoolData: () => Promise;
+ data: Map>;
+ refreshPoolData: (marketData?: MarketDataType) => Promise;
+ refreshPoolV3Data: () => Promise;
// methods
useOptimizedPath: () => boolean | undefined;
mint: (args: Omit) => Promise;
@@ -119,10 +118,10 @@ export const createPoolSlice: StateCreator<
}
return {
data: new Map(),
- refreshPoolData: async () => {
+ refreshPoolData: async (marketData?: MarketDataType) => {
const account = get().account;
- const currentMarketData = get().currentMarketData;
const currentChainId = get().currentChainId;
+ const currentMarketData = marketData || get().currentMarketData;
const poolDataProviderContract = new UiPoolDataProvider({
uiPoolDataProviderAddress: currentMarketData.addresses.UI_POOL_DATA_PROVIDER,
provider: get().jsonRpcProvider(),
@@ -193,6 +192,10 @@ export const createPoolSlice: StateCreator<
console.log('error fetching pool data', e);
}
},
+ refreshPoolV3Data: async () => {
+ const v3MarketData = selectCurrentChainIdV3MarketData(get());
+ get().refreshPoolData(v3MarketData);
+ },
mint: async (args) => {
if (!get().currentMarketData.addresses.FAUCET)
throw Error('currently selected market does not have a faucet attached');
diff --git a/src/store/root.ts b/src/store/root.ts
index d1e7c272c8..1b86709664 100644
--- a/src/store/root.ts
+++ b/src/store/root.ts
@@ -10,6 +10,7 @@ import { createProtocolDataSlice, ProtocolDataSlice } from './protocolDataSlice'
import { createStakeSlice, StakeSlice } from './stakeSlice';
import { createSingletonSubscriber } from './utils/createSingletonSubscriber';
import { getQueryParameter } from './utils/queryParams';
+import { createV3MigrationSlice, V3MigrationSlice } from './v3MigrationSlice';
import { createWalletSlice, WalletSlice } from './walletSlice';
enableMapSet();
@@ -19,7 +20,8 @@ export type RootStore = StakeSlice &
WalletSlice &
PoolSlice &
IncentiveSlice &
- GovernanceSlice;
+ GovernanceSlice &
+ V3MigrationSlice;
export const useRootStore = create()(
devtools((...args) => {
@@ -30,6 +32,7 @@ export const useRootStore = create()(
...createPoolSlice(...args),
...createIncentiveSlice(...args),
...createGovernanceSlice(...args),
+ ...createV3MigrationSlice(...args),
};
})
);
@@ -64,6 +67,10 @@ export const usePoolDataSubscription = createSingletonSubscriber(() => {
return useRootStore.getState().refreshPoolData();
}, 60000);
+export const usePoolDataV3Subscription = createSingletonSubscriber(() => {
+ return useRootStore.getState().refreshPoolV3Data();
+}, 60000);
+
export const useIncentiveDataSubscription = createSingletonSubscriber(() => {
return useRootStore.getState().refreshIncentiveData();
}, 60000);
diff --git a/src/store/v3MigrationSelectors.ts b/src/store/v3MigrationSelectors.ts
new file mode 100644
index 0000000000..e5f95c8627
--- /dev/null
+++ b/src/store/v3MigrationSelectors.ts
@@ -0,0 +1,506 @@
+import {
+ InterestRate,
+ PoolBaseCurrencyHumanized,
+ ReserveDataHumanized,
+ UserReserveDataHumanized,
+ valueToWei,
+} from '@aave/contract-helpers';
+import { V3MigrationHelperSignedPermit } from '@aave/contract-helpers/dist/esm/v3-migration-contract/v3MigrationTypes';
+import {
+ ComputedUserReserve,
+ formatReserves,
+ FormatReserveUSDResponse,
+ formatUserSummary,
+ FormatUserSummaryResponse,
+ rayDiv,
+ valueToBigNumber,
+} from '@aave/math-utils';
+import { SignatureLike } from '@ethersproject/bytes';
+import { BigNumberish, constants } from 'ethers';
+import { ComputedUserReserveData } from 'src/hooks/app-data-provider/useAppDataProvider';
+
+import {
+ selectCurrentChainIdV2PoolReserve,
+ selectCurrentChainIdV3PoolReserve,
+ selectFormatBaseCurrencyData,
+ selectUserSummaryAndIncentives,
+} from './poolSelectors';
+import { RootStore } from './root';
+import { MigrationSelectedBorrowAsset } from './v3MigrationSlice';
+
+export const selectIsolationModeForMigration = (
+ poolReserveV3Summary: Pick<
+ FormatUserSummaryResponse,
+ 'totalCollateralMarketReferenceCurrency' | 'isolatedReserve'
+ >
+) => {
+ if (poolReserveV3Summary.totalCollateralMarketReferenceCurrency !== '0') {
+ return poolReserveV3Summary.isolatedReserve;
+ }
+ return undefined;
+};
+
+export const selectMigrationSelectedSupplyIndex = (store: RootStore, underlyingAsset: string) => {
+ return store.selectedMigrationSupplyAssets.findIndex(
+ (supplyAsset) => supplyAsset.underlyingAsset == underlyingAsset
+ );
+};
+
+export const selectMigrationSelectedBorrowIndex = (
+ selectedBorrowAssets: MigrationSelectedBorrowAsset[],
+ borrowAsset: MigrationSelectedBorrowAsset
+) => {
+ return selectedBorrowAssets.findIndex((asset) => asset.debtKey == borrowAsset.debtKey);
+};
+
+export type SplittedUserReserveIncreasedAmount = ComputedUserReserveData & {
+ increasedStableBorrows: string;
+ increasedVariableBorrows: string;
+ interestRate: InterestRate;
+ debtKey: string;
+};
+
+export const selectSplittedBorrowsForMigration = (userReserves: ComputedUserReserveData[]) => {
+ const splittedUserReserves: SplittedUserReserveIncreasedAmount[] = [];
+ userReserves.forEach((userReserve) => {
+ if (userReserve.stableBorrows !== '0') {
+ const increasedAmount = add1HourBorrowAPY(
+ userReserve.stableBorrows,
+ userReserve.reserve.stableBorrowAPY
+ );
+ splittedUserReserves.push({
+ ...userReserve,
+ interestRate: InterestRate.Stable,
+ increasedStableBorrows: increasedAmount,
+ increasedVariableBorrows: '0',
+ debtKey: userReserve.reserve.stableDebtTokenAddress,
+ });
+ }
+ if (userReserve.variableBorrows !== '0') {
+ const increasedAmount = add1HourBorrowAPY(
+ userReserve.variableBorrows,
+ userReserve.reserve.variableBorrowAPY
+ );
+ splittedUserReserves.push({
+ ...userReserve,
+ interestRate: InterestRate.Variable,
+ increasedStableBorrows: '0',
+ increasedVariableBorrows: increasedAmount,
+ debtKey: userReserve.reserve.variableDebtTokenAddress,
+ });
+ }
+ });
+ return splittedUserReserves;
+};
+
+export const selectDefinitiveSupplyAssetForMigration = (
+ store: RootStore,
+ userReservesV3Map: Record<
+ string,
+ ComputedUserReserve
+ >
+) => {
+ const enforcedAssets = store.selectedMigrationSupplyAssets.filter(
+ (supplyAsset) => supplyAsset.enforced
+ );
+
+ if (enforcedAssets.length > 0) {
+ return enforcedAssets;
+ }
+
+ const nonIsolatedAssets = store.selectedMigrationSupplyAssets.filter((supplyAsset) => {
+ const v3UserReserve = userReservesV3Map[supplyAsset.underlyingAsset];
+ return v3UserReserve.underlyingBalance == '0' && !v3UserReserve.reserve.isIsolated;
+ });
+
+ if (nonIsolatedAssets.length > 0) {
+ return nonIsolatedAssets;
+ }
+
+ const isolatedAssets = store.selectedMigrationSupplyAssets.filter((supplyAsset) => {
+ const v3UserReserve = userReservesV3Map[supplyAsset.underlyingAsset];
+ return v3UserReserve.underlyingBalance == '0' && v3UserReserve.reserve.isIsolated;
+ });
+
+ return isolatedAssets;
+};
+
+export const selectUserReservesMapFromUserReserves = (
+ userReservesData: ComputedUserReserve[]
+) => {
+ const v3ReservesMap = userReservesData.reduce((obj, item) => {
+ obj[item.underlyingAsset] = item;
+ return obj;
+ }, {} as Record>);
+
+ return v3ReservesMap;
+};
+
+export const selectUserReservesForMigration = (store: RootStore, timestamp: number) => {
+ const { userReservesData: userReserveV3Data, ...v3ReservesUserSummary } = selectV3UserSummary(
+ store,
+ timestamp
+ );
+
+ const { userReservesData: userReservesV2Data, ...v2ReservesUserSummary } =
+ selectUserSummaryAndIncentives(store, timestamp);
+
+ const poolReserveV3 = selectCurrentChainIdV3PoolReserve(store);
+ const userEmodeCategoryId = poolReserveV3?.userEmodeCategoryId;
+
+ let isolatedReserveV3 = selectIsolationModeForMigration(v3ReservesUserSummary);
+
+ const v3ReservesMap = selectUserReservesMapFromUserReserves(userReserveV3Data);
+
+ if (v3ReservesUserSummary.totalCollateralMarketReferenceCurrency == '0') {
+ const definitiveAssets = selectDefinitiveSupplyAssetForMigration(store, v3ReservesMap);
+ if (definitiveAssets.length > 0) {
+ const definitiveAsset = v3ReservesMap[definitiveAssets[0].underlyingAsset];
+ if (definitiveAsset.reserve.usageAsCollateralEnabled && definitiveAsset.reserve.isIsolated) {
+ isolatedReserveV3 = definitiveAsset.reserve;
+ }
+ }
+ }
+
+ const supplyReserves = userReservesV2Data.filter(
+ (userReserve) => userReserve.underlyingBalance !== '0'
+ );
+
+ const borrowReserves = selectSplittedBorrowsForMigration(userReservesV2Data);
+
+ const mappedSupplyReserves = supplyReserves.map((userReserve) => {
+ let usageAsCollateralEnabledOnUser = true;
+ const isolatedOnV3 = v3ReservesMap[userReserve.underlyingAsset]?.reserve.isIsolated;
+ const canBeEnforced = v3ReservesMap[userReserve.underlyingAsset]?.underlyingBalance == '0';
+ if (isolatedReserveV3) {
+ usageAsCollateralEnabledOnUser =
+ userReserve.underlyingAsset == isolatedReserveV3.underlyingAsset;
+ } else {
+ const v3SupplyAsset = v3ReservesMap[userReserve.underlyingAsset];
+ if (v3SupplyAsset?.underlyingBalance !== '0') {
+ usageAsCollateralEnabledOnUser = v3SupplyAsset?.usageAsCollateralEnabledOnUser;
+ } else {
+ usageAsCollateralEnabledOnUser = !isolatedOnV3;
+ }
+ }
+ return {
+ ...userReserve,
+ usageAsCollateralEnabledOnUser,
+ isolatedOnV3,
+ canBeEnforced,
+ };
+ });
+
+ const mappedBorrowReserves = borrowReserves.map((userReserve) => {
+ // TOOD: make mapping for liquidity
+ let disabledForMigration = false;
+ const selectedReserve = v3ReservesMap[userReserve.underlyingAsset]?.reserve;
+
+ if (isolatedReserveV3) {
+ disabledForMigration = !selectedReserve.borrowableInIsolation;
+ } else {
+ disabledForMigration = !v3ReservesMap[userReserve.underlyingAsset];
+ }
+ if (!disabledForMigration && userEmodeCategoryId !== 0) {
+ disabledForMigration = selectedReserve?.eModeCategoryId !== userEmodeCategoryId;
+ }
+ return {
+ ...userReserve,
+ disabledForMigration,
+ };
+ });
+
+ return {
+ totalCollateralUSD: v2ReservesUserSummary.totalCollateralUSD,
+ totalBorrowsUSD: v2ReservesUserSummary.totalBorrowsUSD,
+ healthFactor: v2ReservesUserSummary.healthFactor,
+ borrowReserves: mappedBorrowReserves,
+ supplyReserves: mappedSupplyReserves,
+ isolatedReserveV3,
+ };
+};
+
+export const selectedUserSupplyReservesForMigration = (store: RootStore, timestamp: number) => {
+ const { supplyReserves, isolatedReserveV3 } = selectUserReservesForMigration(store, timestamp);
+ const selectedUserReserves = supplyReserves.filter(
+ (userReserve) => selectMigrationSelectedSupplyIndex(store, userReserve.underlyingAsset) >= 0
+ );
+ selectedUserReserves.sort((userReserve) => {
+ if (!isolatedReserveV3) {
+ if (userReserve.isolatedOnV3) {
+ return 1;
+ }
+ return -1;
+ } else {
+ if (isolatedReserveV3.underlyingAsset == userReserve.underlyingAsset) {
+ return -1;
+ } else {
+ return 1;
+ }
+ }
+ });
+
+ return selectedUserReserves;
+};
+
+export const selectUserSupplyIncreasedReservesForMigrationPermits = (
+ store: RootStore,
+ timestamp: number
+) => {
+ return selectedUserSupplyReservesForMigration(store, timestamp).map((userReserve) => {
+ const increasedAmount = addPercent(userReserve.underlyingBalance);
+ const valueInWei = valueToWei(increasedAmount, userReserve.reserve.decimals);
+ return { ...userReserve, increasedAmount: valueInWei };
+ });
+};
+
+export const selectUserSupplyAssetsForMigrationNoPermit = (store: RootStore, timestamp: number) => {
+ const selectedUserReserves = selectedUserSupplyReservesForMigration(store, timestamp);
+ return selectedUserReserves.map(({ underlyingAsset, reserve }) => {
+ const deadline = Math.floor(Date.now() / 1000 + 3600);
+ return {
+ amount: constants.MaxUint256.toString(),
+ aToken: reserve.aTokenAddress,
+ underlyingAsset: underlyingAsset,
+ deadline,
+ };
+ });
+};
+
+export const selectUserSupplyAssetsForMigrationWithPermits = (
+ store: RootStore,
+ signatures: SignatureLike[],
+ deadline: BigNumberish
+): V3MigrationHelperSignedPermit[] => {
+ return store.approvalPermitsForMigrationAssets.map(({ amount, underlyingAsset }, index) => {
+ return {
+ signedPermit: signatures[index],
+ deadline,
+ aToken: underlyingAsset,
+ value: amount,
+ };
+ });
+};
+
+const addPercent = (amount: string) => {
+ const convertedAmount = valueToBigNumber(amount);
+ return convertedAmount.plus(convertedAmount.div(1000)).toString();
+};
+
+// adding 30 min of variable or either stable or variable debt APY similar to swap
+// https://github.com/aave/interface/blob/main/src/hooks/useSwap.ts#L72-L78
+const add1HourBorrowAPY = (amount: string, borrowAPY: string) => {
+ const convertedAmount = valueToBigNumber(amount);
+ const convertedBorrowAPY = valueToBigNumber(borrowAPY);
+ return convertedAmount
+ .plus(convertedAmount.multipliedBy(convertedBorrowAPY).dividedBy(360 * 48))
+ .toString();
+};
+
+export const selectSelectedBorrowReservesForMigrationV3 = (store: RootStore, timestamp: number) => {
+ const { borrowReserves } = selectUserReservesForMigration(store, timestamp);
+ const { userReservesData: userReservesDataV3 } = selectV3UserSummary(store, timestamp);
+ const selectedUserReserves = borrowReserves
+ .filter(
+ (userReserve) =>
+ selectMigrationSelectedBorrowIndex(store.selectedMigrationBorrowAssets, userReserve) >= 0
+ )
+ .filter((userReserve) => !userReserve.disabledForMigration)
+ // debtKey should be mapped for v3Migration
+ .map((borrowReserve) => {
+ let debtKey = borrowReserve.debtKey;
+ const borrowReserveV3 = userReservesDataV3.find(
+ (userReserve) => userReserve.underlyingAsset == borrowReserve.underlyingAsset
+ );
+
+ if (borrowReserveV3) {
+ if (borrowReserve.interestRate == InterestRate.Variable) {
+ debtKey = borrowReserveV3.reserve.variableDebtTokenAddress;
+ } else {
+ debtKey = borrowReserveV3.reserve.stableDebtTokenAddress;
+ }
+ }
+
+ return {
+ ...borrowReserve,
+ debtKey,
+ };
+ });
+
+ return selectedUserReserves;
+};
+
+export const selectFormatUserSummaryForMigration = (
+ reserves: ReserveDataHumanized[] = [],
+ userReserves: UserReserveDataHumanized[] = [],
+ baseCurrencyData: PoolBaseCurrencyHumanized,
+ currentTimestamp: number,
+ userEmodeCategoryId = 0
+) => {
+ const { marketReferenceCurrencyDecimals, marketReferenceCurrencyPriceInUsd } = baseCurrencyData;
+ const formattedReserves = formatReserves({
+ reserves: reserves,
+ currentTimestamp,
+ marketReferenceCurrencyDecimals: marketReferenceCurrencyDecimals,
+ marketReferencePriceInUsd: marketReferenceCurrencyPriceInUsd,
+ });
+
+ const formattedSummary = formatUserSummary({
+ currentTimestamp,
+ formattedReserves,
+ marketReferenceCurrencyDecimals: marketReferenceCurrencyDecimals,
+ marketReferencePriceInUsd: marketReferenceCurrencyPriceInUsd,
+ userReserves,
+ userEmodeCategoryId,
+ });
+
+ return formattedSummary;
+};
+
+export const selectV2UserSummaryAfterMigration = (store: RootStore, currentTimestamp: number) => {
+ const poolReserve = selectCurrentChainIdV2PoolReserve(store);
+
+ const userReserves =
+ poolReserve?.userReserves?.map((userReserve) => {
+ let scaledATokenBalance = userReserve.scaledATokenBalance;
+ let principalStableDebt = userReserve.principalStableDebt;
+ let scaledVariableDebt = userReserve.scaledVariableDebt;
+
+ const isSupplyAsset =
+ selectMigrationSelectedSupplyIndex(store, userReserve.underlyingAsset) >= 0;
+ if (isSupplyAsset) {
+ scaledATokenBalance = '0';
+ }
+
+ const borrowAssets = store.selectedMigrationBorrowAssets.filter(
+ (borrowAsset) => borrowAsset.underlyingAsset == userReserve.underlyingAsset
+ );
+
+ borrowAssets.forEach((borrowAsset) => {
+ if (borrowAsset.interestRate == InterestRate.Stable) {
+ principalStableDebt = '0';
+ } else {
+ scaledVariableDebt = '0';
+ }
+ });
+
+ return {
+ ...userReserve,
+ principalStableDebt,
+ scaledATokenBalance,
+ scaledVariableDebt,
+ };
+ }) || [];
+
+ const baseCurrencyData = selectFormatBaseCurrencyData(poolReserve);
+
+ return selectFormatUserSummaryForMigration(
+ poolReserve?.reserves,
+ userReserves,
+ baseCurrencyData,
+ currentTimestamp,
+ poolReserve?.userEmodeCategoryId
+ );
+};
+
+export const selectV3UserSummaryAfterMigration = (store: RootStore, currentTimestamp: number) => {
+ const poolReserveV3Summary = selectV3UserSummary(store, currentTimestamp);
+ const poolReserveV3 = selectCurrentChainIdV3PoolReserve(store);
+
+ const supplies = selectedUserSupplyReservesForMigration(store, currentTimestamp);
+ const borrows = selectSelectedBorrowReservesForMigrationV3(store, currentTimestamp);
+
+ //TODO: refactor that to be more efficient
+ const suppliesMap = supplies.concat(supplies).reduce((obj, item) => {
+ obj[item.underlyingAsset] = item;
+ return obj;
+ }, {} as Record);
+
+ const borrowsMap = borrows.concat(borrows).reduce((obj, item) => {
+ obj[item.debtKey] = item;
+ return obj;
+ }, {} as Record);
+
+ const userReserves = poolReserveV3Summary.userReservesData.map((userReserveData) => {
+ const stableBorrowAsset = borrowsMap[userReserveData.reserve.stableDebtTokenAddress];
+ const variableBorrowAsset = borrowsMap[userReserveData.reserve.variableDebtTokenAddress];
+
+ const supplyAsset = suppliesMap[userReserveData.underlyingAsset];
+
+ let combinedScaledDownVariableDebtV3 = userReserveData.scaledVariableDebt;
+ let combinedScaledDownABalance = userReserveData.scaledATokenBalance;
+ let usageAsCollateralEnabledOnUser = userReserveData.usageAsCollateralEnabledOnUser;
+ // TODO: combine stable borrow amount as well
+ const variableBorrowIndexV3 = valueToBigNumber(userReserveData.reserve.variableBorrowIndex);
+ if (variableBorrowAsset) {
+ const scaledDownVariableDebtV2Balance = rayDiv(
+ valueToWei(variableBorrowAsset.increasedVariableBorrows, userReserveData.reserve.decimals),
+ variableBorrowIndexV3
+ );
+ combinedScaledDownVariableDebtV3 = valueToBigNumber(combinedScaledDownVariableDebtV3)
+ .plus(scaledDownVariableDebtV2Balance)
+ .toString();
+ }
+ if (stableBorrowAsset) {
+ const scaledDownStableDebtV2Balance = rayDiv(
+ valueToWei(stableBorrowAsset.increasedStableBorrows, userReserveData.reserve.decimals),
+ variableBorrowIndexV3
+ );
+ combinedScaledDownVariableDebtV3 = valueToBigNumber(combinedScaledDownVariableDebtV3)
+ .plus(scaledDownStableDebtV2Balance)
+ .toString();
+ }
+
+ if (supplyAsset) {
+ const scaledDownATokenBalance = valueToBigNumber(userReserveData.scaledATokenBalance);
+ const liquidityIndexV3 = valueToBigNumber(userReserveData.reserve.liquidityIndex);
+ const scaledDownBalanceV2 = rayDiv(
+ valueToWei(supplyAsset.underlyingBalance, userReserveData.reserve.decimals),
+ liquidityIndexV3
+ );
+ combinedScaledDownABalance = scaledDownATokenBalance.plus(scaledDownBalanceV2).toString();
+ usageAsCollateralEnabledOnUser = supplyAsset.usageAsCollateralEnabledOnUser;
+ }
+
+ return {
+ ...userReserveData,
+ id: userReserveData.reserve.id,
+ scaledVariableDebt: combinedScaledDownVariableDebtV3,
+ scaledATokenBalance: combinedScaledDownABalance,
+ usageAsCollateralEnabledOnUser,
+ };
+ });
+
+ const baseCurrencyData = selectFormatBaseCurrencyData(poolReserveV3);
+
+ const formattedUserSummary = selectFormatUserSummaryForMigration(
+ poolReserveV3?.reserves,
+ userReserves,
+ baseCurrencyData,
+ currentTimestamp,
+ poolReserveV3?.userEmodeCategoryId
+ );
+
+ // return the smallest object possible for migration page
+ return {
+ healthFactor: formattedUserSummary.healthFactor,
+ };
+};
+
+export const selectV3UserSummary = (store: RootStore, timestamp: number) => {
+ const poolReserveV3 = selectCurrentChainIdV3PoolReserve(store);
+ const baseCurrencyData = selectFormatBaseCurrencyData(poolReserveV3);
+
+ const formattedUserSummary = selectFormatUserSummaryForMigration(
+ poolReserveV3?.reserves,
+ poolReserveV3?.userReserves,
+ baseCurrencyData,
+ timestamp,
+ poolReserveV3?.userEmodeCategoryId
+ );
+ return formattedUserSummary;
+};
+
+export const selectIsMigrationAvailable = (store: RootStore) => {
+ return Boolean(store.currentMarketData.addresses.V3_MIGRATOR);
+};
diff --git a/src/store/v3MigrationSlice.ts b/src/store/v3MigrationSlice.ts
new file mode 100644
index 0000000000..e33d78df9c
--- /dev/null
+++ b/src/store/v3MigrationSlice.ts
@@ -0,0 +1,326 @@
+import {
+ ERC20_2612Service,
+ ERC20Service,
+ EthereumTransactionTypeExtended,
+ InterestRate,
+ Pool,
+ V3MigrationHelperService,
+} from '@aave/contract-helpers';
+import { V3MigrationHelperSignedPermit } from '@aave/contract-helpers/dist/esm/v3-migration-contract/v3MigrationTypes';
+import { SignatureLike } from '@ethersproject/bytes';
+import dayjs from 'dayjs';
+import { BigNumberish } from 'ethers';
+import { produce } from 'immer';
+import { Approval } from 'src/helpers/useTransactionHandler';
+import { StateCreator } from 'zustand';
+
+import { selectCurrentChainIdV3MarketData } from './poolSelectors';
+import { RootStore } from './root';
+import {
+ selectedUserSupplyReservesForMigration,
+ selectMigrationSelectedBorrowIndex,
+ selectMigrationSelectedSupplyIndex,
+ selectSelectedBorrowReservesForMigrationV3,
+ selectUserReservesForMigration,
+ selectUserSupplyAssetsForMigrationNoPermit,
+ selectUserSupplyAssetsForMigrationWithPermits,
+ selectUserSupplyIncreasedReservesForMigrationPermits,
+} from './v3MigrationSelectors';
+
+type MigrationSelectedAsset = {
+ underlyingAsset: string;
+ enforced: boolean;
+};
+
+export type MigrationSelectedBorrowAsset = {
+ debtKey: string;
+ underlyingAsset: string;
+ interestRate: InterestRate;
+};
+
+export type V3MigrationSlice = {
+ //STATE
+ selectedMigrationSupplyAssets: MigrationSelectedAsset[];
+ selectedMigrationBorrowAssets: MigrationSelectedBorrowAsset[];
+ migrationServiceInstances: Record;
+ timestamp: number;
+ approvalPermitsForMigrationAssets: Array;
+ // ACTIONS
+ generatePermitPayloadForMigrationAsset: (
+ approval: Approval & {
+ deadline: string;
+ }
+ ) => Promise;
+ getApprovePermitsForSelectedAssets: () => Promise;
+ toggleMigrationSelectedSupplyAsset: (assetName: string) => void;
+ toggleMigrationSelectedBorrowAsset: (asset: MigrationSelectedBorrowAsset) => void;
+ getMigratorAddress: () => string;
+ getMigrationServiceInstance: () => V3MigrationHelperService;
+ migrateWithPermits: (
+ signature: SignatureLike[],
+ deadline: BigNumberish
+ ) => Promise;
+ migrateWithoutPermits: () => Promise;
+ migrateBorrow: (
+ signedPermits?: V3MigrationHelperSignedPermit[]
+ ) => Promise;
+ resetMigrationSelectedAssets: () => void;
+ enforceAsCollateral: (underlyingAsset: string) => void;
+ selectAllBorrow: (timestamp: number) => void;
+ selectAllSupply: (timestamp: number) => void;
+};
+
+export const createV3MigrationSlice: StateCreator<
+ RootStore,
+ [['zustand/devtools', never]],
+ [],
+ V3MigrationSlice
+> = (set, get) => {
+ return {
+ selectedMigrationSupplyAssets: [],
+ selectedMigrationBorrowAssets: [],
+ migrationServiceInstances: {},
+ timestamp: 0,
+ approvalPermitsForMigrationAssets: [],
+ generatePermitPayloadForMigrationAsset: async ({ amount, underlyingAsset, deadline }) => {
+ const user = get().account;
+ const { getTokenData } = new ERC20Service(get().jsonRpcProvider());
+
+ const { name } = await getTokenData(underlyingAsset);
+ const chainId = get().currentChainId;
+
+ const erc20_2612Service = new ERC20_2612Service(get().jsonRpcProvider());
+
+ const nonce = await erc20_2612Service.getNonce({
+ token: underlyingAsset,
+ owner: user,
+ });
+
+ const typeData = {
+ types: {
+ EIP712Domain: [
+ { name: 'name', type: 'string' },
+ { name: 'version', type: 'string' },
+ { name: 'chainId', type: 'uint256' },
+ { name: 'verifyingContract', type: 'address' },
+ ],
+ Permit: [
+ // { name: 'PERMIT_TYPEHASH', type: 'string' },
+ { name: 'owner', type: 'address' },
+ { name: 'spender', type: 'address' },
+ { name: 'value', type: 'uint256' },
+ { name: 'nonce', type: 'uint256' },
+ { name: 'deadline', type: 'uint256' },
+ ],
+ },
+ primaryType: 'Permit',
+ domain: {
+ name,
+ version: '1',
+ chainId,
+ verifyingContract: underlyingAsset,
+ },
+ message: {
+ owner: user,
+ spender: get().getMigratorAddress(),
+ value: amount,
+ nonce,
+ deadline,
+ },
+ };
+ return JSON.stringify(typeData);
+ },
+ toggleMigrationSelectedSupplyAsset: (underlyingAsset: string) => {
+ set((state) =>
+ produce(state, (draft) => {
+ const activeAssetIndex = draft.selectedMigrationSupplyAssets.findIndex(
+ (asset) => asset.underlyingAsset == underlyingAsset
+ );
+
+ if (activeAssetIndex >= 0) {
+ draft.selectedMigrationSupplyAssets.splice(activeAssetIndex, 1);
+ } else {
+ draft.selectedMigrationSupplyAssets.push({
+ underlyingAsset,
+ enforced: false,
+ });
+ }
+ })
+ );
+ },
+ toggleMigrationSelectedBorrowAsset: (asset: MigrationSelectedBorrowAsset) => {
+ set((state) =>
+ produce(state, (draft) => {
+ const activeAssetIndex = draft.selectedMigrationBorrowAssets.findIndex(
+ (selectedAsset) => asset.debtKey == selectedAsset.debtKey
+ );
+
+ if (activeAssetIndex >= 0) {
+ draft.selectedMigrationBorrowAssets.splice(activeAssetIndex, 1);
+ } else {
+ draft.selectedMigrationBorrowAssets.push(asset);
+ }
+ })
+ );
+ },
+ enforceAsCollateral: (underlyingAsset: string) => {
+ set((state) =>
+ produce(state, (draft) => {
+ const assetIndex = selectMigrationSelectedSupplyIndex(get(), underlyingAsset);
+ const assetEnforced = draft.selectedMigrationSupplyAssets[assetIndex]?.enforced;
+ if (assetIndex >= 0) {
+ draft.selectedMigrationSupplyAssets.forEach((asset) => {
+ asset.enforced = false;
+ });
+ draft.selectedMigrationSupplyAssets[assetIndex].enforced = !assetEnforced;
+ }
+ })
+ );
+ },
+ resetMigrationSelectedAssets: () => {
+ set({
+ selectedMigrationBorrowAssets: [],
+ selectedMigrationSupplyAssets: [],
+ });
+ },
+ selectAllSupply: (currentTimestamp: number) => {
+ const { supplyReserves } = selectUserReservesForMigration(get(), currentTimestamp);
+ if (get().selectedMigrationSupplyAssets.length == supplyReserves.length) {
+ set({ selectedMigrationSupplyAssets: [] });
+ } else {
+ const nonSelectedSupplies = supplyReserves
+ .filter(
+ ({ underlyingAsset }) => selectMigrationSelectedSupplyIndex(get(), underlyingAsset) < 0
+ )
+ .map(({ underlyingAsset }) => ({ underlyingAsset, enforced: false }));
+
+ set({
+ selectedMigrationSupplyAssets: [
+ ...get().selectedMigrationSupplyAssets,
+ ...nonSelectedSupplies,
+ ],
+ });
+ }
+ },
+ selectAllBorrow: (currentTimestamp: number) => {
+ const { borrowReserves } = selectUserReservesForMigration(get(), currentTimestamp);
+ if (get().selectedMigrationBorrowAssets.length == borrowReserves.length) {
+ set({ selectedMigrationBorrowAssets: [] });
+ } else {
+ const nonSelectedSupplies = borrowReserves.filter(
+ (borrowAsset) =>
+ selectMigrationSelectedBorrowIndex(get().selectedMigrationBorrowAssets, borrowAsset) < 0
+ );
+
+ set({
+ selectedMigrationBorrowAssets: [
+ ...get().selectedMigrationBorrowAssets,
+ ...nonSelectedSupplies,
+ ],
+ });
+ }
+ },
+ getApprovePermitsForSelectedAssets: async () => {
+ const timestamp = dayjs().unix();
+ const approvalPermitsForMigrationAssets = await Promise.all(
+ selectUserSupplyIncreasedReservesForMigrationPermits(get(), timestamp).map(
+ async ({ reserve, increasedAmount }): Promise => {
+ return {
+ amount: increasedAmount,
+ underlyingAsset: reserve.aTokenAddress,
+ permitType: 'MIGRATOR',
+ };
+ }
+ )
+ );
+ set({ approvalPermitsForMigrationAssets });
+ return approvalPermitsForMigrationAssets;
+ },
+ migrateWithoutPermits: () => {
+ const timestamp = dayjs().unix();
+ set({ timestamp });
+ const borrowedPositions = selectSelectedBorrowReservesForMigrationV3(get(), timestamp);
+ if (borrowedPositions.length > 0) {
+ return get().migrateBorrow();
+ }
+ const assets = selectUserSupplyAssetsForMigrationNoPermit(get(), timestamp);
+ const user = get().account;
+ return get().getMigrationServiceInstance().migrateNoBorrow({ assets, user });
+ },
+ migrateWithPermits: async (signatures: SignatureLike[], deadline: BigNumberish) => {
+ const signedPermits = selectUserSupplyAssetsForMigrationWithPermits(
+ get(),
+ signatures,
+ deadline
+ );
+ const borrowedPositions = selectSelectedBorrowReservesForMigrationV3(get(), get().timestamp);
+ if (borrowedPositions.length > 0) {
+ return get().migrateBorrow(signedPermits);
+ }
+
+ const migratorHelperInstance = get().getMigrationServiceInstance();
+ const user = get().account;
+ const assets = selectedUserSupplyReservesForMigration(get(), get().timestamp).map(
+ (reserve) => reserve.underlyingAsset
+ );
+ return migratorHelperInstance.migrateNoBorrowWithPermits({
+ user,
+ assets,
+ deadline,
+ signedPermits,
+ });
+ },
+ getMigratorAddress: () => {
+ return get().currentMarketData.addresses.V3_MIGRATOR || '';
+ },
+ getMigrationServiceInstance: () => {
+ const address = get().getMigratorAddress();
+ const migratorInstance = get().migrationServiceInstances[address];
+ if (migratorInstance) {
+ return migratorInstance;
+ }
+ const provider = get().jsonRpcProvider();
+ const migratorAddress = get().getMigratorAddress();
+
+ // TODO: make it dynamic when network switch will be there
+ const currentMarketV3Data = selectCurrentChainIdV3MarketData(get());
+ const pool = new Pool(provider, {
+ POOL: currentMarketV3Data.addresses.LENDING_POOL,
+ REPAY_WITH_COLLATERAL_ADAPTER: currentMarketV3Data.addresses.REPAY_WITH_COLLATERAL_ADAPTER,
+ SWAP_COLLATERAL_ADAPTER: currentMarketV3Data.addresses.SWAP_COLLATERAL_ADAPTER,
+ WETH_GATEWAY: currentMarketV3Data.addresses.WETH_GATEWAY,
+ L2_ENCODER: currentMarketV3Data.addresses.L2_ENCODER,
+ });
+ const migrationServiceInstances = get().migrationServiceInstances;
+ const newMigratorInstance = new V3MigrationHelperService(provider, migratorAddress, pool);
+ set({
+ migrationServiceInstances: { ...migrationServiceInstances, [address]: newMigratorInstance },
+ });
+ return newMigratorInstance;
+ },
+ migrateBorrow: async (signedPermits: V3MigrationHelperSignedPermit[] = []) => {
+ const currentTimestamp = dayjs().unix();
+ const user = get().account;
+ const suppliedPositions = selectUserSupplyAssetsForMigrationNoPermit(get(), currentTimestamp);
+ const borrowedPositions = selectSelectedBorrowReservesForMigrationV3(get(), currentTimestamp);
+ const mappedBorrowPositions = borrowedPositions.map(
+ ({ increasedStableBorrows, increasedVariableBorrows, interestRate, underlyingAsset }) => {
+ return {
+ amount:
+ interestRate == InterestRate.Variable
+ ? increasedVariableBorrows
+ : increasedStableBorrows,
+ interestRate,
+ address: underlyingAsset,
+ };
+ }
+ );
+ return get().getMigrationServiceInstance().migrateWithBorrow({
+ user,
+ borrowedPositions: mappedBorrowPositions,
+ suppliedPositions,
+ signedPermits,
+ });
+ },
+ };
+};
diff --git a/src/ui-config/marketsConfig.tsx b/src/ui-config/marketsConfig.tsx
index 8a706297a3..4ab032a993 100644
--- a/src/ui-config/marketsConfig.tsx
+++ b/src/ui-config/marketsConfig.tsx
@@ -31,6 +31,7 @@ export type MarketDataType = {
UI_POOL_DATA_PROVIDER: string;
UI_INCENTIVE_DATA_PROVIDER?: string;
COLLECTOR?: string;
+ V3_MIGRATOR?: string;
};
/**
* https://www.hal.xyz/ has integrated aave for healtfactor warning notification
@@ -152,6 +153,7 @@ export const marketsData: {
UI_POOL_DATA_PROVIDER: '0x0d24b23DBaB0dc1A6F58029bA94F94Ff0D5382c2',
UI_INCENTIVE_DATA_PROVIDER: '0x645654D59A5226CBab969b1f5431aA47CBf64ab8',
COLLECTOR: '0x7734280A4337F37Fbf4651073Db7c28C80B339e9',
+ V3_MIGRATOR: '0x01ce9bbcc0418614a8bba983fe79cf77211996f2',
},
halIntegration: {
URL: 'https://app.hal.xyz/recipes/aave-track-your-health-factor',
@@ -176,6 +178,7 @@ export const marketsData: {
UI_POOL_DATA_PROVIDER: '0xa7da242e099136A71fF975B8D78b79AA543c9182',
UI_INCENTIVE_DATA_PROVIDER: '0x11979886A6dBAE27D7a72c49fCF3F23240D647bF',
COLLECTOR: '0x467b92aF281d14cB6809913AD016a607b5ba8A36',
+ // V3_MIGRATOR: '0x52a8e9986e2c6f95c8c17b13fc58d06d05b3384a',
},
halIntegration: {
URL: 'https://app.hal.xyz/recipes/aave-track-your-health-factor',