Skip to content

Commit

Permalink
feat: paraswap permit (#1399)
Browse files Browse the repository at this point in the history
* feat: add permit params to paraswap methods in poolSlice

* feat: update paraswap actions and transaction handler to support permit

* feat: add utility for calculating signature amount for aToken

* feat: add signature request helper function to slice

* feat: configure paraswap tx handler to support permit

* feat: update repay with collateral action with permit parameters

* feat: update collateral swap action with permit parameters

* feat: add comments

* feat: add slippage and amount tip for Paraswap gas estimation error

* chore: run i18n

* feat: export variable for percentage increase of signature amount

* fix: use collateral asset in useEffect depedency for collateral swap

* feat: correctly display approval and error states based on dependency changes

* chore: update range for re-using signature on amount update

* fix: swap and collateral repay tests by tx approve

* chore: remove console log

Co-authored-by: NikitaY <right2maresko@gmail.com>
  • Loading branch information
defispartan and MareskoY authored Jan 18, 2023
1 parent 74bd1ac commit fe8a113
Show file tree
Hide file tree
Showing 13 changed files with 303 additions and 37 deletions.
15 changes: 14 additions & 1 deletion cypress/support/steps/main.steps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,9 +231,10 @@ export const repay = (
break;
}
});

if (repayableAsset) {
it(`Choose ${repayableAsset.shortName} as option to repay`, () => {
cy.get('[data-cy=Modal] ').as('Modal');
cy.get('[data-cy=Modal]').as('Modal');
cy.get('@Modal').get('[data-cy=assetSelect]').click();
cy.get('@Modal')
.get(`[data-cy='assetsSelectOption_${repayableAsset.shortName.toUpperCase()}']`)
Expand All @@ -245,6 +246,13 @@ export const repay = (
isMaxAmount ? 'MAX' : amount
} amount for ${_shortName}, with ${repayOption} repay option`, () => {
cy.setAmount(amount, isMaxAmount);
if (repayOption == constants.repayType.collateral) {
cy.get('[data-cy=Modal]')
.find('[data-cy=approveButtonChange]')
.click()
.get('[data-cy=approveOption_Transaction]')
.click();
}
cy.doConfirm(hasApproval, _actionName, _shortName);
});
doCloseModal();
Expand Down Expand Up @@ -440,6 +448,11 @@ export const swap = (
});
it(`Make approve for ${isMaxAmount ? 'MAX' : amount} amount`, () => {
cy.setAmount(amount, isMaxAmount);
cy.get('[data-cy=Modal]')
.find('[data-cy=approveButtonChange]')
.click()
.get('[data-cy=approveOption_Transaction]')
.click();
cy.wait(2000);
cy.doConfirm(hasApproval, _actionName);
});
Expand Down
11 changes: 2 additions & 9 deletions scripts/populate-cache.js
Original file line number Diff line number Diff line change
Expand Up @@ -11252,15 +11252,8 @@ var require_base = __commonJS({
comb[2] = points[a].toJ().mixedAdd(points[b].neg());
}
var index = [
-3, /* -1 -1 */
-1, /* -1 0 */
-5, /* -1 1 */
-7, /* 0 -1 */
0, /* 0 0 */
7, /* 0 1 */
5, /* 1 -1 */
1, /* 1 0 */
3,
-3 /* -1 -1 */, -1 /* -1 0 */, -5 /* -1 1 */, -7 /* 0 -1 */, 0 /* 0 0 */, 7 /* 0 1 */,
5 /* 1 -1 */, 1 /* 1 0 */, 3,
/* 1 1 */
];
var jsf = getJSF(coeffs[a], coeffs[b]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@ export const ApprovalMethodToggleButton = ({

return (
<>
<Box onClick={handleClick} sx={{ display: 'flex', alignItems: 'center', cursor: 'pointer' }}>
<Box
onClick={handleClick}
sx={{ display: 'flex', alignItems: 'center', cursor: 'pointer' }}
data-cy={`approveButtonChange`}
>
<Typography variant="subheader2" color="info.main">
<Trans>{currentMethod}</Trans>
</Typography>
Expand All @@ -53,6 +57,7 @@ export const ApprovalMethodToggleButton = ({
data-cy={`approveMenu_${currentMethod}`}
>
<MenuItem
data-cy={`approveOption_${ApprovalMethod.PERMIT}`}
selected={currentMethod === ApprovalMethod.PERMIT}
value={ApprovalMethod.PERMIT}
onClick={() => {
Expand All @@ -71,6 +76,7 @@ export const ApprovalMethodToggleButton = ({
</MenuItem>

<MenuItem
data-cy={`approveOption_${ApprovalMethod.APPROVE}`}
selected={currentMethod === ApprovalMethod.APPROVE}
value={ApprovalMethod.APPROVE}
onClick={() => {
Expand Down
26 changes: 20 additions & 6 deletions src/components/transactions/Repay/CollateralRepayActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import {
InterestRate,
ProtocolAction,
} from '@aave/contract-helpers';
import { SignatureLike } from '@ethersproject/bytes';
import { Trans } from '@lingui/macro';
import { BoxProps } from '@mui/material';
import { useParaSwapTransactionHandler } from 'src/helpers/useParaSwapTransactionHandler';
import { ComputedReserveData } from 'src/hooks/app-data-provider/useAppDataProvider';
import { SwapTransactionParams } from 'src/hooks/paraswap/common';
import { calculateSignedAmount, SwapTransactionParams } from 'src/hooks/paraswap/common';
import { useRootStore } from 'src/store/root';

import { TxActionsWrapper } from '../TxActionsWrapper';
Expand All @@ -26,6 +27,9 @@ interface CollateralRepayBaseProps extends BoxProps {
useFlashLoan: boolean;
blocked: boolean;
loading?: boolean;
signature?: SignatureLike;
signedAmount?: string;
deadline?: string;
}

// Used in poolSlice
Expand All @@ -50,11 +54,11 @@ export const CollateralRepayActions = ({
buildTxFn,
...props
}: CollateralRepayBaseProps & { buildTxFn: () => Promise<SwapTransactionParams> }) => {
const paraswapRepayWithCollateral = useRootStore((state) => state.paraswapRepayWithCollateral);
const { paraswapRepayWithCollateral, currentMarketData } = useRootStore();

const { approval, action, requiresApproval, loadingTxns, approvalTxState, mainTxState } =
const { approval, action, loadingTxns, approvalTxState, mainTxState, requiresApproval } =
useParaSwapTransactionHandler({
handleGetTxns: async () => {
handleGetTxns: async (signature, deadline) => {
const route = await buildTxFn();
return paraswapRepayWithCollateral({
repayAllDebt,
Expand All @@ -69,6 +73,9 @@ export const CollateralRepayActions = ({
blocked,
swapCallData: route.swapCallData,
augustus: route.augustus,
signature,
deadline,
signedAmount: calculateSignedAmount(repayWithAmount, fromAssetData.decimals),
});
},
handleGetApprovalTxns: async () => {
Expand All @@ -89,12 +96,13 @@ export const CollateralRepayActions = ({
},
gasLimitRecommendation: gasLimitRecommendations[ProtocolAction.repayCollateral].limit,
skip: loading || !repayAmount || parseFloat(repayAmount) === 0 || blocked,
spender: currentMarketData.addresses.REPAY_WITH_COLLATERAL_ADAPTER ?? '',
deps: [fromAssetData.symbol, repayWithAmount],
});

return (
<TxActionsWrapper
preparingTransactions={loadingTxns}
symbol={fromAssetData.symbol}
mainTxState={mainTxState}
approvalTxState={approvalTxState}
requiresAmount
Expand All @@ -104,7 +112,12 @@ export const CollateralRepayActions = ({
sx={sx}
{...props}
handleAction={action}
handleApproval={() => approval()}
handleApproval={() =>
approval({
amount: calculateSignedAmount(repayWithAmount, fromAssetData.decimals),
underlyingAsset: fromAssetData.aTokenAddress,
})
}
actionText={<Trans>Repay {symbol}</Trans>}
actionInProgressText={<Trans>Repaying {symbol}</Trans>}
fetchingData={loading}
Expand All @@ -114,6 +127,7 @@ export const CollateralRepayActions = ({
content: <Trans>Repay {symbol}</Trans>,
handleClick: action,
}}
tryPermit
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import { ListSlippageButton } from 'src/modules/dashboard/lists/SlippageList';
import { calculateHFAfterRepay } from 'src/utils/hfUtils';

import { Asset, AssetInput } from '../AssetInput';
import { GasEstimationError } from '../FlowCommons/GasEstimationError';
import { ModalWrapperProps } from '../FlowCommons/ModalWrapper';
import { TxSuccessView } from '../FlowCommons/Success';
import {
Expand All @@ -29,6 +28,7 @@ import {
TxModalDetails,
} from '../FlowCommons/TxModalDetails';
import { ErrorType, flashLoanNotAvailable, useFlashloan } from '../utils';
import { ParaswapErrorDisplay } from '../Warnings/ParaswapErrorDisplay';
import { CollateralRepayActions } from './CollateralRepayActions';

export function CollateralRepayModalContent({
Expand Down Expand Up @@ -302,7 +302,7 @@ export function CollateralRepayModalContent({
/>
</TxModalDetails>

{txError && <GasEstimationError txError={txError} />}
{txError && <ParaswapErrorDisplay txError={txError} />}

<CollateralRepayActions
poolReserve={poolReserve}
Expand Down
25 changes: 20 additions & 5 deletions src/components/transactions/Swap/SwapActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ import {
gasLimitRecommendations,
ProtocolAction,
} from '@aave/contract-helpers';
import { SignatureLike } from '@ethersproject/bytes';
import { Trans } from '@lingui/macro';
import { BoxProps } from '@mui/material';
import { useParaSwapTransactionHandler } from 'src/helpers/useParaSwapTransactionHandler';
import { ComputedReserveData } from 'src/hooks/app-data-provider/useAppDataProvider';
import { SwapTransactionParams } from 'src/hooks/paraswap/common';
import { calculateSignedAmount, SwapTransactionParams } from 'src/hooks/paraswap/common';
import { useRootStore } from 'src/store/root';

import { TxActionsWrapper } from '../TxActionsWrapper';
Expand All @@ -24,6 +25,9 @@ interface SwapBaseProps extends BoxProps {
isMaxSelected: boolean;
useFlashLoan: boolean;
loading?: boolean;
signature?: SignatureLike;
deadline?: string;
signedAmount?: string;
}

export interface SwapActionProps extends SwapBaseProps {
Expand All @@ -46,11 +50,11 @@ export const SwapActions = ({
buildTxFn,
...props
}: SwapBaseProps & { buildTxFn: () => Promise<SwapTransactionParams> }) => {
const swapCollateral = useRootStore((state) => state.swapCollateral);
const { swapCollateral, currentMarketData } = useRootStore();

const { approval, action, requiresApproval, approvalTxState, mainTxState, loadingTxns } =
const { approval, action, approvalTxState, mainTxState, loadingTxns, requiresApproval } =
useParaSwapTransactionHandler({
handleGetTxns: async () => {
handleGetTxns: async (signature, deadline) => {
const route = await buildTxFn();
return swapCollateral({
amountToSwap: route.inputAmount,
Expand All @@ -64,6 +68,9 @@ export const SwapActions = ({
useFlashLoan,
swapCallData: route.swapCallData,
augustus: route.augustus,
signature,
deadline,
signedAmount: calculateSignedAmount(amountToSwap, poolReserve.decimals),
});
},
handleGetApprovalTxns: async () => {
Expand All @@ -83,6 +90,8 @@ export const SwapActions = ({
},
gasLimitRecommendation: gasLimitRecommendations[ProtocolAction.swapCollateral].limit,
skip: loading || !amountToSwap || parseFloat(amountToSwap) === 0,
spender: currentMarketData.addresses.SWAP_COLLATERAL_ADAPTER ?? '',
deps: [targetReserve.symbol, amountToSwap],
});

return (
Expand All @@ -94,7 +103,12 @@ export const SwapActions = ({
handleAction={action}
requiresAmount
amount={amountToSwap}
handleApproval={() => approval()}
handleApproval={() =>
approval({
amount: calculateSignedAmount(amountToSwap, poolReserve.decimals),
underlyingAsset: poolReserve.aTokenAddress,
})
}
requiresApproval={requiresApproval}
actionText={<Trans>Swap</Trans>}
actionInProgressText={<Trans>Swapping</Trans>}
Expand All @@ -106,6 +120,7 @@ export const SwapActions = ({
content: <Trans>Swap</Trans>,
handleClick: action,
}}
tryPermit
{...props}
/>
);
Expand Down
4 changes: 2 additions & 2 deletions src/components/transactions/Swap/SwapModalContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import BigNumber from 'bignumber.js';
import React, { useRef, useState } from 'react';
import { PriceImpactTooltip } from 'src/components/infoTooltips/PriceImpactTooltip';
import { Asset, AssetInput } from 'src/components/transactions/AssetInput';
import { GasEstimationError } from 'src/components/transactions/FlowCommons/GasEstimationError';
import { TxModalDetails } from 'src/components/transactions/FlowCommons/TxModalDetails';
import { useCollateralSwap } from 'src/hooks/paraswap/useCollateralSwap';
import { useModalContext } from 'src/hooks/useModal';
Expand All @@ -22,6 +21,7 @@ import {
import { ModalWrapperProps } from '../FlowCommons/ModalWrapper';
import { TxSuccessView } from '../FlowCommons/Success';
import { ErrorType, flashLoanNotAvailable, useFlashloan } from '../utils';
import { ParaswapErrorDisplay } from '../Warnings/ParaswapErrorDisplay';
import { SwapActions } from './SwapActions';
import { SwapModalDetails } from './SwapModalDetails';

Expand Down Expand Up @@ -237,7 +237,7 @@ export const SwapModalContent = ({
/>
</TxModalDetails>

{txError && <GasEstimationError txError={txError} />}
{txError && <ParaswapErrorDisplay txError={txError} />}

<SwapActions
isMaxSelected={isMaxSelected}
Expand Down
31 changes: 31 additions & 0 deletions src/components/transactions/Warnings/ParaswapErrorDisplay.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Trans } from '@lingui/macro';
import { Box, Typography } from '@mui/material';
import { Warning } from 'src/components/primitives/Warning';
import { TxErrorType } from 'src/ui-config/errorMapping';

import { GasEstimationError } from '../FlowCommons/GasEstimationError';

const USER_DENIED_SIGNATURE = 'MetaMask Message Signature: User denied message signature.';
const USER_DENIED_TRANSACTION = 'MetaMask Message Signature: User denied message signature.';

interface ErrorProps {
txError: TxErrorType;
}
export const ParaswapErrorDisplay: React.FC<ErrorProps> = ({ txError }) => {
return (
<Box>
<GasEstimationError txError={txError} />
{txError.rawError.message !== USER_DENIED_SIGNATURE &&
txError.rawError.message !== USER_DENIED_TRANSACTION && (
<Box sx={{ pt: 4 }}>
<Warning severity="info">
<Typography variant="description">
{' '}
<Trans> Tip: Try increasing slippage or reduce input amount</Trans>
</Typography>
</Warning>
</Box>
)}
</Box>
);
};
Loading

0 comments on commit fe8a113

Please sign in to comment.