diff --git a/cypress/e2e/0-v2-markets/0-main-v2-market/0-assets/dai.aave-v2.cy.ts b/cypress/e2e/0-v2-markets/0-main-v2-market/0-assets/dai.aave-v2.cy.ts index 1eb495a42c..e87dac8cae 100644 --- a/cypress/e2e/0-v2-markets/0-main-v2-market/0-assets/dai.aave-v2.cy.ts +++ b/cypress/e2e/0-v2-markets/0-main-v2-market/0-assets/dai.aave-v2.cy.ts @@ -59,14 +59,13 @@ const testData = { hasApproval: true, repayOption: constants.repayType.default, }, - // { - // asset: assets.aaveMarket.DAI, - // apyType: constants.apyType.stable, - // amount: 10, - // hasApproval: false, - // repayOption: constants.repayType.collateral, - // assetForRepay: assets.aaveMarket.BAT, - // }, + { + asset: assets.aaveMarket.DAI, + apyType: constants.apyType.stable, + amount: 10, + hasApproval: false, + repayOption: constants.repayType.collateral, + }, ], withdraw: { asset: assets.aaveMarket.DAI, @@ -81,7 +80,6 @@ const testData = { type: constants.dashboardTypes.deposit, assetName: assets.aaveMarket.DAI.shortName, wrapped: assets.aaveMarket.DAI.wrapped, - // amount: 30, amount: 40, collateralType: constants.collateralType.isCollateral, isCollateral: true, @@ -90,8 +88,7 @@ const testData = { type: constants.dashboardTypes.borrow, assetName: assets.aaveMarket.DAI.shortName, wrapped: assets.aaveMarket.DAI.wrapped, - // amount: 80, - amount: 90, + amount: 80, apyType: constants.borrowAPYType.stable, }, ], diff --git a/cypress/e2e/0-v2-markets/0-main-v2-market/0-assets/ren.aave-v2.cy.ts b/cypress/e2e/0-v2-markets/0-main-v2-market/0-assets/ren.aave-v2.cy.ts index 7d8c3b2988..f811b984b5 100644 --- a/cypress/e2e/0-v2-markets/0-main-v2-market/0-assets/ren.aave-v2.cy.ts +++ b/cypress/e2e/0-v2-markets/0-main-v2-market/0-assets/ren.aave-v2.cy.ts @@ -59,14 +59,13 @@ const testData = { hasApproval: true, repayOption: constants.repayType.default, }, - // { - // asset: assets.aaveMarket.REN, - // apyType: constants.apyType.stable, - // amount: 20, - // hasApproval: false, - // repayOption: constants.repayType.collateral, - // assetForRepay: assets.aaveMarket.BAT, - // }, + { + asset: assets.aaveMarket.REN, + apyType: constants.apyType.stable, + amount: 20, + hasApproval: false, + repayOption: constants.repayType.collateral, + }, ], withdraw: { asset: assets.aaveMarket.REN, @@ -81,7 +80,6 @@ const testData = { type: constants.dashboardTypes.deposit, assetName: assets.aaveMarket.REN.shortName, wrapped: assets.aaveMarket.REN.wrapped, - // amount: 60, amount: 80, collateralType: constants.collateralType.isCollateral, isCollateral: true, @@ -90,8 +88,7 @@ const testData = { type: constants.dashboardTypes.borrow, assetName: assets.aaveMarket.REN.shortName, wrapped: assets.aaveMarket.REN.wrapped, - // amount: 160, - amount: 180, + amount: 160, apyType: constants.borrowAPYType.stable, }, ], diff --git a/cypress/e2e/0-v2-markets/0-main-v2-market/0-assets/tusd.aave-v2.cy.ts b/cypress/e2e/0-v2-markets/0-main-v2-market/0-assets/tusd.aave-v2.cy.ts index a932392319..3900460d95 100644 --- a/cypress/e2e/0-v2-markets/0-main-v2-market/0-assets/tusd.aave-v2.cy.ts +++ b/cypress/e2e/0-v2-markets/0-main-v2-market/0-assets/tusd.aave-v2.cy.ts @@ -59,14 +59,13 @@ const testData = { hasApproval: true, repayOption: constants.repayType.default, }, - // { - // asset: assets.aaveMarket.TUSD, - // apyType: constants.apyType.stable, - // amount: 10, - // hasApproval: false, - // repayOption: constants.repayType.collateral, - // assetForRepay: assets.aaveMarket.TUSD, - // }, + { + asset: assets.aaveMarket.TUSD, + apyType: constants.apyType.stable, + amount: 10, + hasApproval: false, + repayOption: constants.repayType.collateral, + }, ], withdraw: { asset: assets.aaveMarket.TUSD, @@ -81,7 +80,6 @@ const testData = { type: constants.dashboardTypes.deposit, assetName: assets.aaveMarket.TUSD.shortName, wrapped: assets.aaveMarket.TUSD.wrapped, - // amount: 30, amount: 40, collateralType: constants.collateralType.isCollateral, isCollateral: true, @@ -90,8 +88,7 @@ const testData = { type: constants.dashboardTypes.borrow, assetName: assets.aaveMarket.TUSD.shortName, wrapped: assets.aaveMarket.TUSD.wrapped, - // amount: 80, - amount: 90, + amount: 80, apyType: constants.borrowAPYType.stable, }, ], diff --git a/cypress/e2e/0-v2-markets/0-main-v2-market/0-assets/usdc.aave-v2.cy.ts b/cypress/e2e/0-v2-markets/0-main-v2-market/0-assets/usdc.aave-v2.cy.ts index c5d22718f7..6d1ce859fb 100644 --- a/cypress/e2e/0-v2-markets/0-main-v2-market/0-assets/usdc.aave-v2.cy.ts +++ b/cypress/e2e/0-v2-markets/0-main-v2-market/0-assets/usdc.aave-v2.cy.ts @@ -59,14 +59,13 @@ const testData = { hasApproval: true, repayOption: constants.repayType.default, }, - // { - // asset: assets.aaveMarket.USDC, - // apyType: constants.apyType.stable, - // amount: 10, - // hasApproval: false, - // repayOption: constants.repayType.collateral, - // assetForRepay: assets.aaveMarket.USDC, - // }, + { + asset: assets.aaveMarket.USDC, + apyType: constants.apyType.stable, + amount: 10, + hasApproval: false, + repayOption: constants.repayType.collateral, + }, ], withdraw: { asset: assets.aaveMarket.USDC, @@ -81,7 +80,6 @@ const testData = { type: constants.dashboardTypes.deposit, assetName: assets.aaveMarket.USDC.shortName, wrapped: assets.aaveMarket.USDC.wrapped, - // amount: 30, amount: 40, collateralType: constants.collateralType.isCollateral, isCollateral: true, @@ -90,8 +88,7 @@ const testData = { type: constants.dashboardTypes.borrow, assetName: assets.aaveMarket.USDC.shortName, wrapped: assets.aaveMarket.USDC.wrapped, - // amount: 80, - amount: 90, + amount: 80, apyType: constants.borrowAPYType.stable, }, ], diff --git a/cypress/e2e/0-v2-markets/0-main-v2-market/0-assets/usdt.aave-v2.cy.ts b/cypress/e2e/0-v2-markets/0-main-v2-market/0-assets/usdt.aave-v2.cy.ts index 90779a4569..d55c05c2b2 100644 --- a/cypress/e2e/0-v2-markets/0-main-v2-market/0-assets/usdt.aave-v2.cy.ts +++ b/cypress/e2e/0-v2-markets/0-main-v2-market/0-assets/usdt.aave-v2.cy.ts @@ -62,14 +62,13 @@ const testData = { hasApproval: true, repayOption: constants.repayType.default, }, - // { - // asset: assets.aaveMarket.USDT, - // apyType: constants.apyType.stable, - // amount: 10, - // hasApproval: false, - // repayOption: constants.repayType.collateral, - // assetForRepay: assets.aaveMarket.USDT, - // }, + { + asset: assets.aaveMarket.USDT, + apyType: constants.apyType.stable, + amount: 10, + hasApproval: false, + repayOption: constants.repayType.collateral, + }, ], withdraw: { asset: assets.aaveMarket.USDT, @@ -88,7 +87,6 @@ const testData = { type: constants.dashboardTypes.deposit, assetName: assets.aaveMarket.USDT.shortName, wrapped: assets.aaveMarket.USDT.wrapped, - // amount: 30, amount: 40, collateralType: constants.collateralType.isCollateral, isCollateral: false, @@ -97,8 +95,7 @@ const testData = { type: constants.dashboardTypes.borrow, assetName: assets.aaveMarket.USDT.shortName, wrapped: assets.aaveMarket.USDT.wrapped, - // amount: 80, - amount: 90, + amount: 80, apyType: constants.borrowAPYType.stable, }, ], diff --git a/cypress/e2e/0-v2-markets/2-polygon-v2-market/0-assets/usdc.polygon-v2.cy.ts b/cypress/e2e/0-v2-markets/2-polygon-v2-market/0-assets/usdc.polygon-v2.cy.ts index edbcbfc6e1..8aa9ab3003 100644 --- a/cypress/e2e/0-v2-markets/2-polygon-v2-market/0-assets/usdc.polygon-v2.cy.ts +++ b/cypress/e2e/0-v2-markets/2-polygon-v2-market/0-assets/usdc.polygon-v2.cy.ts @@ -22,13 +22,22 @@ const testData = { amount: 10, hasApproval: false, }, - repay: { - asset: assets.polygonMarket.USDC, - apyType: constants.apyType.variable, - amount: 2, - hasApproval: true, - repayOption: constants.repayType.default, - }, + repay: [ + { + asset: assets.polygonMarket.USDC, + apyType: constants.apyType.variable, + amount: 2, + hasApproval: true, + repayOption: constants.repayType.default, + }, + { + asset: assets.polygonMarket.USDC, + apyType: constants.apyType.variable, + amount: 2, + hasApproval: false, + repayOption: constants.repayType.collateral, + }, + ], withdraw: { asset: assets.polygonMarket.USDC, isCollateral: true, @@ -50,7 +59,7 @@ const testData = { type: constants.dashboardTypes.borrow, assetName: assets.polygonMarket.USDC.shortName, wrapped: assets.polygonMarket.USDC.wrapped, - amount: 23.0, + amount: 21.0, apyType: constants.borrowAPYType.variable, }, ], @@ -64,7 +73,9 @@ describe('USDC INTEGRATION SPEC, POLYGON V2 MARKET', () => { supply(testData.depositBaseAmount, skipTestState, true); borrow(testData.testCases.borrow, skipTestState, true); supply(testData.testCases.deposit, skipTestState, true); - repay(testData.testCases.repay, skipTestState, false); + testData.testCases.repay.forEach((repayCase) => { + repay(repayCase, skipTestState, false); + }); withdraw(testData.testCases.withdraw, skipTestState, false); dashboardAssetValuesVerification(testData.verifications.finalDashboard, skipTestState); }); diff --git a/cypress/e2e/0-v2-markets/2-polygon-v2-market/0-assets/usdt.polygon-v2.cy.ts b/cypress/e2e/0-v2-markets/2-polygon-v2-market/0-assets/usdt.polygon-v2.cy.ts index bda9fd6c8e..68ccca77a0 100644 --- a/cypress/e2e/0-v2-markets/2-polygon-v2-market/0-assets/usdt.polygon-v2.cy.ts +++ b/cypress/e2e/0-v2-markets/2-polygon-v2-market/0-assets/usdt.polygon-v2.cy.ts @@ -25,13 +25,22 @@ const testData = { amount: 10, hasApproval: false, }, - repay: { - asset: assets.polygonMarket.USDT, - apyType: constants.apyType.variable, - amount: 2, - hasApproval: true, - repayOption: constants.repayType.default, - }, + repay: [ + { + asset: assets.polygonMarket.USDT, + apyType: constants.apyType.variable, + amount: 2, + hasApproval: true, + repayOption: constants.repayType.default, + }, + { + asset: assets.polygonMarket.USDT, + apyType: constants.apyType.variable, + amount: 2, + hasApproval: false, + repayOption: constants.repayType.collateral, + }, + ], withdraw: { asset: assets.polygonMarket.USDT, isCollateral: false, @@ -57,7 +66,7 @@ const testData = { type: constants.dashboardTypes.borrow, assetName: assets.polygonMarket.USDT.shortName, wrapped: assets.polygonMarket.USDT.wrapped, - amount: 23.0, + amount: 21.0, apyType: constants.borrowAPYType.variable, }, ], @@ -71,7 +80,9 @@ describe('USDT INTEGRATION SPEC, POLYGON MARKET', () => { supply(testData.depositBaseAmount, skipTestState, true); borrow(testData.testCases.borrow, skipTestState, true); supply(testData.testCases.deposit, skipTestState, true); - repay(testData.testCases.repay, skipTestState, false); + testData.testCases.repay.forEach((repayCase) => { + repay(repayCase, skipTestState, false); + }); withdraw(testData.testCases.withdraw, skipTestState, false); changeBorrowTypeBlocked(testData.testCases.checkDisabledCollateral, skipTestState); dashboardAssetValuesVerification(testData.verifications.finalDashboard, skipTestState); diff --git a/cypress/e2e/0-v2-markets/3-avalanche-v2-market/0-assets/usdc.avalanche-v2.cy.ts b/cypress/e2e/0-v2-markets/3-avalanche-v2-market/0-assets/usdc.avalanche-v2.cy.ts index 44ef49fec1..a8e8d585b0 100644 --- a/cypress/e2e/0-v2-markets/3-avalanche-v2-market/0-assets/usdc.avalanche-v2.cy.ts +++ b/cypress/e2e/0-v2-markets/3-avalanche-v2-market/0-assets/usdc.avalanche-v2.cy.ts @@ -25,13 +25,22 @@ const testData = { amount: 10, hasApproval: false, }, - repay: { - asset: assets.avalancheMarket.USDC, - apyType: constants.apyType.variable, - amount: 2, - hasApproval: true, - repayOption: constants.repayType.default, - }, + repay: [ + { + asset: assets.avalancheMarket.USDC, + apyType: constants.apyType.variable, + amount: 2, + hasApproval: true, + repayOption: constants.repayType.default, + }, + { + asset: assets.avalancheMarket.USDC, + apyType: constants.apyType.variable, + amount: 2, + hasApproval: false, + repayOption: constants.repayType.collateral, + }, + ], withdraw: { asset: assets.avalancheMarket.USDC, isCollateral: true, @@ -57,7 +66,7 @@ const testData = { type: constants.dashboardTypes.borrow, assetName: assets.avalancheMarket.USDC.shortName, wrapped: assets.avalancheMarket.USDC.wrapped, - amount: 23.0, + amount: 21.0, apyType: constants.borrowAPYType.variable, }, ], @@ -71,7 +80,9 @@ describe('USDC INTEGRATION SPEC, AVALANCHE V2 MARKET', () => { supply(testData.depositBaseAmount, skipTestState, true); borrow(testData.testCases.borrow, skipTestState, true); supply(testData.testCases.deposit, skipTestState, true); - repay(testData.testCases.repay, skipTestState, false); + testData.testCases.repay.forEach((repayCase) => { + repay(repayCase, skipTestState, false); + }); withdraw(testData.testCases.withdraw, skipTestState, false); switchApyBlocked(testData.testCases.checkDisabledApy, skipTestState); dashboardAssetValuesVerification(testData.verifications.finalDashboard, skipTestState); diff --git a/cypress/e2e/0-v2-markets/3-avalanche-v2-market/0-assets/usdt.avalanche-v2.cy.ts b/cypress/e2e/0-v2-markets/3-avalanche-v2-market/0-assets/usdt.avalanche-v2.cy.ts index 792537669f..78ea09759d 100644 --- a/cypress/e2e/0-v2-markets/3-avalanche-v2-market/0-assets/usdt.avalanche-v2.cy.ts +++ b/cypress/e2e/0-v2-markets/3-avalanche-v2-market/0-assets/usdt.avalanche-v2.cy.ts @@ -26,13 +26,22 @@ const testData = { amount: 10, hasApproval: false, }, - repay: { - asset: assets.avalancheMarket.USDT, - apyType: constants.apyType.variable, - amount: 2, - hasApproval: true, - repayOption: constants.repayType.default, - }, + repay: [ + { + asset: assets.avalancheMarket.USDT, + apyType: constants.apyType.variable, + amount: 2, + hasApproval: true, + repayOption: constants.repayType.default, + }, + { + asset: assets.avalancheMarket.USDT, + apyType: constants.apyType.variable, + amount: 2, + hasApproval: false, + repayOption: constants.repayType.collateral, + }, + ], withdraw: { asset: assets.avalancheMarket.USDT, isCollateral: false, @@ -62,7 +71,7 @@ const testData = { type: constants.dashboardTypes.borrow, assetName: assets.avalancheMarket.USDT.shortName, wrapped: assets.avalancheMarket.USDT.wrapped, - amount: 23.0, + amount: 21.0, apyType: constants.borrowAPYType.variable, }, ], @@ -76,7 +85,9 @@ describe('USDT INTEGRATION SPEC, AVALANCHE V2 MARKET', () => { supply(testData.depositBaseAmount, skipTestState, true); borrow(testData.testCases.borrow, skipTestState, true); supply(testData.testCases.deposit, skipTestState, true); - repay(testData.testCases.repay, skipTestState, false); + testData.testCases.repay.forEach((repayCase) => { + repay(repayCase, skipTestState, false); + }); withdraw(testData.testCases.withdraw, skipTestState, false); switchApyBlocked(testData.testCases.checkDisabledApy, skipTestState); changeBorrowTypeBlocked(testData.testCases.checkBorrowTypeBlocked, skipTestState); diff --git a/cypress/e2e/1-v3-markets/1-arbitrum-v3-market/0-assets/usdc.arbitrum-v3.cy.ts b/cypress/e2e/1-v3-markets/1-arbitrum-v3-market/0-assets/usdc.arbitrum-v3.cy.ts index 01592b4272..58bdeb7f71 100644 --- a/cypress/e2e/1-v3-markets/1-arbitrum-v3-market/0-assets/usdc.arbitrum-v3.cy.ts +++ b/cypress/e2e/1-v3-markets/1-arbitrum-v3-market/0-assets/usdc.arbitrum-v3.cy.ts @@ -52,12 +52,19 @@ const testData = { hasApproval: false, }, repay: [ + { + asset: assets.arbitrumMarket.USDC, + apyType: constants.apyType.stable, + amount: 2, + hasApproval: false, + repayOption: constants.repayType.collateral, + }, { asset: assets.arbitrumMarket.USDC, apyType: constants.apyType.stable, amount: 2, hasApproval: true, - repayOption: constants.repayType.default, + repayOption: constants.repayType.wallet, }, { asset: assets.arbitrumMarket.USDC, @@ -87,7 +94,7 @@ const testData = { { type: constants.dashboardTypes.borrow, assetName: assets.arbitrumMarket.USDC.shortName, - amount: 46.0, + amount: 44.0, apyType: constants.borrowAPYType.stable, }, ], diff --git a/cypress/e2e/1-v3-markets/2-avalanche-v3-market/0-assets/usdc.avalanche-v3.cy.ts b/cypress/e2e/1-v3-markets/2-avalanche-v3-market/0-assets/usdc.avalanche-v3.cy.ts index eb69809d30..100048498c 100644 --- a/cypress/e2e/1-v3-markets/2-avalanche-v3-market/0-assets/usdc.avalanche-v3.cy.ts +++ b/cypress/e2e/1-v3-markets/2-avalanche-v3-market/0-assets/usdc.avalanche-v3.cy.ts @@ -52,12 +52,19 @@ const testData = { hasApproval: false, }, repay: [ + { + asset: assets.avalancheV3Market.USDC, + apyType: constants.apyType.stable, + amount: 2, + hasApproval: false, + repayOption: constants.repayType.collateral, + }, { asset: assets.avalancheV3Market.USDC, apyType: constants.apyType.stable, amount: 2, hasApproval: true, - repayOption: constants.repayType.default, + repayOption: constants.repayType.wallet, }, { asset: assets.avalancheV3Market.USDC, @@ -87,7 +94,7 @@ const testData = { { type: constants.dashboardTypes.borrow, assetName: assets.avalancheV3Market.USDC.shortName, - amount: 46.0, + amount: 44.0, apyType: constants.borrowAPYType.stable, }, ], diff --git a/cypress/e2e/1-v3-markets/2-avalanche-v3-market/0-assets/usdt.avalacnhe-v3.cy.ts b/cypress/e2e/1-v3-markets/2-avalanche-v3-market/0-assets/usdt.avalacnhe-v3.cy.ts index e9cc302a5a..22bb45e68b 100644 --- a/cypress/e2e/1-v3-markets/2-avalanche-v3-market/0-assets/usdt.avalacnhe-v3.cy.ts +++ b/cypress/e2e/1-v3-markets/2-avalanche-v3-market/0-assets/usdt.avalacnhe-v3.cy.ts @@ -70,6 +70,13 @@ const testData = { hasApproval: true, repayOption: constants.repayType.default, }, + { + asset: assets.avalancheV3Market.USDT, + apyType: constants.apyType.stable, + amount: 2, + hasApproval: false, + repayOption: constants.repayType.collateral, + }, ], withdraw: { asset: assets.avalancheV3Market.USDT, @@ -94,7 +101,7 @@ const testData = { { type: constants.dashboardTypes.borrow, assetName: assets.avalancheV3Market.USDT.shortName, - amount: 16.0, + amount: 14.0, apyType: constants.borrowAPYType.stable, }, ], diff --git a/cypress/e2e/1-v3-markets/3-polygon-v3-market/0-assets/usdc.polygon-v3.cy.ts b/cypress/e2e/1-v3-markets/3-polygon-v3-market/0-assets/usdc.polygon-v3.cy.ts index 279af0965a..7bbfc030ad 100644 --- a/cypress/e2e/1-v3-markets/3-polygon-v3-market/0-assets/usdc.polygon-v3.cy.ts +++ b/cypress/e2e/1-v3-markets/3-polygon-v3-market/0-assets/usdc.polygon-v3.cy.ts @@ -52,12 +52,19 @@ const testData = { hasApproval: false, }, repay: [ + { + asset: assets.polygonV3Market.USDC, + apyType: constants.apyType.stable, + amount: 2, + hasApproval: false, + repayOption: constants.repayType.collateral, + }, { asset: assets.polygonV3Market.USDC, apyType: constants.apyType.stable, amount: 2, hasApproval: true, - repayOption: constants.repayType.default, + repayOption: constants.repayType.wallet, }, { asset: assets.polygonV3Market.USDC, @@ -87,7 +94,7 @@ const testData = { { type: constants.dashboardTypes.borrow, assetName: assets.polygonV3Market.USDC.shortName, - amount: 46.0, + amount: 44.0, apyType: constants.borrowAPYType.stable, }, ], diff --git a/cypress/e2e/1-v3-markets/3-polygon-v3-market/0-assets/usdt.polygon-v3.cy.ts b/cypress/e2e/1-v3-markets/3-polygon-v3-market/0-assets/usdt.polygon-v3.cy.ts index fdce66bf7c..2fd46c4a50 100644 --- a/cypress/e2e/1-v3-markets/3-polygon-v3-market/0-assets/usdt.polygon-v3.cy.ts +++ b/cypress/e2e/1-v3-markets/3-polygon-v3-market/0-assets/usdt.polygon-v3.cy.ts @@ -55,12 +55,19 @@ const testData = { hasApproval: false, }, repay: [ + { + asset: assets.polygonV3Market.USDT, + apyType: constants.apyType.stable, + amount: 2, + hasApproval: false, + repayOption: constants.repayType.collateral, + }, { asset: assets.polygonV3Market.USDT, apyType: constants.apyType.stable, amount: 2, hasApproval: true, - repayOption: constants.repayType.default, + repayOption: constants.repayType.wallet, }, { asset: assets.polygonV3Market.USDT, @@ -94,7 +101,7 @@ const testData = { { type: constants.dashboardTypes.borrow, assetName: assets.polygonV3Market.USDT.shortName, - amount: 46.0, + amount: 44.0, apyType: constants.borrowAPYType.stable, }, ], diff --git a/cypress/e2e/1-v3-markets/3-polygon-v3-market/e-mode.polygon-v3.cy.ts b/cypress/e2e/1-v3-markets/3-polygon-v3-market/e-mode.polygon-v3.cy.ts index 7edac00438..9a87334ece 100644 --- a/cypress/e2e/1-v3-markets/3-polygon-v3-market/e-mode.polygon-v3.cy.ts +++ b/cypress/e2e/1-v3-markets/3-polygon-v3-market/e-mode.polygon-v3.cy.ts @@ -45,7 +45,6 @@ const testData = { assets.polygonV3Market.EURS, assets.polygonV3Market.jEUR, assets.polygonV3Market.agEUR, - assets.polygonV3Market.miMATIC, ], }, }; diff --git a/cypress/e2e/1-v3-markets/4-optimism-v3-market/0-assets/usdc.optimism-v3.cy.ts b/cypress/e2e/1-v3-markets/4-optimism-v3-market/0-assets/usdc.optimism-v3.cy.ts index bb4d57065b..d61c2d7a2a 100644 --- a/cypress/e2e/1-v3-markets/4-optimism-v3-market/0-assets/usdc.optimism-v3.cy.ts +++ b/cypress/e2e/1-v3-markets/4-optimism-v3-market/0-assets/usdc.optimism-v3.cy.ts @@ -52,12 +52,19 @@ const testData = { hasApproval: false, }, repay: [ + { + asset: assets.optimismMarket.USDC, + apyType: constants.apyType.stable, + amount: 2, + hasApproval: false, + repayOption: constants.repayType.collateral, + }, { asset: assets.optimismMarket.USDC, apyType: constants.apyType.stable, amount: 2, hasApproval: true, - repayOption: constants.repayType.default, + repayOption: constants.repayType.wallet, }, { asset: assets.optimismMarket.USDC, @@ -87,7 +94,7 @@ const testData = { { type: constants.dashboardTypes.borrow, assetName: assets.optimismMarket.USDC.shortName, - amount: 46.0, + amount: 44.0, apyType: constants.borrowAPYType.stable, }, ], diff --git a/cypress/e2e/1-v3-markets/4-optimism-v3-market/0-assets/usdt.optimism-v3.cy.ts b/cypress/e2e/1-v3-markets/4-optimism-v3-market/0-assets/usdt.optimism-v3.cy.ts index 29ff2b2a73..067f6f13c6 100644 --- a/cypress/e2e/1-v3-markets/4-optimism-v3-market/0-assets/usdt.optimism-v3.cy.ts +++ b/cypress/e2e/1-v3-markets/4-optimism-v3-market/0-assets/usdt.optimism-v3.cy.ts @@ -55,12 +55,19 @@ const testData = { hasApproval: false, }, repay: [ + { + asset: assets.optimismMarket.USDT, + apyType: constants.apyType.stable, + amount: 2, + hasApproval: false, + repayOption: constants.repayType.collateral, + }, { asset: assets.optimismMarket.USDT, apyType: constants.apyType.stable, amount: 2, hasApproval: true, - repayOption: constants.repayType.default, + repayOption: constants.repayType.wallet, }, { asset: assets.optimismMarket.USDT, @@ -94,7 +101,7 @@ const testData = { { type: constants.dashboardTypes.borrow, assetName: assets.optimismMarket.USDT.shortName, - amount: 46.0, + amount: 44.0, apyType: constants.borrowAPYType.stable, }, ], diff --git a/cypress/e2e/1-v3-markets/5-fantom-v3-market/0-assets/usdc.fantom-v3.cy.ts b/cypress/e2e/1-v3-markets/5-fantom-v3-market/0-assets/usdc.fantom-v3.cy.ts index 216acb955e..156aab5193 100644 --- a/cypress/e2e/1-v3-markets/5-fantom-v3-market/0-assets/usdc.fantom-v3.cy.ts +++ b/cypress/e2e/1-v3-markets/5-fantom-v3-market/0-assets/usdc.fantom-v3.cy.ts @@ -52,12 +52,19 @@ const testData = { hasApproval: false, }, repay: [ + { + asset: assets.fantomMarket.USDC, + apyType: constants.apyType.stable, + amount: 2, + hasApproval: false, + repayOption: constants.repayType.collateral, + }, { asset: assets.fantomMarket.USDC, apyType: constants.apyType.stable, amount: 2, hasApproval: true, - repayOption: constants.repayType.default, + repayOption: constants.repayType.wallet, }, { asset: assets.fantomMarket.USDC, @@ -87,7 +94,7 @@ const testData = { { type: constants.dashboardTypes.borrow, assetName: assets.fantomMarket.USDC.shortName, - amount: 46.0, + amount: 44.0, apyType: constants.borrowAPYType.stable, }, ], diff --git a/cypress/support/steps/main.steps.ts b/cypress/support/steps/main.steps.ts index 24a72b0839..fb9e99e6c6 100644 --- a/cypress/support/steps/main.steps.ts +++ b/cypress/support/steps/main.steps.ts @@ -176,6 +176,7 @@ export const repay = ( repayOption, hasApproval = false, repayableAsset, + assetForCollateralRepay, isMaxAmount = false, }: { asset: { shortName: string; fullName: string }; @@ -184,6 +185,7 @@ export const repay = ( repayOption: string; hasApproval: boolean; repayableAsset?: { shortName: string }; + assetForCollateralRepay?: { shortName: string }; isMaxAmount?: boolean; }, skip: SkipType, @@ -192,8 +194,15 @@ export const repay = ( const _shortName = asset.shortName; const _actionName = constants.actionTypes.repay; - return describe(`Repay by ${repayOption} process for ${_shortName} by ${ - repayableAsset ? repayableAsset.shortName : _shortName + return describe(`Repay by ${repayOption} process for ${_shortName} by + ${ + repayOption == constants.repayType.collateral + ? assetForCollateralRepay + ? assetForCollateralRepay.shortName + : 'default asset' + : repayableAsset + ? repayableAsset.shortName + : _shortName }`, () => { skipSetup({ skip, updateSkipStatus }); it(`Open ${_shortName} repay popup view`, () => { diff --git a/package.json b/package.json index 168e999951..379585020f 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "@lingui/react": "^3.14.0", "@mui/icons-material": "^5.10.6", "@mui/material": "^5.10.9", - "@paraswap/sdk": "5.6.0-alpha.3", + "@paraswap/sdk": "^6.1.0", "@visx/axis": "^2.14.0", "@visx/curve": "^2.1.0", "@visx/event": "^2.6.0", diff --git a/public/icons/other/paraswap.svg b/public/icons/other/paraswap.svg new file mode 100644 index 0000000000..a724bb22ce --- /dev/null +++ b/public/icons/other/paraswap.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/components/infoTooltips/PriceImpactTooltip.tsx b/src/components/infoTooltips/PriceImpactTooltip.tsx new file mode 100644 index 0000000000..d0af452109 --- /dev/null +++ b/src/components/infoTooltips/PriceImpactTooltip.tsx @@ -0,0 +1,49 @@ +import { Trans } from '@lingui/macro'; +import { Box, Skeleton } from '@mui/material'; + +import { FormattedNumber } from '../primitives/FormattedNumber'; +import { TextWithTooltip } from '../TextWithTooltip'; + +interface PriceImpactTooltipProps { + loading: boolean; + priceImpact: string; +} + +export const PriceImpactTooltip = ({ loading, priceImpact }: PriceImpactTooltipProps) => { + return ( + + + Price impact{' '} + {loading ? ( + + ) : ( + + )} + % + + + } + > + + 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. + + + ); +}; diff --git a/src/components/infoTooltips/SlippageTooltip.tsx b/src/components/infoTooltips/SlippageTooltip.tsx new file mode 100644 index 0000000000..76ba3d73d0 --- /dev/null +++ b/src/components/infoTooltips/SlippageTooltip.tsx @@ -0,0 +1,14 @@ +import { Trans } from '@lingui/macro'; + +import { TextWithTooltip, TextWithTooltipProps } from '../TextWithTooltip'; + +export const SlippageTooltip = ({ ...rest }: TextWithTooltipProps) => { + return ( + + + Slippage is the difference between the quoted and received amounts from changing market + conditions between the moment the transaction is submitted and its verification. + + + ); +}; diff --git a/src/components/transactions/AssetInput.tsx b/src/components/transactions/AssetInput.tsx index f2c7620c3c..aaa4fdb9d5 100644 --- a/src/components/transactions/AssetInput.tsx +++ b/src/components/transactions/AssetInput.tsx @@ -3,6 +3,7 @@ import { Trans } from '@lingui/macro'; import { Box, Button, + CircularProgress, FormControl, IconButton, InputBase, @@ -74,7 +75,8 @@ export interface AssetInputProps { maxValue?: string; isMaxSelected?: boolean; inputTitle?: ReactNode; - balanceText?: ReactNode; // Support translated text + balanceText?: ReactNode; + loading?: boolean; } export const AssetInput = ({ @@ -91,6 +93,7 @@ export const AssetInput = ({ isMaxSelected, inputTitle, balanceText, + loading = false, }: AssetInputProps) => { const handleSelect = (event: SelectChangeEvent) => { const newAsset = assets.find((asset) => asset.symbol === event.target.value) as T; @@ -121,35 +124,41 @@ export const AssetInput = ({ })} > - { - if (!onChange) return; - if (Number(e.target.value) > Number(maxValue)) { - onChange('-1'); - } else { - onChange(e.target.value); - } - }} - inputProps={{ - 'aria-label': 'amount input', - style: { - fontSize: '21px', - lineHeight: '28,01px', - padding: 0, - height: '28px', - textOverflow: 'ellipsis', - whiteSpace: 'nowrap', - overflow: 'hidden', - }, - }} - // eslint-disable-next-line - inputComponent={NumberFormatCustom as any} - /> + {loading ? ( + + + + ) : ( + { + if (!onChange) return; + if (Number(e.target.value) > Number(maxValue)) { + onChange('-1'); + } else { + onChange(e.target.value); + } + }} + inputProps={{ + 'aria-label': 'amount input', + style: { + fontSize: '21px', + lineHeight: '28,01px', + padding: 0, + height: '28px', + textOverflow: 'ellipsis', + whiteSpace: 'nowrap', + overflow: 'hidden', + }, + }} + // eslint-disable-next-line + inputComponent={NumberFormatCustom as any} + /> + )} {value !== '' && !disableInput && ( ({ '&.AssetInput__select .MuiOutlinedInput-notchedOutline': { display: 'none' }, '&.AssetInput__select .MuiSelect-icon': { color: 'text.primary', + right: '0%', }, }} renderValue={(symbol) => { @@ -245,15 +255,19 @@ export const AssetInput = ({ - + {loading ? ( + + ) : ( + + )} {asset.balance && onChange && ( <> @@ -267,14 +281,16 @@ export const AssetInput = ({ symbolsColor="text.disabled" /> - + {!disableInput && ( + + )} )} diff --git a/src/components/transactions/Borrow/BorrowModalContent.tsx b/src/components/transactions/Borrow/BorrowModalContent.tsx index 6dd39395f2..99fd5bfd0f 100644 --- a/src/components/transactions/Borrow/BorrowModalContent.tsx +++ b/src/components/transactions/Borrow/BorrowModalContent.tsx @@ -74,7 +74,7 @@ const BorrowModeSwitch = ({ value={interestRateMode} exclusive onChange={(_, value) => setInterestRateMode(value)} - sx={{ width: '100%', mt: 0.5 }} + sx={{ width: '100%', height: '36px', p: '2px', mt: 0.5 }} > = ({ gasLimit, children }) => { +export const TxModalDetails: React.FC = ({ + gasLimit, + slippageSelector, + children, +}) => { return ( @@ -37,8 +42,10 @@ export const TxModalDetails: React.FC = ({ gasLimit, childr > {children} - - + + + {slippageSelector} + ); }; @@ -49,6 +56,7 @@ interface DetailsNumberLineProps extends FormattedNumberProps { futureValue?: FormattedNumberProps['value']; numberPrefix?: ReactNode; iconSymbol?: string; + loading?: boolean; } export const DetailsNumberLine = ({ @@ -57,20 +65,27 @@ export const DetailsNumberLine = ({ futureValue, numberPrefix, iconSymbol, + loading = false, ...rest }: DetailsNumberLineProps) => { return ( - {iconSymbol && } - {numberPrefix && {numberPrefix}} - - {futureValue && ( + {loading ? ( + + ) : ( <> - - - - + {iconSymbol && } + {numberPrefix && {numberPrefix}} + + {futureValue && ( + <> + + + + + + )} )} @@ -87,6 +102,8 @@ interface DetailsNumberLineWithSubProps { futureValueUSD: string; hideSymbolSuffix?: boolean; color?: string; + tokenIcon?: string; + loading?: boolean; } export const DetailsNumberLineWithSub = ({ @@ -98,42 +115,58 @@ export const DetailsNumberLineWithSub = ({ futureValueUSD, hideSymbolSuffix, color, + tokenIcon, + loading = false, }: DetailsNumberLineWithSubProps) => { return ( - - {value && ( - <> - - {!hideSymbolSuffix && ( - - {symbol} - - )} - - - - - )} - - {!hideSymbolSuffix && ( - - {symbol} - - )} - - - {valueUSD && ( - <> - - - - - - )} - - + {loading ? ( + + ) : ( + + {value && ( + <> + + {!hideSymbolSuffix && ( + + {symbol} + + )} + + + + + )} + {tokenIcon && } + + {!hideSymbolSuffix && ( + + {symbol} + + )} + + )} + {loading ? ( + + ) : ( + + {valueUSD && ( + <> + + + + + + )} + + + )} ); @@ -198,6 +231,7 @@ interface DetailsIncentivesLineProps { incentives?: ReserveIncentiveResponse[]; // the token yielding the incentive, not the incentive itself symbol: string; + loading?: boolean; } export const DetailsIncentivesLine = ({ @@ -205,19 +239,33 @@ export const DetailsIncentivesLine = ({ symbol, futureIncentives, futureSymbol, + loading = false, }: DetailsIncentivesLineProps) => { if (!incentives || incentives.filter((i) => i.incentiveAPR !== '0').length === 0) return null; return ( Rewards APR} captionVariant="description" mb={4} minHeight={24}> - - {futureSymbol && ( - <> - - - - - - )} + + {loading ? ( + + ) : ( + <> + + {futureSymbol && ( + <> + + + + + {futureIncentives && futureIncentives.length === 0 && ( + + None + + )} + + )} + + )} + ); }; @@ -226,12 +274,14 @@ export interface DetailsHFLineProps { healthFactor: string; futureHealthFactor: string; visibleHfChange: boolean; + loading?: boolean; } export const DetailsHFLine = ({ healthFactor, futureHealthFactor, visibleHfChange, + loading = false, }: DetailsHFLineProps) => { if (healthFactor === '-1' && futureHealthFactor === '-1') return null; return ( @@ -243,18 +293,24 @@ export const DetailsHFLine = ({ > - - - {visibleHfChange && ( + {loading ? ( + + ) : ( <> - - - + + + {visibleHfChange && ( + <> + + + - + + + )} )} diff --git a/src/components/transactions/Repay/CollateralRepayActions.tsx b/src/components/transactions/Repay/CollateralRepayActions.tsx index f7fdd6e181..ed1e71fdd5 100644 --- a/src/components/transactions/Repay/CollateralRepayActions.tsx +++ b/src/components/transactions/Repay/CollateralRepayActions.tsx @@ -1,14 +1,19 @@ -import { InterestRate } from '@aave/contract-helpers'; +import { + API_ETH_MOCK_ADDRESS, + gasLimitRecommendations, + InterestRate, + ProtocolAction, +} from '@aave/contract-helpers'; import { Trans } from '@lingui/macro'; import { BoxProps } from '@mui/material'; -import { OptimalRate } from 'paraswap-core'; -import { useTransactionHandler } from 'src/helpers/useTransactionHandler'; +import { useParaSwapTransactionHandler } from 'src/helpers/useParaSwapTransactionHandler'; import { ComputedReserveData } from 'src/hooks/app-data-provider/useAppDataProvider'; +import { SwapTransactionParams } from 'src/hooks/paraswap/common'; import { useRootStore } from 'src/store/root'; import { TxActionsWrapper } from '../TxActionsWrapper'; -export interface RepayActionProps extends BoxProps { +interface CollateralRepayBaseProps extends BoxProps { rateMode: InterestRate; repayAmount: string; repayWithAmount: string; @@ -17,65 +22,79 @@ export interface RepayActionProps extends BoxProps { isWrongNetwork: boolean; customGasPrice?: string; symbol: string; - priceRoute: OptimalRate | null; repayAllDebt: boolean; useFlashLoan: boolean; blocked: boolean; - maxSlippage: number; + loading?: boolean; +} + +// Used in poolSlice +export interface CollateralRepayActionProps extends CollateralRepayBaseProps { + augustus: string; + swapCallData: string; } export const CollateralRepayActions = ({ repayAmount, - repayWithAmount, poolReserve, fromAssetData, isWrongNetwork, sx, symbol, rateMode, - priceRoute, repayAllDebt, useFlashLoan, blocked, - maxSlippage, + loading, + repayWithAmount, + buildTxFn, ...props -}: RepayActionProps) => { +}: CollateralRepayBaseProps & { buildTxFn: () => Promise }) => { const paraswapRepayWithCollateral = useRootStore((state) => state.paraswapRepayWithCollateral); const { approval, action, requiresApproval, loadingTxns, approvalTxState, mainTxState } = - useTransactionHandler({ + useParaSwapTransactionHandler({ handleGetTxns: async () => { + const route = await buildTxFn(); + return paraswapRepayWithCollateral({ + repayAllDebt, + repayAmount: route.outputAmount, + rateMode, + repayWithAmount: route.inputAmount, + fromAssetData, + poolReserve, + isWrongNetwork, + symbol, + useFlashLoan, + blocked, + swapCallData: route.swapCallData, + augustus: route.augustus, + }); + }, + handleGetApprovalTxns: async () => { return paraswapRepayWithCollateral({ repayAllDebt, repayAmount, - maxSlippage, rateMode, repayWithAmount, fromAssetData, poolReserve, isWrongNetwork, symbol, - priceRoute, useFlashLoan, blocked, + swapCallData: '0x', + augustus: API_ETH_MOCK_ADDRESS, }); }, - skip: !repayAmount || parseFloat(repayAmount) === 0 || blocked, - deps: [ - repayWithAmount, - repayAmount, - priceRoute, - poolReserve.underlyingAsset, - fromAssetData.underlyingAsset, - repayAllDebt, - useFlashLoan, - ], + gasLimitRecommendation: gasLimitRecommendations[ProtocolAction.repayCollateral].limit, + skip: loading || !repayAmount || parseFloat(repayAmount) === 0 || blocked, }); return ( approval()} actionText={Repay {symbol}} actionInProgressText={Repaying {symbol}} + fetchingData={loading} + errorParams={{ + loading: false, + disabled: blocked, + content: Repay {symbol}, + handleClick: action, + }} /> ); }; diff --git a/src/components/transactions/Repay/CollateralRepayModalContent.tsx b/src/components/transactions/Repay/CollateralRepayModalContent.tsx index 35f40899fe..b9cd6a1f0f 100644 --- a/src/components/transactions/Repay/CollateralRepayModalContent.tsx +++ b/src/components/transactions/Repay/CollateralRepayModalContent.tsx @@ -1,22 +1,22 @@ import { InterestRate } from '@aave/contract-helpers'; -import { USD_DECIMALS, valueToBigNumber } from '@aave/math-utils'; +import { valueToBigNumber } from '@aave/math-utils'; +import { ArrowDownIcon } from '@heroicons/react/outline'; import { Trans } from '@lingui/macro'; -import { Box, Typography } from '@mui/material'; +import { Box, SvgIcon, Typography } from '@mui/material'; import BigNumber from 'bignumber.js'; import { useRef, useState } from 'react'; -import { FormattedNumber } from 'src/components/primitives/FormattedNumber'; -import { Row } from 'src/components/primitives/Row'; -import StyledToggleButton from 'src/components/StyledToggleButton'; -import StyledToggleButtonGroup from 'src/components/StyledToggleButtonGroup'; +import { PriceImpactTooltip } from 'src/components/infoTooltips/PriceImpactTooltip'; import { ComputedReserveData, ComputedUserReserveData, useAppDataContext, } from 'src/hooks/app-data-provider/useAppDataProvider'; +import { SwapVariant } from 'src/hooks/paraswap/common'; +import { useCollateralRepaySwap } from 'src/hooks/paraswap/useCollateralRepaySwap'; import { useModalContext } from 'src/hooks/useModal'; import { useProtocolDataContext } from 'src/hooks/useProtocolDataContext'; -import { useSwap } from 'src/hooks/useSwap'; import { useWeb3Context } from 'src/libs/hooks/useWeb3Context'; +import { ListSlippageButton } from 'src/modules/dashboard/lists/SlippageList'; import { calculateHFAfterRepay } from 'src/utils/hfUtils'; import { Asset, AssetInput } from '../AssetInput'; @@ -38,11 +38,12 @@ export function CollateralRepayModalContent({ userReserve, isWrongNetwork, }: ModalWrapperProps & { debtType: InterestRate }) { - const { user, marketReferencePriceInUsd, reserves, userReserves } = useAppDataContext(); + const { user, reserves, userReserves } = useAppDataContext(); const { gasLimit, txError, mainTxState } = useModalContext(); const { currentChainId, currentNetworkConfig } = useProtocolDataContext(); const { currentAccount } = useWeb3Context(); + // List of tokens eligble to repay with, ordered by USD value const repayTokens = user.userReservesData .filter( (userReserve) => @@ -52,69 +53,104 @@ export function CollateralRepayModalContent({ .map((userReserve) => ({ address: userReserve.underlyingAsset, balance: userReserve.underlyingBalance, + balanceUSD: userReserve.underlyingBalanceUSD, symbol: userReserve.reserve.symbol, iconSymbol: userReserve.reserve.iconSymbol, - aToken: true, - })); + })) + .sort((a, b) => Number(b.balanceUSD) - Number(a.balanceUSD)); const [tokenToRepayWith, setTokenToRepayWith] = useState(repayTokens[0]); + const tokenToRepayWithBalance = tokenToRepayWith.balance || '0'; - const fromAssetData = reserves.find( - (reserve) => reserve.underlyingAsset === tokenToRepayWith.address - ) as ComputedReserveData; - - const repayWithUserReserve = userReserves.find( - (userReserve) => userReserve.underlyingAsset === tokenToRepayWith.address - ) as ComputedUserReserveData; - - const [_amount, setAmount] = useState(''); + const [swapVariant, setSwapVariant] = useState('exactOut'); + const [amount, setAmount] = useState(''); const [maxSlippage, setMaxSlippage] = useState('0.5'); const amountRef = useRef(''); + const collateralReserveData = reserves.find( + (reserve) => reserve.underlyingAsset === tokenToRepayWith.address + ) as ComputedReserveData; + const debt = debtType === InterestRate.Stable ? userReserve?.stableBorrows || '0' : userReserve?.variableBorrows || '0'; const safeAmountToRepayAll = valueToBigNumber(debt).multipliedBy('1.0025'); - const isMaxSelected = _amount === '-1'; - const amount = isMaxSelected ? safeAmountToRepayAll.toString() : _amount; - const usdValue = valueToBigNumber(amount).multipliedBy(poolReserve.priceInUSD); + const isMaxSelected = amount === '-1'; + const repayAmount = isMaxSelected ? safeAmountToRepayAll.toString() : amount; + const repayAmountUsdValue = valueToBigNumber(repayAmount) + .multipliedBy(poolReserve.priceInUSD) + .toString(); + + // The slippage is factored into the collateral amount because when we swap for 'exactOut', positive slippage is applied on the collateral amount. + const collateralAmountRequiredToCoverDebt = safeAmountToRepayAll + .multipliedBy(poolReserve.priceInUSD) + .multipliedBy(100 + Number(maxSlippage)) + .dividedBy(100) + .dividedBy(collateralReserveData.priceInUSD); - const { priceRoute, inputAmountUSD, inputAmount, outputAmount, outputAmountUSD } = useSwap({ + const swapIn = { ...collateralReserveData, amount: tokenToRepayWithBalance }; + const swapOut = { ...poolReserve, amount: amountRef.current }; + if (swapVariant === 'exactIn') { + swapIn.amount = tokenToRepayWithBalance; + swapOut.amount = '0'; + } + + const repayAllDebt = + isMaxSelected && + valueToBigNumber(tokenToRepayWithBalance).gte(collateralAmountRequiredToCoverDebt); + + const { + inputAmountUSD, + inputAmount, + outputAmount, + outputAmountUSD, + loading: routeLoading, + error, + buildTxFn, + } = useCollateralRepaySwap({ chainId: currentNetworkConfig.underlyingChainId || currentChainId, - userId: currentAccount, - variant: 'exactOut', - swapIn: { ...fromAssetData, amount: '0' }, - swapOut: { ...poolReserve, amount: amountRef.current }, - max: isMaxSelected, - skip: mainTxState.loading, + userAddress: currentAccount, + swapVariant: swapVariant, + swapIn, + swapOut, + max: repayAllDebt, + skip: mainTxState.loading || false, + maxSlippage: Number(maxSlippage), }); - // Calculations to get the max repayable debt depending on the balance and value of the - // selected collateral - const maxCollateral = valueToBigNumber(tokenToRepayWith?.balance || 0).multipliedBy( - fromAssetData.priceInMarketReferenceCurrency - ); - const maxDebtThatCanBeRepaidWithSelectedCollateral = maxCollateral.dividedBy( - poolReserve.priceInMarketReferenceCurrency - ); - const maxRepayableDebt = BigNumber.min( - maxDebtThatCanBeRepaidWithSelectedCollateral, - safeAmountToRepayAll - ); - const handleChange = (value: string) => { + const loadingSkeleton = routeLoading && inputAmountUSD === '0'; + + const handleRepayAmountChange = (value: string) => { const maxSelected = value === '-1'; - amountRef.current = maxSelected ? maxRepayableDebt.toString(10) : value; - setAmount(value); + + if ( + maxSelected && + valueToBigNumber(tokenToRepayWithBalance).lt(collateralAmountRequiredToCoverDebt) + ) { + // The selected collateral amount is not enough to pay the full debt. We'll try to do a swap using the exact amount of collateral. + // The amount won't be known until we fetch the swap data, so we'll clear it out. Once the swap data is fetched, we'll set the amount. + amountRef.current = ''; + setAmount(''); + setSwapVariant('exactIn'); + } else { + amountRef.current = maxSelected ? safeAmountToRepayAll.toString(10) : value; + setAmount(value); + setSwapVariant('exactOut'); + } }; + // for v3 we need hf after withdraw collateral, because when removing collateral to repay // debt, hf could go under 1 then it would fail. If that is the case then we need // to use flashloan path + const repayWithUserReserve = userReserves.find( + (userReserve) => userReserve.underlyingAsset === tokenToRepayWith.address + ) as ComputedUserReserveData; const { hfAfterSwap, hfEffectOfFromAmount } = calculateHFAfterRepay({ amountToReceiveAfterSwap: outputAmount, amountToSwap: inputAmount, - fromAssetData, + fromAssetData: collateralReserveData, user, toAssetData: poolReserve, repayWithUserReserve, @@ -134,24 +170,26 @@ export function CollateralRepayModalContent({ // a safe amount to repay all. When this happens amountAfterRepay would be < 0 and // this would show as certain amount left to repay when we are actually repaying all debt const amountAfterRepay = valueToBigNumber(debt).minus(BigNumber.min(outputAmount, debt)); - const displayAmountAfterRepayInUsd = amountAfterRepay - .multipliedBy(poolReserve.formattedPriceInMarketReferenceCurrency) - .multipliedBy(marketReferencePriceInUsd) - .shiftedBy(-USD_DECIMALS); + const displayAmountAfterRepayInUsd = amountAfterRepay.multipliedBy(poolReserve.priceInUSD); + const collateralAmountAfterRepay = tokenToRepayWithBalance + ? valueToBigNumber(tokenToRepayWithBalance).minus(inputAmount) + : valueToBigNumber('0'); + const collateralAmountAfterRepayUSD = collateralAmountAfterRepay.multipliedBy( + collateralReserveData.priceInUSD + ); // calculate impact based on $ difference - const priceImpact = + let priceImpact = outputAmountUSD && outputAmountUSD !== '0' - ? new BigNumber(1) - .minus(new BigNumber(inputAmountUSD).dividedBy(outputAmountUSD)) - .toString(10) + ? new BigNumber(1).minus(new BigNumber(inputAmountUSD).dividedBy(outputAmountUSD)).toFixed(2) : '0'; + if (priceImpact === '-0.00') { + priceImpact = '0.00'; + } let blockingError: ErrorType | undefined = undefined; - const tokenToRepayWithUsdValue = valueToBigNumber(tokenToRepayWith?.balance || '0').multipliedBy( - fromAssetData.priceInUSD - ); - if (Number(usdValue) > Number(tokenToRepayWithUsdValue.toString(10))) { + + if (valueToBigNumber(tokenToRepayWithBalance).lt(inputAmount)) { blockingError = ErrorType.NOT_ENOUGH_COLLATERAL_TO_REPAY_WITH; } else if (disableFlashLoan) { blockingError = ErrorType.FLASH_LOAN_NOT_AVAILABLE; @@ -176,18 +214,17 @@ export function CollateralRepayModalContent({ if (mainTxState.success) return ( repaid} - amount={amountRef.current} + action={Repaid} + amount={swapVariant === 'exactIn' ? outputAmount : repayAmount} symbol={poolReserve.symbol} /> ); - return ( <> Debt amount to repay} + inputTitle={Expected amount to repay} balanceText={Borrow balance} /> + + + + + + + Collateral amount to repay with} + onChange={handleRepayAmountChange} + inputTitle={Collateral to repay with} balanceText={Borrow balance} + maxValue={tokenToRepayWithBalance} + loading={loadingSkeleton} disableInput /> + {error && !loadingSkeleton && ( + + {error} + + )} {blockingError !== undefined && ( {handleBlocked()} )} - + } > - Price impact} captionVariant="subheader1"> - - - Minimum received} captionVariant="subheader1" sx={{ mt: 4 }}> - - - - Max slippage rate - - setMaxSlippage(value)} - exclusive - > - - 0.1% - - - 0.5% - - - 1% - - - - + Remaining debt} + description={Borrow balance after repay} futureValue={amountAfterRepay.toString()} futureValueUSD={displayAmountAfterRepayInUsd.toString()} symbol={symbol} + tokenIcon={poolReserve.iconSymbol} + loading={loadingSkeleton} + hideSymbolSuffix /> - Collateral balance after repay} + futureValue={collateralAmountAfterRepay.toString()} + futureValueUSD={collateralAmountAfterRepayUSD.toString()} + symbol={tokenToRepayWith.symbol} + tokenIcon={tokenToRepayWith.iconSymbol} + loading={loadingSkeleton} + hideSymbolSuffix /> @@ -270,17 +306,17 @@ export function CollateralRepayModalContent({ ); diff --git a/src/components/transactions/Repay/RepayModal.tsx b/src/components/transactions/Repay/RepayModal.tsx index 782cc23e7d..5ebaf5f3db 100644 --- a/src/components/transactions/Repay/RepayModal.tsx +++ b/src/components/transactions/Repay/RepayModal.tsx @@ -16,6 +16,7 @@ export const RepayModal = () => { const { type, close, args, mainTxState } = useModalContext() as ModalContextType<{ underlyingAsset: string; currentRateMode: InterestRate; + isFrozen: boolean; }>; const { userReserves } = useAppDataContext(); const { currentMarketData } = useProtocolDataContext(); @@ -25,12 +26,14 @@ export const RepayModal = () => { // 1. on chains with paraswap deployed // 2. when you have a different supplied(not necessarily collateral) asset then the one your debt is in // For repaying your debt with the same assets aToken you can use repayWithAToken on aave protocol v3 + // 3. the supplied asset is not frozen const collateralRepayPossible = isFeatureEnabled.collateralRepay(currentMarketData) && userReserves.some( (userReserve) => userReserve.scaledATokenBalance !== '0' && - userReserve.underlyingAsset !== args.underlyingAsset + userReserve.underlyingAsset !== args.underlyingAsset && + !args.isFrozen ); return ( diff --git a/src/components/transactions/Repay/RepayModalContent.tsx b/src/components/transactions/Repay/RepayModalContent.tsx index 01f0c27e5f..58abfc4152 100644 --- a/src/components/transactions/Repay/RepayModalContent.tsx +++ b/src/components/transactions/Repay/RepayModalContent.tsx @@ -171,13 +171,12 @@ export const RepayModalContent = ({ const amountAfterRepay = valueToBigNumber(debt) .minus(amount || '0') .toString(10); - const displayAmountAfterRepay = BigNumber.min(amountAfterRepay, maxAmountToRepay); - const displayAmountAfterRepayInUsd = displayAmountAfterRepay + const amountAfterRepayInUsd = new BigNumber(amountAfterRepay) .multipliedBy(poolReserve.formattedPriceInMarketReferenceCurrency) .multipliedBy(marketReferencePriceInUsd) .shiftedBy(-USD_DECIMALS); - const maxRepayWithDustRemaining = isMaxSelected && displayAmountAfterRepayInUsd.toNumber() > 0; + const maxRepayWithDustRemaining = isMaxSelected && amountAfterRepayInUsd.toNumber() > 0; // health factor calculations // we use usd values instead of MarketreferenceCurrency so it has same precision @@ -236,7 +235,7 @@ export const RepayModalContent = ({ Remaining debt} futureValue={amountAfterRepay} - futureValueUSD={displayAmountAfterRepayInUsd.toString(10)} + futureValueUSD={amountAfterRepayInUsd.toString(10)} value={debt} valueUSD={debtUSD.toString()} symbol={ diff --git a/src/components/transactions/Repay/RepayTypeSelector.tsx b/src/components/transactions/Repay/RepayTypeSelector.tsx index fb573c6f24..97981ea306 100644 --- a/src/components/transactions/Repay/RepayTypeSelector.tsx +++ b/src/components/transactions/Repay/RepayTypeSelector.tsx @@ -28,7 +28,7 @@ export function RepayTypeSelector({ value={repayType} exclusive onChange={(_, value) => setRepayType(value)} - sx={{ width: '100%' }} + sx={{ width: '100%', height: '36px', p: '2px' }} > diff --git a/src/components/transactions/Swap/SwapActions.tsx b/src/components/transactions/Swap/SwapActions.tsx index 9a9fab1913..6f30b187c8 100644 --- a/src/components/transactions/Swap/SwapActions.tsx +++ b/src/components/transactions/Swap/SwapActions.tsx @@ -1,13 +1,18 @@ +import { + API_ETH_MOCK_ADDRESS, + gasLimitRecommendations, + ProtocolAction, +} from '@aave/contract-helpers'; import { Trans } from '@lingui/macro'; import { BoxProps } from '@mui/material'; -import { OptimalRate } from 'paraswap-core'; +import { useParaSwapTransactionHandler } from 'src/helpers/useParaSwapTransactionHandler'; import { ComputedReserveData } from 'src/hooks/app-data-provider/useAppDataProvider'; +import { SwapTransactionParams } from 'src/hooks/paraswap/common'; import { useRootStore } from 'src/store/root'; -import { useTransactionHandler } from '../../../helpers/useTransactionHandler'; import { TxActionsWrapper } from '../TxActionsWrapper'; -export interface SwapActionProps extends BoxProps { +interface SwapBaseProps extends BoxProps { amountToSwap: string; amountToReceive: string; poolReserve: ComputedReserveData; @@ -16,9 +21,14 @@ export interface SwapActionProps extends BoxProps { customGasPrice?: string; symbol: string; blocked: boolean; - priceRoute: OptimalRate | null; isMaxSelected: boolean; useFlashLoan: boolean; + loading?: boolean; +} + +export interface SwapActionProps extends SwapBaseProps { + swapCallData: string; + augustus: string; } export const SwapActions = ({ @@ -28,18 +38,35 @@ export const SwapActions = ({ sx, poolReserve, targetReserve, - priceRoute, isMaxSelected, useFlashLoan, + loading, symbol, blocked, + buildTxFn, ...props -}: SwapActionProps) => { +}: SwapBaseProps & { buildTxFn: () => Promise }) => { const swapCollateral = useRootStore((state) => state.swapCollateral); const { approval, action, requiresApproval, approvalTxState, mainTxState, loadingTxns } = - useTransactionHandler({ + useParaSwapTransactionHandler({ handleGetTxns: async () => { + const route = await buildTxFn(); + return swapCollateral({ + amountToSwap: route.inputAmount, + amountToReceive: route.outputAmount, + poolReserve, + targetReserve, + isWrongNetwork, + symbol, + blocked, + isMaxSelected, + useFlashLoan, + swapCallData: route.swapCallData, + augustus: route.augustus, + }); + }, + handleGetApprovalTxns: async () => { return swapCollateral({ amountToSwap, amountToReceive, @@ -48,21 +75,14 @@ export const SwapActions = ({ isWrongNetwork, symbol, blocked, - priceRoute, isMaxSelected, useFlashLoan, + swapCallData: '0x', + augustus: API_ETH_MOCK_ADDRESS, }); }, - skip: !priceRoute || !amountToSwap || parseFloat(amountToSwap) === 0, - deps: [ - amountToSwap, - amountToReceive, - priceRoute, - poolReserve.underlyingAsset, - targetReserve.underlyingAsset, - isMaxSelected, - useFlashLoan, - ], + gasLimitRecommendation: gasLimitRecommendations[ProtocolAction.swapCollateral].limit, + skip: loading || !amountToSwap || parseFloat(amountToSwap) === 0, }); return ( @@ -74,11 +94,18 @@ export const SwapActions = ({ handleAction={action} requiresAmount amount={amountToSwap} - handleApproval={() => approval(amountToSwap, poolReserve.aTokenAddress)} + handleApproval={() => approval()} requiresApproval={requiresApproval} actionText={Swap} actionInProgressText={Swapping} sx={sx} + fetchingData={loading} + errorParams={{ + loading: false, + disabled: blocked, + content: Swap, + handleClick: action, + }} {...props} /> ); diff --git a/src/components/transactions/Swap/SwapModalContent.tsx b/src/components/transactions/Swap/SwapModalContent.tsx index fe628778ed..b7516d4ca9 100644 --- a/src/components/transactions/Swap/SwapModalContent.tsx +++ b/src/components/transactions/Swap/SwapModalContent.tsx @@ -1,34 +1,29 @@ +import { SwitchVerticalIcon } from '@heroicons/react/outline'; import { Trans } from '@lingui/macro'; -import { Box, Typography } from '@mui/material'; +import { Box, SvgIcon, Typography } from '@mui/material'; import BigNumber from 'bignumber.js'; import React, { useRef, useState } from 'react'; -import { FormattedNumber } from 'src/components/primitives/FormattedNumber'; -import { Row } from 'src/components/primitives/Row'; -import StyledToggleButton from 'src/components/StyledToggleButton'; -import StyledToggleButtonGroup from 'src/components/StyledToggleButtonGroup'; +import { PriceImpactTooltip } from 'src/components/infoTooltips/PriceImpactTooltip'; import { Asset, AssetInput } from 'src/components/transactions/AssetInput'; import { GasEstimationError } from 'src/components/transactions/FlowCommons/GasEstimationError'; -import { - DetailsHFLine, - DetailsIncentivesLine, - DetailsNumberLine, - TxModalDetails, -} from 'src/components/transactions/FlowCommons/TxModalDetails'; +import { TxModalDetails } from 'src/components/transactions/FlowCommons/TxModalDetails'; +import { useCollateralSwap } from 'src/hooks/paraswap/useCollateralSwap'; import { useModalContext } from 'src/hooks/useModal'; import { useProtocolDataContext } from 'src/hooks/useProtocolDataContext'; -import { useSwap } from 'src/hooks/useSwap'; import { useWeb3Context } from 'src/libs/hooks/useWeb3Context'; +import { ListSlippageButton } from 'src/modules/dashboard/lists/SlippageList'; import { remainingCap } from 'src/utils/getMaxAmountAvailableToSupply'; import { calculateHFAfterSwap } from 'src/utils/hfUtils'; import { - ComputedReserveData, + ComputedUserReserveData, useAppDataContext, } from '../../../hooks/app-data-provider/useAppDataProvider'; import { ModalWrapperProps } from '../FlowCommons/ModalWrapper'; import { TxSuccessView } from '../FlowCommons/Success'; import { ErrorType, flashLoanNotAvailable, useFlashloan } from '../utils'; import { SwapActions } from './SwapActions'; +import { SwapModalDetails } from './SwapModalDetails'; export type SupplyProps = { underlyingAsset: string; @@ -58,9 +53,9 @@ export const SwapModalContent = ({ const [targetReserve, setTargetReserve] = useState(swapTargets[0]); const [maxSlippage, setMaxSlippage] = useState('0.1'); - const swapTarget = reserves.find( + const swapTarget = user.userReservesData.find( (r) => r.underlyingAsset === targetReserve.address - ) as ComputedReserveData; + ) as ComputedUserReserveData; // a user can never swap more then 100% of available as the txn would fail on withdraw step const maxAmountToSwap = BigNumber.min( @@ -68,26 +63,30 @@ export const SwapModalContent = ({ new BigNumber(poolReserve.availableLiquidity).multipliedBy(0.99) ).toString(10); - const remainingCapBn = remainingCap(swapTarget); + const remainingCapBn = remainingCap(swapTarget.reserve); const isMaxSelected = _amount === '-1'; const amount = isMaxSelected ? maxAmountToSwap : _amount; - const { priceRoute, inputAmountUSD, inputAmount, outputAmount, outputAmountUSD, error } = useSwap( - { - chainId: currentNetworkConfig.underlyingChainId || currentChainId, - userId: currentAccount, - variant: 'exactIn', - swapIn: { ...poolReserve, amount: amountRef.current }, - swapOut: { ...swapTarget, amount: '0' }, - max: isMaxSelected, - skip: supplyTxState.loading, - } - ); + const { + inputAmountUSD, + inputAmount, + outputAmount, + outputAmountUSD, + error, + loading: routeLoading, + buildTxFn, + } = useCollateralSwap({ + chainId: currentNetworkConfig.underlyingChainId || currentChainId, + userAddress: currentAccount, + swapIn: { ...poolReserve, amount: amountRef.current }, + swapOut: { ...swapTarget.reserve, amount: '0' }, + max: isMaxSelected, + skip: supplyTxState.loading || false, + maxSlippage: Number(maxSlippage), + }); - const minimumReceived = new BigNumber(outputAmount || '0') - .multipliedBy(new BigNumber(100).minus(maxSlippage).dividedBy(100)) - .toString(10); + const loadingSkeleton = routeLoading && outputAmountUSD === '0'; const handleChange = (value: string) => { const maxSelected = value === '-1'; @@ -100,8 +99,8 @@ export const SwapModalContent = ({ fromAssetData: poolReserve, fromAssetUserData: userReserve, user, - toAmountAfterSlippage: minimumReceived, - toAssetData: swapTarget, + toAmountAfterSlippage: outputAmount, + toAssetData: swapTarget.reserve, }); // if the hf would drop below 1 from the hf effect a flashloan should be used to mitigate liquidation @@ -165,9 +164,7 @@ export const SwapModalContent = ({ // calculate impact based on $ difference const priceImpact = outputAmountUSD && outputAmountUSD !== '0' - ? new BigNumber(1) - .minus(new BigNumber(inputAmountUSD).dividedBy(outputAmountUSD)) - .toString(10) + ? new BigNumber(1).minus(new BigNumber(inputAmountUSD).dividedBy(outputAmountUSD)).toFixed(2) : '0'; return ( @@ -189,87 +186,55 @@ export const SwapModalContent = ({ }, ]} maxValue={maxAmountToSwap} - isMaxSelected={isMaxSelected} + inputTitle={Supplied asset amount} balanceText={Supply balance} + isMaxSelected={isMaxSelected} /> + + + + + + + Swap to} balanceText={Supply balance} disableInput + loading={loadingSkeleton} /> - - Price impact} captionVariant="subheader1"> - - - Minimum received} captionVariant="subheader1" sx={{ mt: 4 }}> - - - - Max slippage rate - - setMaxSlippage(value)} - exclusive - > - - 0.1% - - - 0.5% - - - 1% - - - - {blockingError !== undefined && ( + {error && !loadingSkeleton && ( - {handleBlocked()} + {error} )} - {error && ( + {!error && blockingError !== undefined && ( - {error} + {handleBlocked()} )} - - Supply apy} - value={poolReserve.supplyAPY} - futureValue={swapTarget.supplyAPY} - percent - /> - + } + > + - {showHealthFactor && ( - - )} {txError && } @@ -278,13 +243,14 @@ export const SwapModalContent = ({ isMaxSelected={isMaxSelected} poolReserve={poolReserve} amountToSwap={inputAmount} - amountToReceive={minimumReceived} + amountToReceive={outputAmount} isWrongNetwork={isWrongNetwork} - targetReserve={swapTarget} + targetReserve={swapTarget.reserve} symbol={poolReserve.symbol} - blocked={blockingError !== undefined} - priceRoute={priceRoute} + blocked={blockingError !== undefined || error !== ''} useFlashLoan={shouldUseFlashloan} + loading={routeLoading} + buildTxFn={buildTxFn} /> ); diff --git a/src/components/transactions/Swap/SwapModalDetails.tsx b/src/components/transactions/Swap/SwapModalDetails.tsx new file mode 100644 index 0000000000..316c791056 --- /dev/null +++ b/src/components/transactions/Swap/SwapModalDetails.tsx @@ -0,0 +1,223 @@ +import { valueToBigNumber } from '@aave/math-utils'; +import { ArrowNarrowRightIcon } from '@heroicons/react/outline'; +import { Trans } from '@lingui/macro'; +import { Box, Skeleton, SvgIcon, Typography, useTheme } from '@mui/material'; +import React from 'react'; +import { FormattedNumber } from 'src/components/primitives/FormattedNumber'; +import { Row } from 'src/components/primitives/Row'; +import { TokenIcon } from 'src/components/primitives/TokenIcon'; +import { + DetailsHFLine, + DetailsIncentivesLine, + DetailsNumberLine, +} from 'src/components/transactions/FlowCommons/TxModalDetails'; + +import { ComputedUserReserveData } from '../../../hooks/app-data-provider/useAppDataProvider'; + +export type SupplyModalDetailsProps = { + showHealthFactor: boolean; + healthFactor: string; + healthFactorAfterSwap: string; + swapSource: ComputedUserReserveData; + swapTarget: ComputedUserReserveData; + toAmount: string; + fromAmount: string; + loading: boolean; +}; + +export const SwapModalDetails = ({ + showHealthFactor, + healthFactor, + healthFactorAfterSwap, + swapSource, + swapTarget, + toAmount, + fromAmount, + loading, +}: SupplyModalDetailsProps) => { + const { palette } = useTheme(); + + const parseUsageString = (usage: boolean) => { + if (usage) { + return ( + + Yes + + ); + } else { + return ( + + No + + ); + } + }; + + const sourceAmountAfterSwap = valueToBigNumber(swapSource.underlyingBalance).minus( + valueToBigNumber(fromAmount) + ); + + const targetAmountAfterSwap = valueToBigNumber(swapTarget.underlyingBalance).plus( + valueToBigNumber(toAmount) + ); + + return ( + <> + {healthFactorAfterSwap && ( + + )} + Supply apy} + value={swapSource.reserve.supplyAPY} + futureValue={swapTarget.reserve.supplyAPY} + percent + loading={loading} + /> + Can be collateral} captionVariant="description" mb={4}> + + {loading ? ( + + ) : ( + <> + {parseUsageString(swapSource.reserve.usageAsCollateralEnabled)} + + + + + + {parseUsageString(swapTarget.reserve.usageAsCollateralEnabled)} + + )} + + + + Liquidation threshold} + value={swapSource.reserve.formattedReserveLiquidationThreshold} + futureValue={swapTarget.reserve.formattedReserveLiquidationThreshold} + percent + visibleDecimals={0} + loading={loading} + /> + + Supply balance after swap} + captionVariant="description" + mb={4} + align="flex-start" + > + + + {loading ? ( + + ) : ( + + + + + )} + {loading ? ( + + ) : ( + + )} + + + + {loading ? ( + + ) : ( + + + + + )} + {loading ? ( + + ) : ( + + )} + + + + + ); +}; diff --git a/src/components/transactions/TxActionsWrapper.tsx b/src/components/transactions/TxActionsWrapper.tsx index 26c3f0b846..b0c3e84e40 100644 --- a/src/components/transactions/TxActionsWrapper.tsx +++ b/src/components/transactions/TxActionsWrapper.tsx @@ -23,6 +23,13 @@ interface TxActionsWrapperProps extends BoxProps { requiresApproval: boolean; symbol?: string; blocked?: boolean; + fetchingData?: boolean; + errorParams?: { + loading: boolean; + disabled: boolean; + content: ReactNode; + handleClick: () => Promise; + }; } export const TxActionsWrapper = ({ @@ -40,22 +47,29 @@ export const TxActionsWrapper = ({ sx, symbol, blocked, + fetchingData = false, + errorParams, ...rest }: TxActionsWrapperProps) => { const { txError, retryWithApproval } = useModalContext(); const { watchModeOnlyAddress } = useWeb3Context(); const hasApprovalError = - requiresApproval && txError && txError.txAction === TxAction.APPROVAL && txError.actionBlocked; + requiresApproval && txError?.txAction === TxAction.APPROVAL && txError?.actionBlocked; const isAmountMissing = requiresAmount && requiresAmount && Number(amount) === 0; function getMainParams() { if (blocked) return { disabled: true, content: actionText }; - if (txError && txError.txAction === TxAction.GAS_ESTIMATION && txError.actionBlocked) - return { loading: false, disabled: true, content: actionText }; - if (txError && txError.txAction === TxAction.MAIN_ACTION && txError.actionBlocked) + if ( + (txError?.txAction === TxAction.GAS_ESTIMATION || + txError?.txAction === TxAction.MAIN_ACTION) && + txError?.actionBlocked + ) { + if (errorParams) return errorParams; return { loading: false, disabled: true, content: actionText }; + } if (isWrongNetwork) return { disabled: true, content: Wrong Network }; + if (fetchingData) return { disabled: true, content: Fetching data... }; if (isAmountMissing) return { disabled: true, content: Enter an amount }; if (preparingTransactions || isEmpty(mainTxState)) return { disabled: true, loading: true }; // if (hasApprovalError && handleRetry) diff --git a/src/helpers/useParaSwapTransactionHandler.tsx b/src/helpers/useParaSwapTransactionHandler.tsx new file mode 100644 index 0000000000..c440d313ae --- /dev/null +++ b/src/helpers/useParaSwapTransactionHandler.tsx @@ -0,0 +1,226 @@ +import { EthereumTransactionTypeExtended } from '@aave/contract-helpers'; +import { TransactionResponse } from '@ethersproject/providers'; +import { useEffect, useRef, useState } from 'react'; +import { useBackgroundDataProvider } from 'src/hooks/app-data-provider/BackgroundDataProvider'; +import { useModalContext } from 'src/hooks/useModal'; +import { useWeb3Context } from 'src/libs/hooks/useWeb3Context'; +import { getErrorTextFromError, TxAction } from 'src/ui-config/errorMapping'; + +interface UseParaSwapTransactionHandlerProps { + /** + * This function is called when the user clicks the action button in the modal and should return the transaction for the swap or repay. + * The paraswap API should be called in the implementation to get the required transaction parameters. + */ + handleGetTxns: () => Promise; + /** + * This function is only called once on initial load, and should return a transaction for the swap or repay, + * but the paraswap API should not be called in the implementation. This is to determine if an approval is needed and + * to get the gas limit for the swap or repay. + */ + handleGetApprovalTxns: () => Promise; + /** + * The gas limit recommendation to use for the swap or repay. This is used in the case where there is no approval needed. + */ + gasLimitRecommendation: string; + /** + * If true, handleGetApprovalTxns will not be called. Can be used if the route information is still loading. + */ + skip?: boolean; +} + +export const useParaSwapTransactionHandler = ({ + handleGetTxns, + handleGetApprovalTxns, + gasLimitRecommendation, + skip, +}: UseParaSwapTransactionHandlerProps) => { + const { + approvalTxState, + setApprovalTxState, + mainTxState, + setMainTxState, + setGasLimit, + loadingTxns, + setLoadingTxns, + setTxError, + } = useModalContext(); + const { sendTx, getTxError } = useWeb3Context(); + const { refetchWalletBalances, refetchPoolData, refetchIncentiveData } = + useBackgroundDataProvider(); + + const [approvalTx, setApprovalTx] = useState(); + const [actionTx, setActionTx] = useState(); + const mounted = useRef(false); + + useEffect(() => { + mounted.current = true; // Will set it to true on mount ... + return () => { + mounted.current = false; + }; // ... and to false on unmount + }, []); + /** + * Executes the transactions and handles loading & error states. + * @param fn + * @returns + */ + // eslint-disable-next-line + const processTx = async ({ + tx, + errorCallback, + successCallback, + }: { + tx: () => Promise; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + errorCallback?: (error: any, hash?: string) => void; + successCallback?: (param: TransactionResponse) => void; + action: TxAction; + }) => { + try { + const txnResult = await tx(); + try { + await txnResult.wait(1); + mounted.current && successCallback && successCallback(txnResult); + + refetchWalletBalances(); + refetchPoolData && refetchPoolData(); + refetchIncentiveData && refetchIncentiveData(); + } catch (e) { + // TODO: what to do with this error? + try { + // TODO: what to do with this error? + const error = await getTxError(txnResult.hash); + mounted.current && errorCallback && errorCallback(new Error(error), txnResult.hash); + return; + } catch (e) { + mounted.current && errorCallback && errorCallback(e, txnResult.hash); + return; + } + } + + return; + } catch (e) { + errorCallback && errorCallback(e); + } + }; + + const approval = async () => { + 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 () => { + setMainTxState({ ...mainTxState, loading: true }); + setTxError(undefined); + await handleGetTxns() + .then(async (data) => { + // Find actionTx (repay with collateral or swap) + const actionTx = data.find((tx) => ['DLP_ACTION'].includes(tx.txType)); + if (actionTx) { + try { + const params = await actionTx.tx(); + delete params.gasPrice; + return processTx({ + tx: () => sendTx(params), + successCallback: (txnResponse: TransactionResponse) => { + setMainTxState({ + txHash: txnResponse.hash, + loading: false, + success: true, + }); + setTxError(undefined); + }, + errorCallback: (error, hash) => { + const parsedError = getErrorTextFromError(error, TxAction.MAIN_ACTION); + setTxError(parsedError); + setMainTxState({ + txHash: hash, + loading: false, + }); + }, + action: TxAction.MAIN_ACTION, + }); + } catch (error) { + const parsedError = getErrorTextFromError(error, TxAction.GAS_ESTIMATION, false); + setTxError(parsedError); + setMainTxState({ + ...mainTxState, + loading: false, + }); + } + } + }) + .catch((error) => { + const parsedError = getErrorTextFromError(error, TxAction.GAS_ESTIMATION, false); + setTxError(parsedError); + setMainTxState({ + ...mainTxState, + loading: false, + }); + }); + }; + + // Populates the approval transaction and sets the default gas estimation. + useEffect(() => { + if (!skip) { + setLoadingTxns(true); + handleGetApprovalTxns() + .then(async (data) => { + setApprovalTx(data.find((tx) => tx.txType === 'ERC20_APPROVAL')); + }) + .finally(() => { + setMainTxState({ + txHash: undefined, + }); + setGasLimit(gasLimitRecommendation); + setLoadingTxns(false); + }); + } else { + setApprovalTx(undefined); + setActionTx(undefined); + } + }, [skip]); + + return { + approval, + action, + loadingTxns, + requiresApproval: !!approvalTx, + approvalTxState, + mainTxState, + actionTx, + approvalTx, + }; +}; diff --git a/src/hooks/paraswap/common.ts b/src/hooks/paraswap/common.ts new file mode 100644 index 0000000000..69500d31ac --- /dev/null +++ b/src/hooks/paraswap/common.ts @@ -0,0 +1,404 @@ +import { ChainId } from '@aave/contract-helpers'; +import { BigNumberZeroDecimal, normalize, normalizeBN, valueToBigNumber } from '@aave/math-utils'; +import { + constructBuildTx, + constructFetchFetcher, + constructGetRate, + constructPartialSDK, + TransactionParams, +} from '@paraswap/sdk'; +import { RateOptions } from '@paraswap/sdk/dist/methods/swap/rates'; +import { ContractMethod, OptimalRate, SwapSide } from 'paraswap-core'; + +import { ComputedReserveData } from '../app-data-provider/useAppDataProvider'; + +const FEE_CLAIMER_ADDRESS = '0x9abf798f5314BFd793A9E57A654BEd35af4A1D60'; + +export type UseSwapProps = { + chainId: ChainId; + max: boolean; + maxSlippage: number; + swapIn: SwapReserveData; + swapOut: SwapReserveData; + userAddress: string; + skip: boolean; +}; + +export type SwapReserveData = ComputedReserveData & { amount: string }; + +export type SwapData = Pick< + SwapReserveData, + 'amount' | 'underlyingAsset' | 'decimals' | 'supplyAPY' | 'variableBorrowAPY' +>; + +export type SwapVariant = 'exactIn' | 'exactOut'; + +type SwapRateParams = { + inputAmount: string; + outputAmount: string; + inputAmountUSD: string; + outputAmountUSD: string; +}; + +export type SwapTransactionParams = SwapRateParams & { + swapCallData: string; + augustus: string; +}; + +const ParaSwap = (chainId: number) => { + const fetcher = constructFetchFetcher(fetch); // alternatively constructFetchFetcher + return constructPartialSDK( + { + chainId, + fetcher, + }, + constructBuildTx, + constructGetRate + ); +}; + +const mainnetParaswap = ParaSwap(ChainId.mainnet); +const polygonParaswap = ParaSwap(ChainId.polygon); +const avalancheParaswap = ParaSwap(ChainId.avalanche); +const fantomParaswap = ParaSwap(ChainId.fantom); +const arbitrumParaswap = ParaSwap(ChainId.arbitrum_one); +const optimismParaswap = ParaSwap(ChainId.optimism); + +export const getParaswap = (chainId: ChainId) => { + if (ChainId.mainnet === chainId) return mainnetParaswap; + if (ChainId.polygon === chainId) return polygonParaswap; + if (ChainId.avalanche === chainId) return avalancheParaswap; + if (ChainId.fantom === chainId) return fantomParaswap; + if (ChainId.arbitrum_one === chainId) return arbitrumParaswap; + if (ChainId.optimism === chainId) return optimismParaswap; + throw new Error('chain not supported'); +}; + +export const MESSAGE_MAP: { [key: string]: string } = { + ESTIMATED_LOSS_GREATER_THAN_MAX_IMPACT: + 'Price impact too high. Please try a different amount or asset pair.', + // not sure why this error-code is not upper-cased + 'No routes found with enough liquidity': 'No routes found with enough liquidity.', +}; + +/** + * Uses the Paraswap SDK to build the transaction parameters for a 'Sell', or 'Exact In' swap. + * @param {OptimalRate} route + * @param {SwapData} swapIn + * @param {SwapData} swapOut + * @param {ChainId} chainId + * @param {string} userAddress + * @param {number} maxSlippage + * @param {boolean} [max] + * @returns {Promise} + */ +export async function fetchExactInTxParams( + route: OptimalRate, + swapIn: SwapData, + swapOut: SwapData, + chainId: ChainId, + userAddress: string, + maxSlippage: number +): Promise { + const swapper = ExactInSwapper(chainId); + const { swapCallData, augustus, destAmountWithSlippage } = await swapper.getTransactionParams( + swapIn.underlyingAsset, + swapIn.decimals, + swapOut.underlyingAsset, + swapOut.decimals, + userAddress, + route, + maxSlippage + ); + + return { + swapCallData, + augustus, + inputAmount: normalize(route.srcAmount, swapIn.decimals), + outputAmount: normalize(destAmountWithSlippage, swapOut.decimals), + inputAmountUSD: route.srcUSD, + outputAmountUSD: route.destUSD, + }; +} + +/** + * Uses the Paraswap SDK to fetch the route for a 'Sell', or 'Exact In' swap. + * The swap in amount is fixed, and the slippage will be applied to the amount received. + * @param {SwapData} swapIn + * @param {SwapData} swapOut + * @param {ChainId} chainId + * @param {string} userAddress + * @param {number} maxSlippage + * @param {boolean} [max] + * @returns {Promise} + */ +export async function fetchExactInRate( + swapIn: SwapData, + swapOut: SwapData, + chainId: ChainId, + userAddress: string, + max?: boolean +): Promise { + let swapInAmount = valueToBigNumber(swapIn.amount); + if (max && swapIn.supplyAPY !== '0') { + swapInAmount = swapInAmount.plus( + swapInAmount.multipliedBy(swapIn.supplyAPY).dividedBy(360 * 24) + ); + } + + const amount = normalizeBN(swapInAmount, swapIn.decimals * -1); + + const options: RateOptions = { + partner: 'aave', + }; + + if (max) { + options.excludeContractMethods = [ContractMethod.simpleSwap]; + } + + const swapper = ExactInSwapper(chainId); + return await swapper.getRate( + amount.toFixed(0), + swapIn.underlyingAsset, + swapIn.decimals, + swapOut.underlyingAsset, + swapOut.decimals, + userAddress, + options + ); +} + +/** + * Uses the Paraswap SDK to build the transaction parameters for a 'Buy', or 'Exact Out' swap. + * @param {OptimalRate} route + * @param {SwapData} swapIn + * @param {SwapData} swapOut + * @param {ChainId} chainId + * @param {string} userAddress + * @param {number} maxSlippage + * @returns {Promise} + */ +export async function fetchExactOutTxParams( + route: OptimalRate, + swapIn: SwapData, + swapOut: SwapData, + chainId: ChainId, + userAddress: string, + maxSlippage: number +): Promise { + const swapper = ExactOutSwapper(chainId); + const { swapCallData, augustus, srcAmountWithSlippage } = await swapper.getTransactionParams( + swapIn.underlyingAsset, + swapIn.decimals, + swapOut.underlyingAsset, + swapOut.decimals, + userAddress, + route, + maxSlippage + ); + + return { + swapCallData, + augustus, + inputAmount: normalize(srcAmountWithSlippage, swapIn.decimals), + outputAmount: normalize(route.destAmount, swapOut.decimals), + inputAmountUSD: route.srcUSD, + outputAmountUSD: route.destUSD, + }; +} + +/** + * Uses the Paraswap SDK to fetch the swap rate for a 'Buy', or 'Exact Out' swap. + * This means that amount received is fixed, and positive slippage will be applied to the input amount. + * @param {SwapData} swapIn + * @param {SwapData} swapOut + * @param {ChainId} chainId + * @param {string} userAddress + * @param {number} maxSlippage + * @param {boolean} max + * @returns {Promise} + */ +export async function fetchExactOutRate( + swapIn: SwapData, + swapOut: SwapData, + chainId: ChainId, + userAddress: string, + max: boolean +): Promise { + let swapOutAmount = valueToBigNumber(swapOut.amount); + if (max) { + // variableBorrowAPY in most cases should be higher than stableRate so while this is slightly inaccurate it should be enough + swapOutAmount = swapOutAmount.plus( + swapOutAmount.multipliedBy(swapIn.variableBorrowAPY).dividedBy(360 * 24) + ); + } + const amount = normalizeBN(swapOutAmount, swapOut.decimals * -1); + + const options: RateOptions = { + partner: 'aave', + }; + + if (max) { + options.excludeContractMethods = [ContractMethod.simpleBuy]; + } + + const swapper = ExactOutSwapper(chainId); + + return await swapper.getRate( + amount.toFixed(0), + swapIn.underlyingAsset, + swapIn.decimals, + swapOut.underlyingAsset, + swapOut.decimals, + userAddress, + options + ); +} + +const ExactInSwapper = (chainId: ChainId) => { + const paraSwap = getParaswap(chainId); + + const getRate = async ( + amount: string, + srcToken: string, + srcDecimals: number, + destToken: string, + destDecimals: number, + userAddress: string, + options: RateOptions + ) => { + const priceRoute = await paraSwap.getRate({ + amount, + srcToken, + srcDecimals, + destToken, + destDecimals, + userAddress, + side: SwapSide.SELL, + options, + }); + + return priceRoute; + }; + + const getTransactionParams = async ( + srcToken: string, + srcDecimals: number, + destToken: string, + destDecimals: number, + user: string, + route: OptimalRate, + maxSlippage: number + ) => { + const destAmountWithSlippage = new BigNumberZeroDecimal(route.destAmount) + .multipliedBy(100 - maxSlippage) + .dividedBy(100) + .toFixed(0); + + try { + const params = await paraSwap.buildTx( + { + srcToken, + srcDecimals, + srcAmount: route.srcAmount, + destToken, + destDecimals, + destAmount: destAmountWithSlippage, + priceRoute: route, + userAddress: user, + partner: 'aave', + partnerAddress: FEE_CLAIMER_ADDRESS, + }, + { ignoreChecks: true } + ); + + return { + swapCallData: (params as TransactionParams).data, + augustus: (params as TransactionParams).to, + destAmountWithSlippage, + }; + } catch (e) { + console.error(e); + throw new Error('Error building transaction parameters'); + } + }; + + return { + getRate, + getTransactionParams, + }; +}; + +const ExactOutSwapper = (chainId: ChainId) => { + const paraSwap = getParaswap(chainId); + + const getRate = async ( + amount: string, + srcToken: string, + srcDecimals: number, + destToken: string, + destDecimals: number, + userAddress: string, + options: RateOptions + ) => { + const priceRoute = await paraSwap.getRate({ + amount, + srcToken, + srcDecimals, + destToken, + destDecimals, + userAddress, + side: SwapSide.BUY, + options, + }); + + return priceRoute; + }; + + const getTransactionParams = async ( + srcToken: string, + srcDecimals: number, + destToken: string, + destDecimals: number, + user: string, + route: OptimalRate, + maxSlippage: number + ) => { + const srcAmountWithSlippage = new BigNumberZeroDecimal(route.srcAmount) + .multipliedBy(100 + maxSlippage) + .dividedBy(100) + .toFixed(0); + + try { + const params = await paraSwap.buildTx( + { + srcToken, + srcDecimals, + srcAmount: srcAmountWithSlippage, + destToken, + destDecimals, + destAmount: route.destAmount, + priceRoute: route, + userAddress: user, + partner: 'aave', + partnerAddress: FEE_CLAIMER_ADDRESS, + }, + { ignoreChecks: true } + ); + + return { + swapCallData: (params as TransactionParams).data, + augustus: (params as TransactionParams).to, + srcAmountWithSlippage, + }; + } catch (e) { + console.log(e); + throw new Error('Error building transaction parameters'); + } + }; + + return { + getRate, + getTransactionParams, + }; +}; diff --git a/src/hooks/paraswap/useCollateralRepaySwap.tsx b/src/hooks/paraswap/useCollateralRepaySwap.tsx new file mode 100644 index 0000000000..cdbabc894e --- /dev/null +++ b/src/hooks/paraswap/useCollateralRepaySwap.tsx @@ -0,0 +1,188 @@ +import { BigNumberZeroDecimal, normalize } from '@aave/math-utils'; +import { OptimalRate } from 'paraswap-core'; +import { useCallback, useEffect, useMemo, useState } from 'react'; + +import { + fetchExactInRate, + fetchExactInTxParams, + fetchExactOutRate, + fetchExactOutTxParams, + MESSAGE_MAP, + SwapData, + SwapTransactionParams, + SwapVariant, + UseSwapProps, +} from './common'; + +type UseRepayWithCollateralProps = UseSwapProps & { + swapVariant: SwapVariant; +}; + +interface UseRepayWithCollateralResponse { + outputAmount: string; + outputAmountUSD: string; + inputAmount: string; + inputAmountUSD: string; + loading: boolean; + error: string; + buildTxFn: () => Promise; +} + +export const useCollateralRepaySwap = ({ + chainId, + max, + maxSlippage, + skip, + swapIn, + swapOut, + userAddress, + swapVariant, +}: UseRepayWithCollateralProps): UseRepayWithCollateralResponse => { + const [inputAmount, setInputAmount] = useState('0'); + const [inputAmountUSD, setInputAmountUSD] = useState('0'); + const [outputAmount, setOutputAmount] = useState('0'); + const [outputAmountUSD, setOutputAmountUSD] = useState('0'); + const [route, setRoute] = useState(); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(''); + + const swapInData = useMemo(() => { + const swapData: SwapData = { + underlyingAsset: swapIn.underlyingAsset, + decimals: swapIn.decimals, + supplyAPY: swapIn.supplyAPY, + amount: swapIn.amount, + variableBorrowAPY: swapIn.variableBorrowAPY, + }; + return swapData; + }, [ + swapIn.amount, + swapIn.decimals, + swapIn.supplyAPY, + swapIn.underlyingAsset, + swapIn.variableBorrowAPY, + ]); + + const swapOutData = useMemo(() => { + const swapData: SwapData = { + underlyingAsset: swapOut.underlyingAsset, + decimals: swapOut.decimals, + supplyAPY: swapOut.supplyAPY, + amount: swapOut.amount, + variableBorrowAPY: swapOut.variableBorrowAPY, + }; + return swapData; + }, [ + swapOut.amount, + swapOut.decimals, + swapOut.supplyAPY, + swapOut.underlyingAsset, + swapOut.variableBorrowAPY, + ]); + + const exactInRate = useCallback(() => { + return fetchExactInRate(swapInData, swapOutData, chainId, userAddress); + }, [chainId, swapInData, swapOutData, userAddress]); + + const exactOutRate = useCallback( + () => fetchExactOutRate(swapInData, swapOutData, chainId, userAddress, max), + [chainId, max, swapInData, swapOutData, userAddress] + ); + + useEffect(() => { + if (skip) return; + + const fetchRoute = async () => { + if ( + !swapInData.underlyingAsset || + !swapOutData.underlyingAsset || + (swapVariant === 'exactIn' && + (!swapInData.amount || swapInData.amount === '0' || isNaN(+swapInData.amount))) || + (swapVariant === 'exactOut' && + (!swapOutData.amount || swapOutData.amount === '0' || isNaN(+swapOutData.amount))) + ) { + setInputAmount('0'); + setInputAmountUSD('0'); + setOutputAmount('0'); + setOutputAmountUSD('0'); + setRoute(undefined); + return; + } + + setLoading(true); + + try { + let route: OptimalRate; + if (swapVariant === 'exactIn') { + route = await exactInRate(); + } else { + route = await exactOutRate(); + } + + setError(''); + setRoute(route); + + if (swapVariant === 'exactIn') { + const minAmount = new BigNumberZeroDecimal(route.destAmount) + .multipliedBy(1 - maxSlippage / 100) + .toFixed(0); + setInputAmount(normalize(route.srcAmount, route.srcDecimals)); + setOutputAmount(normalize(minAmount, route.destDecimals)); + } else { + const srcAmount = new BigNumberZeroDecimal(route.srcAmount) + .multipliedBy(1 - maxSlippage / 100) + .toFixed(0); + + setInputAmount(normalize(srcAmount, route.srcDecimals)); + setOutputAmount(normalize(route.destAmount, route.destDecimals)); + } + + setInputAmountUSD(route.srcUSD); + setOutputAmountUSD(route.destUSD); + } catch (e) { + console.error(e); + const message = MESSAGE_MAP[e.message] || 'There was an issue fetching data from Paraswap'; + setError(message); + } finally { + setLoading(false); + } + }; + + // Update the transaction on any dependency change + const timeout = setTimeout(() => { + fetchRoute(); + }, 400); + + return () => { + clearTimeout(timeout); + }; + }, [ + skip, + swapVariant, + swapInData.underlyingAsset, + swapInData.amount, + swapOutData.underlyingAsset, + swapOutData.amount, + exactInRate, + exactOutRate, + maxSlippage, + ]); + + return { + outputAmount, + outputAmountUSD, + inputAmount, + inputAmountUSD, + loading, + error, + // Used for calling paraswap buildTx as very last step in transaction + buildTxFn: async () => { + if (!route) throw new Error('Route required to build transaction'); + if (swapVariant === 'exactIn') { + return fetchExactInTxParams(route, swapIn, swapOut, chainId, userAddress, maxSlippage); + } else { + return fetchExactOutTxParams(route, swapIn, swapOut, chainId, userAddress, maxSlippage); + } + }, + }; +}; diff --git a/src/hooks/paraswap/useCollateralSwap.tsx b/src/hooks/paraswap/useCollateralSwap.tsx new file mode 100644 index 0000000000..df3ed6fd69 --- /dev/null +++ b/src/hooks/paraswap/useCollateralSwap.tsx @@ -0,0 +1,156 @@ +import { BigNumberZeroDecimal, normalize } from '@aave/math-utils'; +import { OptimalRate } from 'paraswap-core'; +import { useCallback, useEffect, useMemo, useState } from 'react'; + +import { + fetchExactInRate, + fetchExactInTxParams, + MESSAGE_MAP, + SwapData, + SwapTransactionParams, + UseSwapProps, +} from './common'; + +interface UseSwapResponse { + outputAmount: string; + outputAmountUSD: string; + inputAmount: string; + inputAmountUSD: string; + loading: boolean; + error: string; + buildTxFn: () => Promise; +} + +export const useCollateralSwap = ({ + chainId, + max, + maxSlippage, + swapIn, + swapOut, + userAddress, + skip, +}: UseSwapProps): UseSwapResponse => { + const [inputAmount, setInputAmount] = useState('0'); + const [inputAmountUSD, setInputAmountUSD] = useState('0'); + const [outputAmount, setOutputAmount] = useState('0'); + const [outputAmountUSD, setOutputAmountUSD] = useState('0'); + const [route, setRoute] = useState(); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(''); + + const swapInData = useMemo(() => { + const swapData: SwapData = { + underlyingAsset: swapIn.underlyingAsset, + decimals: swapIn.decimals, + supplyAPY: swapIn.supplyAPY, + amount: swapIn.amount, + variableBorrowAPY: swapIn.variableBorrowAPY, + }; + return swapData; + }, [ + swapIn.amount, + swapIn.decimals, + swapIn.supplyAPY, + swapIn.underlyingAsset, + swapIn.variableBorrowAPY, + ]); + + const swapOutData = useMemo(() => { + const swapData: SwapData = { + underlyingAsset: swapOut.underlyingAsset, + decimals: swapOut.decimals, + supplyAPY: swapOut.supplyAPY, + amount: swapOut.amount, + variableBorrowAPY: swapOut.variableBorrowAPY, + }; + return swapData; + }, [ + swapOut.amount, + swapOut.decimals, + swapOut.supplyAPY, + swapOut.underlyingAsset, + swapOut.variableBorrowAPY, + ]); + + const exactInRate = useCallback(() => { + return fetchExactInRate(swapInData, swapOutData, chainId, userAddress, max); + }, [chainId, swapInData, swapOutData, userAddress, max]); + + useEffect(() => { + if (skip) return; + + const fetchRoute = async () => { + if ( + !swapInData.underlyingAsset || + !swapOutData.underlyingAsset || + !swapInData.amount || + swapInData.amount === '0' || + isNaN(+swapInData.amount) + ) { + setInputAmount('0'); + setOutputAmount('0'); + setOutputAmountUSD('0'); + setInputAmountUSD('0'); + setRoute(undefined); + return; + } + + setLoading(true); + + try { + const route = await exactInRate(); + setError(''); + setRoute(route); + + setInputAmount(normalize(route.srcAmount, route.srcDecimals)); + setInputAmountUSD(route.srcUSD); + + const minAmount = new BigNumberZeroDecimal(route.destAmount) + .multipliedBy(1 - maxSlippage / 100) + .toFixed(0); + + setOutputAmount(normalize(minAmount, route.destDecimals)); + setOutputAmountUSD(route.destUSD); + } catch (e) { + console.error(e); + const message = MESSAGE_MAP[e.message] || 'There was an issue fetching data from Paraswap'; + setError(message); + } finally { + setLoading(false); + } + }; + + // Update the transaction on any dependency change + const timeout = setTimeout(() => { + fetchRoute(); + }, 400); + + return () => { + clearTimeout(timeout); + }; + }, [ + error, + skip, + swapInData.underlyingAsset, + swapOutData.underlyingAsset, + exactInRate, + maxSlippage, + swapInData.amount, + userAddress, + max, + ]); + + return { + outputAmount, + outputAmountUSD, + inputAmount, + inputAmountUSD, + loading, + error, + // Used for calling paraswap buildTx as very last step in transaction + buildTxFn: async () => { + if (!route) throw new Error('Route required to build transaction'); + return fetchExactInTxParams(route, swapIn, swapOut, chainId, userAddress, maxSlippage); + }, + }; +}; diff --git a/src/hooks/useModal.tsx b/src/hooks/useModal.tsx index 1518c217aa..803ea11710 100644 --- a/src/hooks/useModal.tsx +++ b/src/hooks/useModal.tsx @@ -32,6 +32,7 @@ export interface ModalArgsType { stakeAssetName?: string; currentRateMode?: InterestRate; emode?: EmodeModalType; + isFrozen?: boolean; } export type TxStateType = { @@ -45,7 +46,7 @@ export interface ModalContextType { openSupply: (underlyingAsset: string) => void; openWithdraw: (underlyingAsset: string) => void; openBorrow: (underlyingAsset: string) => void; - openRepay: (underlyingAsset: string, currentRateMode: InterestRate) => void; + openRepay: (underlyingAsset: string, currentRateMode: InterestRate, isFrozen: boolean) => void; openCollateralChange: (underlyingAsset: string) => void; openRateSwitch: (underlyingAsset: string, currentRateMode: InterestRate) => void; openStake: (stakeAssetName: string, icon: string) => void; @@ -107,9 +108,9 @@ export const ModalContextProvider: React.FC = ({ children }) => { setType(ModalType.Borrow); setArgs({ underlyingAsset }); }, - openRepay: (underlyingAsset, currentRateMode) => { + openRepay: (underlyingAsset, currentRateMode, isFrozen) => { setType(ModalType.Repay); - setArgs({ underlyingAsset, currentRateMode }); + setArgs({ underlyingAsset, currentRateMode, isFrozen }); }, openCollateralChange: (underlyingAsset) => { setType(ModalType.CollateralChange); diff --git a/src/hooks/useSwap.ts b/src/hooks/useSwap.ts deleted file mode 100644 index 0c759e8769..0000000000 --- a/src/hooks/useSwap.ts +++ /dev/null @@ -1,281 +0,0 @@ -import { ChainId } from '@aave/contract-helpers'; -import { BigNumberZeroDecimal, normalize, normalizeBN, valueToBigNumber } from '@aave/math-utils'; -import { - constructBuildTx, - constructFetchFetcher, - constructGetRate, - constructPartialSDK, - TransactionParams, -} from '@paraswap/sdk'; -import { ContractMethod, OptimalRate, SwapSide } from 'paraswap-core'; -import { useCallback, useEffect, useState } from 'react'; - -import { ComputedReserveData } from './app-data-provider/useAppDataProvider'; - -const ParaSwap = (chainId: number) => { - const fetcher = constructFetchFetcher(fetch); // alternatively constructFetchFetcher - return constructPartialSDK( - { - network: chainId, - fetcher, - }, - constructBuildTx, - constructGetRate - ); -}; - -const mainnetParaswap = ParaSwap(ChainId.mainnet); -const polygonParaswap = ParaSwap(ChainId.polygon); -const avalancheParaswap = ParaSwap(ChainId.avalanche); -const fantomParaswap = ParaSwap(ChainId.fantom); -const arbitrumParaswap = ParaSwap(ChainId.arbitrum_one); -const optimismParaswap = ParaSwap(ChainId.optimism); - -const getParaswap = (chainId: ChainId) => { - if (ChainId.mainnet === chainId) return mainnetParaswap; - if (ChainId.polygon === chainId) return polygonParaswap; - if (ChainId.avalanche === chainId) return avalancheParaswap; - if (ChainId.fantom === chainId) return fantomParaswap; - if (ChainId.arbitrum_one === chainId) return arbitrumParaswap; - if (ChainId.optimism === chainId) return optimismParaswap; - throw new Error('chain not supported'); -}; - -type UseSwapProps = { - max?: boolean; - swapIn: ComputedReserveData & { amount: string }; - swapOut: ComputedReserveData & { amount: string }; - variant: 'exactIn' | 'exactOut'; - userId?: string; - chainId: ChainId; - skip?: boolean; -}; - -const MESSAGE_MAP = { - ESTIMATED_LOSS_GREATER_THAN_MAX_IMPACT: 'Price impact to high', - // not sure why this error-code is not upper-cased - 'No routes found with enough liquidity': 'No routes found with enough liquidity', -}; - -export const useSwap = ({ swapIn, swapOut, variant, userId, max, chainId, skip }: UseSwapProps) => { - const paraSwap = getParaswap(chainId); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(''); - const [priceRoute, setPriceRoute] = useState(null); - - const fetchRoute = useCallback(async () => { - if (!swapIn.underlyingAsset || !swapOut.underlyingAsset || !userId) return; - if (variant === 'exactIn' && (!swapIn.amount || swapIn.amount === '0')) return; - if (variant === 'exactOut' && (!swapOut.amount || swapOut.amount === '0')) return; - setLoading(true); - let _amount = valueToBigNumber(variant === 'exactIn' ? swapIn.amount : swapOut.amount); - if (variant === 'exactIn' && max && swapIn.supplyAPY !== '0') { - _amount = _amount.plus(_amount.multipliedBy(swapIn.supplyAPY).dividedBy(360 * 24)); - } - if (variant === 'exactOut' && max) { - // variableBorrowAPY in most cases should be higher than stableRate so while this is slightly inaccurate it should be enough - _amount = _amount.plus(_amount.multipliedBy(swapIn.variableBorrowAPY).dividedBy(360 * 24)); - } - const amount = normalizeBN( - _amount, - (variant === 'exactIn' ? swapIn.decimals : swapOut.decimals) * -1 - ); - - try { - const excludedMethod = - variant === 'exactIn' ? ContractMethod.simpleSwap : ContractMethod.simpleBuy; - const response = await paraSwap.getRate({ - amount: amount.toFixed(0), - srcToken: swapIn.underlyingAsset, - srcDecimals: swapIn.decimals, - destToken: swapOut.underlyingAsset, - destDecimals: swapOut.decimals, - userAddress: userId, - side: variant === 'exactIn' ? SwapSide.SELL : SwapSide.BUY, - options: { - partner: 'aave', - excludeDEXS: - 'ParaSwapPool,ParaSwapPool2,ParaSwapPool3,ParaSwapPool4,ParaSwapPool5,ParaSwapPool6,ParaSwapPool7,ParaSwapPool8,ParaSwapPool9,ParaSwapPool10', - ...(max - ? { - excludeDEXS: - 'Balancer,ParaSwapPool,ParaSwapPool2,ParaSwapPool3,ParaSwapPool4,ParaSwapPool5,ParaSwapPool6,ParaSwapPool7,ParaSwapPool8,ParaSwapPool9,ParaSwapPool10', - excludeContractMethods: [excludedMethod], - } - : {}), - }, - }); - - setError(''); - setPriceRoute(response as OptimalRate); - } catch (e) { - console.log(e); - console.log(e.message); - const message = (MESSAGE_MAP as { [key: string]: string })[e.message]; - setError(message || 'There was an issue fetching data from Paraswap'); - } - setLoading(false); - }, [ - swapIn.amount, - swapIn.underlyingAsset, - swapIn.decimals, - swapOut.amount, - swapOut.underlyingAsset, - swapOut.decimals, - userId, - variant, - max, - chainId, - ]); - - // updates the route on input change - useEffect(() => { - if (skip) return; - setPriceRoute(null); - const timeout = setTimeout(fetchRoute, 400); - return () => clearTimeout(timeout); - }, [fetchRoute, skip]); - - // updates the route based on on interval - useEffect(() => { - if (skip) return; - const interval = setInterval(fetchRoute, error ? 3000 : 15000); - return () => clearInterval(interval); - }, [fetchRoute, error, skip]); - - if (priceRoute) { - return { - // full object needed for building the tx - priceRoute: priceRoute, - outputAmount: normalize( - priceRoute.destAmount ?? '0', - variant === 'exactIn' ? swapOut.decimals : swapOut.decimals - ), - outputAmountUSD: priceRoute.destUSD ?? '0', - inputAmount: normalize( - priceRoute.srcAmount ?? '0', - variant === 'exactIn' ? swapIn.decimals : swapIn.decimals - ), - inputAmountUSD: priceRoute.srcUSD ?? '0', - loading: loading, - error: error, - }; - } - return { - // full object needed for building the tx - priceRoute: null, - outputAmount: '0', - outputAmountUSD: '0', - inputAmount: '0', - inputAmountUSD: '0', - loading: loading, - error: error, - }; -}; - -type GetSwapCallDataProps = { - srcToken: string; - srcDecimals: number; - destToken: string; - destDecimals: number; - user: string; - route: OptimalRate; - max?: boolean; - chainId: ChainId; -}; - -export type GetSwapAndRepayCallDataProps = { - srcToken: string; - srcDecimals: number; - destToken: string; - destDecimals: number; - user: string; - route: OptimalRate; - max?: boolean; - chainId: ChainId; - maxSlippage: number; -}; - -export const getSwapCallData = async ({ - srcToken, - srcDecimals, - destToken, - destDecimals, - user, - route, - chainId, -}: GetSwapCallDataProps) => { - const paraSwap = getParaswap(chainId); - const destAmountWithSlippage = new BigNumberZeroDecimal(route.destAmount) - .multipliedBy(99) - .dividedBy(100) - .toFixed(0); - - try { - const params = await paraSwap.buildTx( - { - srcToken, - destToken, - srcAmount: route.srcAmount, - destAmount: destAmountWithSlippage, - priceRoute: route, - userAddress: user, - partner: 'aave', - srcDecimals, - destDecimals, - }, - { ignoreChecks: true } - ); - - return { - swapCallData: (params as TransactionParams).data, - augustus: (params as TransactionParams).to, - }; - } catch (e) { - console.log(e); - throw new Error('Error getting txParams'); - } -}; - -export const getRepayCallData = async ({ - srcToken, - srcDecimals, - destToken, - destDecimals, - user, - route, - chainId, - maxSlippage, -}: GetSwapAndRepayCallDataProps) => { - const paraSwap = getParaswap(chainId); - const srcAmountWithSlippage = new BigNumberZeroDecimal(route.srcAmount) - .multipliedBy(100 + maxSlippage) - .dividedBy(100) - .toFixed(0); - - try { - const params = await paraSwap.buildTx( - { - srcToken, - destToken, - srcAmount: srcAmountWithSlippage, - destAmount: route.destAmount, - priceRoute: route, - userAddress: user, - partner: 'aave', - srcDecimals, - destDecimals, - }, - { ignoreChecks: true } - ); - - return { - swapCallData: (params as TransactionParams).data, - augustus: (params as TransactionParams).to, - srcAmountWithSlippage, - }; - } catch (e) { - console.log(e); - throw new Error('Error getting txParams'); - } -}; diff --git a/src/locales/en/messages.js b/src/locales/en/messages.js index 7dccea95d6..345ab86a36 100644 --- a/src/locales/en/messages.js +++ b/src/locales/en/messages.js @@ -1 +1 @@ -/*eslint-disable*/module.exports={messages:{"<0>Ampleforth is a rebasing asset. Visit the <1>documentation to learn more.":"<0>Ampleforth is a rebasing asset. Visit the <1>documentation to learn more.","<0>Attention: Parameter changes via governance can alter your account health factor and risk of liquidation. Follow the <1>Aave governance forum for updates.":"<0>Attention: Parameter changes via governance can alter your account health factor and risk of liquidation. Follow the <1>Aave governance forum for updates.","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>variable and <1>stable 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>variable and <1>stable 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.","Approval":"Approval","Approve confirmed":"Approve confirmed","Approve to continue":"Approve to continue","Approved":"Approved","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","Before supplying, you need to approve its usage by the Aave protocol. You can learn more in our <0>FAQ":"Before supplying, you need to approve its usage by the Aave protocol. You can learn more in our <0>FAQ","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 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 details":"Borrowing is disabled due to an Aave community decision. <0>More details","Borrowing is not enabled":"Borrowing is not enabled","Borrowing is unavailable because you’re using Isolation mode. To manage Isolation mode visit your <0>Dashboard.":"Borrowing is unavailable because you’re using Isolation mode. To manage Isolation mode visit your <0>Dashboard.","Borrowing is unavailable because you’ve enabled Efficiency Mode (E-Mode) and Isolation mode. To manage E-Mode and Isolation mode visit your <0>Dashboard.":"Borrowing is unavailable because you’ve enabled Efficiency Mode (E-Mode) and Isolation mode. To manage E-Mode and Isolation mode visit your <0>Dashboard.","Borrowing is unavailable because you’ve enabled Efficiency Mode (E-Mode) for {0} category. To manage E-Mode categories visit your <0>Dashboard.":["Borrowing is unavailable because you’ve enabled Efficiency Mode (E-Mode) for ",["0"]," category. To manage E-Mode categories visit your <0>Dashboard."],"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 amount to repay with":"Collateral amount to repay with","Collateral is (mostly) the same currency that is being borrowed":"Collateral is (mostly) the same currency that is being borrowed","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 More":"Collateral usage is limited because of isolation mode. <0>Learn More","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 amount to repay":"Debt amount to repay","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.","Define Retry with Approval text":"Define Retry with Approval text","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 more":"E-Mode increases your LTV for a selected category of assets up to 97%. <0>Learn more","E-Mode increases your LTV for a selected category of assets up to<0/>. <1>Learn more":"E-Mode increases your LTV for a selected category of assets up to<0/>. <1>Learn more","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>Dashboard. To learn more about E-Mode and applied restrictions in <1>FAQ or <2>Aave V3 Technical Paper.":"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>Dashboard. To learn more about E-Mode and applied restrictions in <1>FAQ or <2>Aave V3 Technical Paper.","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 guide 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 guide 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 address to track in watch-only mode":"Enter an address to track in watch-only mode","Enter an amount":"Enter an amount","Error connecting. Try refreshing the page.":"Error connecting. Try refreshing the page.","Executed":"Executed","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"]],"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>FAQ":["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>FAQ"],"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 guide":"Learn more in our <0>FAQ guide","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","Max slippage rate":"Max slippage rate","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","Minimum received":"Minimum received","More":"More","NAY":"NAY","Need help connecting a wallet? <0>Read our FAQ":"Need help connecting a wallet? <0>Read our FAQ","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 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","Price impact":"Price impact","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","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","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","Retry What?":"Retry What?","Retry with Approval":"Retry with Approval","Retry with approval":"Retry with approval","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 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>Dashboard":"Since this asset is frozen, the only available actions are withdraw and repay which can be accessed from the <0>Dashboard","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","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 same 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 same 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","Supply":"Supply","Supply APY":"Supply APY","Supply apy":"Supply apy","Supply balance":"Supply balance","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","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 more":"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 more","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 error":"There was some error. Please try changing the parameters or <0><1>copy the error","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 forum 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 forum 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 details":"This asset is frozen due to an Aave Protocol Governance decision. <0>More details","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 details":"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 details","This asset is frozen due to an Aave community decision. <0>More details":"This asset is frozen due to an Aave community decision. <0>More details","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 approvedby the community.":"This integration was<0>proposed and approvedby 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 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 Name":"To request access for this permissioned market, please visit: <0>Acces Provider Name","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","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>fluctuate based on the market conditions. Recommended for short-term positions.":"Variable interest rate will <0>fluctuate 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.","Watch-only mode allows to see address positions in Aave, but you won't be able to perform transactions.":"Watch-only mode allows to see address positions in Aave, but you won't be able to perform transactions.","Watch-only mode.":"Watch-only mode.","Watch-only mode. Connect to a wallet to perform transactions.":"Watch-only mode. Connect to a wallet to perform transactions.","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.","Why do I need to approve?":"Why do I need to approve?","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 more":"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 more","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","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>Discord or <1>Github.":"You can report incident to our <0>Discord or <1>Github.","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} to transfer your {network} assets.":["Your ",["name"]," wallet is empty. Purchase or transfer assets or use <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"]],"{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>Ampleforth is a rebasing asset. Visit the <1>documentation to learn more.":"<0>Ampleforth is a rebasing asset. Visit the <1>documentation to learn more.","<0>Attention: Parameter changes via governance can alter your account health factor and risk of liquidation. Follow the <1>Aave governance forum for updates.":"<0>Attention: Parameter changes via governance can alter your account health factor and risk of liquidation. Follow the <1>Aave governance forum for updates.","<0>Slippage tolerance <1>{selectedSlippage}% <2>{0}":["<0>Slippage tolerance <1>",["selectedSlippage"],"% <2>",["0"],""],"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>variable and <1>stable 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>variable and <1>stable 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.","Approval":"Approval","Approve confirmed":"Approve confirmed","Approve to continue":"Approve to continue","Approved":"Approved","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","Before supplying, you need to approve its usage by the Aave protocol. You can learn more in our <0>FAQ":"Before supplying, you need to approve its usage by the Aave protocol. You can learn more in our <0>FAQ","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 details":"Borrowing is disabled due to an Aave community decision. <0>More details","Borrowing is not enabled":"Borrowing is not enabled","Borrowing is unavailable because you’re using Isolation mode. To manage Isolation mode visit your <0>Dashboard.":"Borrowing is unavailable because you’re using Isolation mode. To manage Isolation mode visit your <0>Dashboard.","Borrowing is unavailable because you’ve enabled Efficiency Mode (E-Mode) and Isolation mode. To manage E-Mode and Isolation mode visit your <0>Dashboard.":"Borrowing is unavailable because you’ve enabled Efficiency Mode (E-Mode) and Isolation mode. To manage E-Mode and Isolation mode visit your <0>Dashboard.","Borrowing is unavailable because you’ve enabled Efficiency Mode (E-Mode) for {0} category. To manage E-Mode categories visit your <0>Dashboard.":["Borrowing is unavailable because you’ve enabled Efficiency Mode (E-Mode) for ",["0"]," category. To manage E-Mode categories visit your <0>Dashboard."],"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 More":"Collateral usage is limited because of isolation mode. <0>Learn More","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.","Define Retry with Approval text":"Define Retry with Approval text","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 more":"E-Mode increases your LTV for a selected category of assets up to 97%. <0>Learn more","E-Mode increases your LTV for a selected category of assets up to<0/>. <1>Learn more":"E-Mode increases your LTV for a selected category of assets up to<0/>. <1>Learn more","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>Dashboard. To learn more about E-Mode and applied restrictions in <1>FAQ or <2>Aave V3 Technical Paper.":"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>Dashboard. To learn more about E-Mode and applied restrictions in <1>FAQ or <2>Aave V3 Technical Paper.","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 guide 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 guide 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 address to track in watch-only mode":"Enter an address to track in watch-only mode","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>FAQ":["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>FAQ"],"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 guide":"Learn more in our <0>FAQ guide","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 FAQ":"Need help connecting a wallet? <0>Read our FAQ","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","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","Retry What?":"Retry What?","Retry with Approval":"Retry with Approval","Retry with approval":"Retry with approval","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>Dashboard":"Since this asset is frozen, the only available actions are withdraw and repay which can be accessed from the <0>Dashboard","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 same 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 same 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 more":"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 more","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 error":"There was some error. Please try changing the parameters or <0><1>copy the error","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 forum 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 forum 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 details":"This asset is frozen due to an Aave Protocol Governance decision. <0>More details","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 details":"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 details","This asset is frozen due to an Aave community decision. <0>More details":"This asset is frozen due to an Aave community decision. <0>More details","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 approvedby the community.":"This integration was<0>proposed and approvedby 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 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 Name":"To request access for this permissioned market, please visit: <0>Acces Provider Name","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","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>fluctuate based on the market conditions. Recommended for short-term positions.":"Variable interest rate will <0>fluctuate 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.","Watch-only mode allows to see address positions in Aave, but you won't be able to perform transactions.":"Watch-only mode allows to see address positions in Aave, but you won't be able to perform transactions.","Watch-only mode.":"Watch-only mode.","Watch-only mode. Connect to a wallet to perform transactions.":"Watch-only mode. Connect to a wallet to perform transactions.","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.","Why do I need to approve?":"Why do I need to approve?","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 more":"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 more","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>Discord or <1>Github.":"You can report incident to our <0>Discord or <1>Github.","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} to transfer your {network} assets.":["Your ",["name"]," wallet is empty. Purchase or transfer assets or use <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"]],"{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 24337c73e5..fe4fbb5e7e 100644 --- a/src/locales/en/messages.po +++ b/src/locales/en/messages.po @@ -21,6 +21,10 @@ msgstr "<0>Ampleforth is a rebasing asset. Visit the <1>documentation to msgid "<0>Attention: Parameter changes via governance can alter your account health factor and risk of liquidation. Follow the <1>Aave governance forum for updates." msgstr "<0>Attention: Parameter changes via governance can alter your account health factor and risk of liquidation. Follow the <1>Aave governance forum for updates." +#: src/modules/dashboard/lists/SlippageList.tsx +msgid "<0>Slippage tolerance <1>{selectedSlippage}% <2>{0}" +msgstr "<0>Slippage tolerance <1>{selectedSlippage}% <2>{0}" + #: src/modules/staking/StakingHeader.tsx msgid "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." msgstr "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." @@ -322,6 +326,10 @@ msgstr "Borrow and repay in same block is not allowed" msgid "Borrow balance" msgstr "Borrow balance" +#: src/components/transactions/Repay/CollateralRepayModalContent.tsx +msgid "Borrow balance after repay" +msgstr "Borrow balance after repay" + #: src/modules/reserve-overview/BorrowInfo.tsx msgid "Borrow cap" msgstr "Borrow cap" @@ -402,6 +410,7 @@ msgstr "CLAIM {symbol}" msgid "CLAIMING {symbol}" msgstr "CLAIMING {symbol}" +#: src/components/transactions/Swap/SwapModalDetails.tsx #: src/modules/dashboard/lists/SupplyAssetsList/SupplyAssetsList.tsx #: src/modules/dashboard/lists/SupplyAssetsList/SupplyAssetsListMobileItem.tsx #: src/modules/reserve-overview/SupplyInfo.tsx @@ -474,13 +483,17 @@ msgid "Collateral" msgstr "Collateral" #: src/components/transactions/Repay/CollateralRepayModalContent.tsx -msgid "Collateral amount to repay with" -msgstr "Collateral amount to repay with" +msgid "Collateral balance after repay" +msgstr "Collateral balance after repay" #: src/ui-config/errorMapping.tsx msgid "Collateral is (mostly) the same currency that is being borrowed" msgstr "Collateral is (mostly) the same currency that is being borrowed" +#: src/components/transactions/Repay/CollateralRepayModalContent.tsx +msgid "Collateral to repay with" +msgstr "Collateral to repay with" + #: src/modules/reserve-overview/SupplyInfo.tsx #: src/modules/reserve-overview/SupplyInfo.tsx #: src/modules/reserve-overview/SupplyInfo.tsx @@ -579,10 +592,6 @@ msgstr "Data couldn't be fetched, please reload graph." msgid "Debt" msgstr "Debt" -#: src/components/transactions/Repay/CollateralRepayModalContent.tsx -msgid "Debt amount to repay" -msgstr "Debt amount to repay" - #: src/ui-config/errorMapping.tsx msgid "Debt ceiling is exceeded" msgstr "Debt ceiling is exceeded" @@ -771,6 +780,10 @@ msgstr "Error connecting. Try refreshing the page." msgid "Executed" msgstr "Executed" +#: src/components/transactions/Repay/CollateralRepayModalContent.tsx +msgid "Expected amount to repay" +msgstr "Expected amount to repay" + #: src/modules/governance/FormattedProposalTime.tsx msgid "Expires" msgstr "Expires" @@ -796,6 +809,10 @@ msgstr "Faucet" msgid "Faucet {0}" msgstr "Faucet {0}" +#: src/components/transactions/TxActionsWrapper.tsx +msgid "Fetching data..." +msgstr "Fetching data..." + #: src/modules/governance/ProposalsList.tsx msgid "Filter" msgstr "Filter" @@ -1011,6 +1028,7 @@ msgstr "Liquidation risk" msgid "Liquidation risk parameters" msgstr "Liquidation risk parameters" +#: src/components/transactions/Swap/SwapModalDetails.tsx #: src/modules/reserve-overview/ReserveConfiguration.tsx #: src/modules/reserve-overview/SupplyInfo.tsx msgid "Liquidation threshold" @@ -1054,11 +1072,6 @@ msgstr "Max LTV" msgid "Max slashing" msgstr "Max slashing" -#: src/components/transactions/Repay/CollateralRepayModalContent.tsx -#: src/components/transactions/Swap/SwapModalContent.tsx -msgid "Max slippage rate" -msgstr "Max slippage rate" - #: src/components/transactions/Warnings/DebtCeilingWarning.tsx msgid "Maximum amount available to borrow against this asset is limited because debt ceiling is at {0}%." msgstr "Maximum amount available to borrow against this asset is limited because debt ceiling is at {0}%." @@ -1084,11 +1097,6 @@ msgstr "Maximum loan to value" msgid "Menu" msgstr "Menu" -#: src/components/transactions/Repay/CollateralRepayModalContent.tsx -#: src/components/transactions/Swap/SwapModalContent.tsx -msgid "Minimum received" -msgstr "Minimum received" - #: src/layouts/MoreMenu.tsx msgid "More" msgstr "More" @@ -1129,6 +1137,10 @@ msgstr "Network not supported for this wallet" msgid "New APY" msgstr "New APY" +#: src/components/transactions/Swap/SwapModalDetails.tsx +msgid "No" +msgstr "No" + #: src/components/transactions/StakeRewardClaim/StakeRewardClaimModalContent.tsx msgid "No rewards to claim" msgstr "No rewards to claim" @@ -1144,6 +1156,7 @@ msgstr "No voting power" #: src/components/transactions/Emode/EmodeModalContent.tsx #: src/components/transactions/Emode/EmodeModalContent.tsx +#: src/components/transactions/FlowCommons/TxModalDetails.tsx msgid "None" msgstr "None" @@ -1255,10 +1268,17 @@ msgstr "Please, connect your wallet" msgid "Pool addresses provider is not registered" msgstr "Pool addresses provider is not registered" -#: src/components/transactions/Repay/CollateralRepayModalContent.tsx -#: src/components/transactions/Swap/SwapModalContent.tsx -msgid "Price impact" -msgstr "Price impact" +#: src/modules/dashboard/lists/SlippageList.tsx +msgid "Powered by" +msgstr "Powered by" + +#: 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." + +#: src/components/infoTooltips/PriceImpactTooltip.tsx +msgid "Price impact {0}%" +msgstr "Price impact {0}%" #: pages/governance/proposal/[proposalId].governance.tsx msgid "Proposal details" @@ -1335,7 +1355,6 @@ msgstr "Reload" msgid "Reload the page" msgstr "Reload the page" -#: src/components/transactions/Repay/CollateralRepayModalContent.tsx #: src/components/transactions/Repay/RepayModalContent.tsx msgid "Remaining debt" msgstr "Remaining debt" @@ -1344,6 +1363,10 @@ msgstr "Remaining debt" msgid "Remaining supply" msgstr "Remaining supply" +#: src/components/transactions/Repay/CollateralRepayModalContent.tsx +msgid "Repaid" +msgstr "Repaid" + #: src/components/transactions/Repay/RepayModal.tsx #: src/modules/dashboard/lists/BorrowedPositionsList/BorrowedPositionsListItem.tsx #: src/modules/dashboard/lists/BorrowedPositionsList/BorrowedPositionsListMobileItem.tsx @@ -1354,6 +1377,7 @@ msgstr "Repay" msgid "Repay with" msgstr "Repay with" +#: src/components/transactions/Repay/CollateralRepayActions.tsx #: src/components/transactions/Repay/CollateralRepayActions.tsx #: src/components/transactions/Repay/RepayActions.tsx msgid "Repay {symbol}" @@ -1444,6 +1468,10 @@ msgstr "Select APY type to switch" msgid "Select language" msgstr "Select language" +#: src/modules/dashboard/lists/SlippageList.tsx +msgid "Select slippage tolerance" +msgstr "Select slippage tolerance" + #: src/modules/reserve-overview/AddTokenDropdown.tsx msgid "Select token to add" msgstr "Select token to add" @@ -1476,6 +1504,10 @@ msgstr "Since this asset is frozen, the only available actions are withdraw and msgid "Since this is a test network, you can get any of the assets if you have ETH on your wallet" msgstr "Since this is a test network, you can get any of the assets if you have ETH on your wallet" +#: src/components/infoTooltips/SlippageTooltip.tsx +msgid "Slippage is the difference between the quoted and received amounts from changing market conditions between the moment the transaction is submitted and its verification." +msgstr "Slippage is the difference between the quoted and received amounts from changing market conditions between the moment the transaction is submitted and its verification." + #: pages/500.page.tsx #: src/modules/reserve-overview/graphs/ApyGraphContainer.tsx msgid "Something went wrong" @@ -1577,6 +1609,10 @@ msgstr "State" msgid "Supplied" msgstr "Supplied" +#: src/components/transactions/Swap/SwapModalContent.tsx +msgid "Supplied asset amount" +msgstr "Supplied asset amount" + #: pages/index.page.tsx #: src/components/transactions/Supply/SupplyModal.tsx #: src/modules/dashboard/lists/SuppliedPositionsList/SuppliedPositionsListItem.tsx @@ -1595,7 +1631,7 @@ msgstr "Supply" msgid "Supply APY" msgstr "Supply APY" -#: src/components/transactions/Swap/SwapModalContent.tsx +#: src/components/transactions/Swap/SwapModalDetails.tsx msgid "Supply apy" msgstr "Supply apy" @@ -1608,6 +1644,10 @@ msgstr "Supply apy" msgid "Supply balance" msgstr "Supply balance" +#: src/components/transactions/Swap/SwapModalDetails.tsx +msgid "Supply balance after swap" +msgstr "Supply balance after swap" + #: src/ui-config/errorMapping.tsx msgid "Supply cap is exceeded" msgstr "Supply cap is exceeded" @@ -1628,6 +1668,7 @@ msgstr "Supplying your" msgid "Supplying {symbol}" msgstr "Supplying {symbol}" +#: src/components/transactions/Swap/SwapActions.tsx #: src/components/transactions/Swap/SwapActions.tsx #: src/components/transactions/Swap/SwapModal.tsx #: src/modules/dashboard/lists/SuppliedPositionsList/SuppliedPositionsListItem.tsx @@ -1635,6 +1676,10 @@ msgstr "Supplying {symbol}" msgid "Swap" msgstr "Swap" +#: src/components/transactions/Swap/SwapModalContent.tsx +msgid "Swap to" +msgstr "Swap to" + #: src/components/transactions/Swap/SwapModalContent.tsx msgid "Swapped" msgstr "Swapped" @@ -2158,6 +2203,10 @@ msgstr "Wrong Network" msgid "YAE" msgstr "YAE" +#: src/components/transactions/Swap/SwapModalDetails.tsx +msgid "Yes" +msgstr "Yes" + #: src/components/transactions/Warnings/IsolationModeWarning.tsx msgid "You are entering Isolation mode" msgstr "You are entering Isolation mode" @@ -2323,7 +2372,6 @@ msgstr "on" msgid "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." msgstr "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." -#: src/components/transactions/Repay/CollateralRepayModalContent.tsx #: src/components/transactions/Repay/RepayModalContent.tsx msgid "repaid" msgstr "repaid" diff --git a/src/locales/es/messages.po b/src/locales/es/messages.po index 3b3e7d26d7..3cdab718a6 100644 --- a/src/locales/es/messages.po +++ b/src/locales/es/messages.po @@ -764,6 +764,10 @@ msgstr "Introduce la dirección ETH" msgid "Enter an address to track in watch-only mode" msgstr "Introduce una dirección para rastrear en modo de solo lectura" +#: src/components/WalletConnection/WalletSelector.tsx +msgid "Enter an address to track in watch-only mode" +msgstr "Introduce una dirección para rastrear en modo de solo lectura" + #: src/components/transactions/TxActionsWrapper.tsx msgid "Enter an amount" msgstr "Ingresa una cantidad" @@ -963,6 +967,10 @@ msgstr "Los activos aislados han limitado tu capacidad de préstamo y otros acti msgid "Join the community discussion" msgstr "Únete a la discusión de la comunidad" +#: src/components/transactions/Warnings/MarketWarning.tsx +msgid "Join the community discussion" +msgstr "Únete a la discusión de la comunidad" + #: src/layouts/components/LanguageSwitcher.tsx msgid "Language" msgstr "Idioma" @@ -1247,6 +1255,10 @@ msgstr "Por favor, conecta tu cartera para ver tus suministros, préstamos y pos msgid "Please enter a valid wallet address." msgstr "Por favor introduce una dirección de cartera válida." +#: src/components/WalletConnection/WalletSelector.tsx +msgid "Please enter a valid wallet address." +msgstr "Por favor introduce una dirección de cartera válida." + #: src/components/transactions/Warnings/ChangeNetworkWarning.tsx msgid "Please switch to {networkName}." msgstr "Por favor, cambia a {networkName}." diff --git a/src/modules/dashboard/lists/BorrowedPositionsList/BorrowedPositionsListItem.tsx b/src/modules/dashboard/lists/BorrowedPositionsList/BorrowedPositionsListItem.tsx index a1ef0fa819..6a23294879 100644 --- a/src/modules/dashboard/lists/BorrowedPositionsList/BorrowedPositionsListItem.tsx +++ b/src/modules/dashboard/lists/BorrowedPositionsList/BorrowedPositionsListItem.tsx @@ -78,7 +78,7 @@ export const BorrowedPositionsListItem = ({ diff --git a/src/modules/dashboard/lists/BorrowedPositionsList/BorrowedPositionsListMobileItem.tsx b/src/modules/dashboard/lists/BorrowedPositionsList/BorrowedPositionsListMobileItem.tsx index b6c24b8659..bcd7843098 100644 --- a/src/modules/dashboard/lists/BorrowedPositionsList/BorrowedPositionsListMobileItem.tsx +++ b/src/modules/dashboard/lists/BorrowedPositionsList/BorrowedPositionsListMobileItem.tsx @@ -87,7 +87,7 @@ export const BorrowedPositionsListMobileItem = ({