Skip to content

Commit

Permalink
♻️ rollover: rework allowance
Browse files Browse the repository at this point in the history
  • Loading branch information
jgalat committed Sep 21, 2023
1 parent f6d6e71 commit 6005b69
Show file tree
Hide file tree
Showing 9 changed files with 29 additions and 60 deletions.
24 changes: 6 additions & 18 deletions components/DebtManager/Operation/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useTranslation } from 'react-i18next';
import ArrowForwardRoundedIcon from '@mui/icons-material/ArrowForwardRounded';
import { usePublicClient, useSignTypedData } from 'wagmi';
import dayjs from 'dayjs';
import { formatUnits, Hex, isAddress, parseUnits, parseEther, trim, pad } from 'viem';
import { formatUnits, Hex, isAddress, parseUnits, parseEther, trim, pad, encodeFunctionData } from 'viem';
import { splitSignature } from '@ethersproject/bytes';

import { ModalBox, ModalBoxRow } from 'components/common/modal/ModalBox';
Expand Down Expand Up @@ -270,26 +270,14 @@ function Operation() {
const raw = input.slippage || '0';
const slippage = WEI_PER_ETHER + parseEther(raw) / 100n;

const ret: [bigint, bigint] = [0n, 0n];
if (!fromRow || !toRow) {
return ret;
return [0n, 0n];
}

const fromBalance = fromRow.balance ? (fromRow.balance * BigInt(input.percent)) / 100n : 0n;
const toBalance = toRow.balance ? toRow.balance : fromBalance;

if (fromRow.maturity) {
ret[0] = (fromBalance * slippage) / WEI_PER_ETHER;
} else {
ret[0] = fromBalance;
}

if (toRow.maturity) {
ret[1] = toRow.balance ? (toRow.balance * slippage) / WEI_PER_ETHER : 0n;
} else {
ret[1] = fromBalance;
}

return ret;
return [(fromBalance * slippage) / WEI_PER_ETHER, (toBalance * slippage) / WEI_PER_ETHER];
}, [input.slippage, input.percent, fromRow, toRow]);

const [requiresApproval, setRequiresApproval] = useState(false);
Expand Down Expand Up @@ -369,7 +357,7 @@ function Operation() {
message: {
owner: walletAddress,
spender: debtManager.address,
value: input.from.maturity && !input.to.maturity ? maxRepayAssets : maxBorrowAssets, // TODO: check for partial repay
value: await marketContract.read.previewWithdraw([maxBorrowAssets]),
nonce: marketNonce,
deadline,
},
Expand All @@ -378,7 +366,7 @@ function Operation() {
const permit = {
account: walletAddress,
deadline,
value: input.from.maturity && !input.to.maturity ? maxRepayAssets : maxBorrowAssets, // TODO: check for partial repay
value: await marketContract.read.previewWithdraw([maxBorrowAssets]),
...{ v, r: r as Hex, s: s as Hex },
} as const;

Expand Down
16 changes: 4 additions & 12 deletions components/dashboard/DashboardContent/DashboardMobile/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,13 @@ import useAccountData from 'hooks/useAccountData';
import { useTranslation } from 'react-i18next';
import useAnalytics from 'hooks/useAnalytics';
import Rates from 'components/Rates';
import { useWeb3 } from 'hooks/useWeb3';

type Props = {
type: 'deposit' | 'borrow';
};

const DashboardMobile: FC<Props> = ({ type }) => {
const { t } = useTranslation();
const { disableFeature } = useWeb3();
const { accountData, getMarketAccount } = useAccountData();
const { handleActionClick } = useActionButton();
const { startDebtManager, isRolloverDisabled } = useStartDebtManagerButton();
Expand Down Expand Up @@ -124,15 +122,12 @@ const DashboardMobile: FC<Props> = ({ type }) => {
height: '34px',
'&:disabled': {
borderLeftColor: ({ palette }) => palette.grey[palette.mode === 'light' ? 500 : 300],
pointerEvents: disableFeature ? 'auto' : 'none',
},
}}
onClick={() => startDebtManager({ from: { symbol } })}
disabled={disableFeature || isRolloverDisabled(borrowedAmount)}
disabled={isRolloverDisabled(borrowedAmount)}
>
<Tooltip title={disableFeature ? t('Temporary disabled') : ''} arrow placement="top">
<span>{t('Rollover')}</span>
</Tooltip>
{t('Rollover')}
</Button>
</ButtonGroup>
)}
Expand Down Expand Up @@ -217,15 +212,12 @@ const DashboardMobile: FC<Props> = ({ type }) => {
height: '34px',
'&:disabled': {
borderLeftColor: ({ palette }) => palette.grey[palette.mode === 'light' ? 500 : 300],
pointerEvents: disableFeature ? 'auto' : 'none',
},
}}
onClick={() => startDebtManager({ from: { symbol, maturity } })}
disabled={disableFeature || isRolloverDisabled()}
disabled={isRolloverDisabled()}
>
<Tooltip title={disableFeature ? t('Temporary disabled') : ''} arrow placement="top">
<span>{t('Rollover')}</span>
</Tooltip>
{t('Rollover')}
</Button>
</ButtonGroup>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import { Borrow } from 'types/Borrow';
import { Repay } from 'types/Repay';
import useAccountData from 'hooks/useAccountData';
import useRouter from 'hooks/useRouter';
import { useWeb3 } from 'hooks/useWeb3';

type Props = {
symbol: string;
Expand All @@ -47,7 +46,6 @@ type Props = {

function TableRowFixedPool({ symbol, valueUSD, type, maturityDate, market, decimals }: Props) {
const { t } = useTranslation();
const { disableFeature } = useWeb3();
const { query } = useRouter();
const { marketAccount } = useAccountData(symbol);
const { withdrawTxs, repayTxs, depositTxs, borrowTxs } = useFixedOperation(type, maturityDate, market);
Expand Down Expand Up @@ -178,15 +176,12 @@ function TableRowFixedPool({ symbol, valueUSD, type, maturityDate, market, decim
whiteSpace: 'nowrap',
'&:disabled': {
borderLeftColor: ({ palette }) => palette.grey[palette.mode === 'light' ? 500 : 300],
pointerEvents: disableFeature ? 'auto' : 'none',
},
}}
onClick={() => startDebtManager({ from: { symbol, maturity: maturityDate } })}
disabled={disableFeature || isRolloverDisabled()}
disabled={isRolloverDisabled()}
>
<Tooltip title={disableFeature ? t('Temporary disabled') : ''} arrow placement="top">
<span>{t('Rollover')}</span>
</Tooltip>
{t('Rollover')}
</Button>
</ButtonGroup>
))) || (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';
import Image from 'next/image';
import { formatUnits } from 'viem';

import { Button, TableRow, TableCell, Stack, Typography, Skeleton, Box, ButtonGroup, Tooltip } from '@mui/material';
import { Button, TableRow, TableCell, Stack, Typography, Skeleton, Box, ButtonGroup } from '@mui/material';

import type { Operation } from 'types/Operation';

Expand All @@ -15,7 +15,6 @@ import useActionButton, { useStartDebtManagerButton } from 'hooks/useActionButto
import useRouter from 'hooks/useRouter';
import { useTranslation } from 'react-i18next';
import Rates from 'components/Rates';
import { useWeb3 } from 'hooks/useWeb3';

type Props = {
symbol: string;
Expand All @@ -30,7 +29,6 @@ function TableRowFloatingPool({ symbol, valueUSD, depositedAmount, borrowedAmoun
const { t } = useTranslation();
const { query } = useRouter();
const { marketAccount } = useAccountData(symbol);
const { disableFeature } = useWeb3();

const { handleActionClick } = useActionButton();
const { startDebtManager, isRolloverDisabled } = useStartDebtManagerButton();
Expand Down Expand Up @@ -126,15 +124,12 @@ function TableRowFloatingPool({ symbol, valueUSD, depositedAmount, borrowedAmoun
whiteSpace: 'nowrap',
'&:disabled': {
borderLeftColor: ({ palette }) => palette.grey[palette.mode === 'light' ? 500 : 300],
pointerEvents: disableFeature ? 'auto' : 'none',
},
}}
onClick={() => startDebtManager({ from: { symbol } })}
disabled={disableFeature || isRolloverDisabled(borrowedAmount)}
disabled={isRolloverDisabled(borrowedAmount)}
>
<Tooltip title={disableFeature ? t('Temporary disabled') : ''} arrow placement="top">
<span>{t('Rollover')}</span>
</Tooltip>
{t('Rollover')}
</Button>
</ButtonGroup>
)}
Expand Down
14 changes: 8 additions & 6 deletions contexts/DebtManagerContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import type { ErrorData } from 'types/Error';
import type { PopulatedTransaction, Transaction } from 'types/Transaction';
import type { Position } from 'components/DebtManager/types';
import useDebtManager from 'hooks/useDebtManager';
import numbers from 'config/numbers.json';
import useAccountData from 'hooks/useAccountData';
import useMarket from 'hooks/useMarket';
import { useWeb3 } from 'hooks/useWeb3';
Expand Down Expand Up @@ -43,7 +42,7 @@ export function isRolloverInput(input: unknown): input is RolloverInput {
);
}

const DEFAULT_SLIPPAGE = (numbers.slippage * 100).toFixed(2);
const DEFAULT_SLIPPAGE = '0.01';

const initState: RolloverInput = {
from: undefined,
Expand Down Expand Up @@ -109,9 +108,12 @@ export const DebtManagerContextProvider: FC<PropsWithChildren<Props>> = ({ args,
async (qty: bigint): Promise<boolean> => {
if (!walletAddress || !market || !debtManager || !opts || qty === 0n) return true;
try {
if (!(await isContract(walletAddress))) return false;
const isMultiSig = await isContract(walletAddress);
if (!isMultiSig) return false;

const shares = await market.read.previewWithdraw([qty], opts);
const allowance = await market.read.allowance([walletAddress, debtManager.address], opts);
return allowance <= qty;
return allowance < shares;
} catch (e: unknown) {
setErrorData({ status: true, message: handleOperationError(e) });
return true;
Expand All @@ -121,12 +123,12 @@ export const DebtManagerContextProvider: FC<PropsWithChildren<Props>> = ({ args,
);

const approve = useCallback(
async (maxAssets: bigint) => {
async (assets: bigint) => {
if (!debtManager || !market || !opts) return;

setIsLoading(true);
try {
const max = (maxAssets * 100_005n) / 100_000n;
const max = await market.read.previewWithdraw([(assets * 100_005n) / 100_000n], opts);
const gasEstimation = await market.estimateGas.approve([debtManager.address, max], opts);
const hash = await market.write.approve([debtManager.address, max], {
...opts,
Expand Down
4 changes: 2 additions & 2 deletions contexts/LeveragerContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -592,7 +592,7 @@ export const LeveragerContextProvider: FC<PropsWithChildren> = ({ children }) =>
if (marketOutAllownce < borrowShares) return true;
} else {
setApprovalStatus('MARKET-IN');
const marketInAllownce = await marketIn.read.allowance([walletAddress, debtManager.address], opts);
const marketInAllowance = await marketIn.read.allowance([walletAddress, debtManager.address], opts);
const _slippage =
(maIn.floatingBorrowAssets * ((maIn.floatingBorrowRate * 300n) / 31_536_000n)) / WEI_PER_ETHER;
const permitShares = await marketIn.read.previewWithdraw(
Expand All @@ -603,7 +603,7 @@ export const LeveragerContextProvider: FC<PropsWithChildren> = ({ children }) =>
],
opts,
);
if (marketInAllownce < permitShares) return true;
if (marketInAllowance < permitShares) return true;
}

setApprovalStatus('APPROVED');
Expand Down
4 changes: 0 additions & 4 deletions hooks/useWeb3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ type Web3 = {
walletAddress?: Address;
chain: Chain;
subgraphURL?: string;
disableFeature: boolean;
opts?: {
account: Address;
chain: Chain;
Expand Down Expand Up @@ -60,8 +59,6 @@ export const useWeb3 = (): Web3 => {
[walletAddress, connector?.id],
);

const disableFeature = true;

return {
connect: connectWallet,
isConnected,
Expand All @@ -70,7 +67,6 @@ export const useWeb3 = (): Web3 => {
walletAddress,
chain: defaultChain,
subgraphURL,
disableFeature,
opts,
};
};
5 changes: 2 additions & 3 deletions i18n/es/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,6 @@
"Take control of your investments with strategies that balance risk and reward for long-term success.": "Toma control de tus inversiones con estrategias que equilibren el riesgo y la recompensa para el éxito a largo plazo.",
"You are currently over leveraged with the selected markets.": "Actualmente estás sobre apalancado con los mercados seleccionados.",
"The APR displayed comes from the Lido API.": "La TNA proviene de la API de Lido.",
"Price impact is above {{ threshold }}, operation is too risky.": "El impacto en el precio está por encima de {{ threshold }}, la operación es demasiado riesgosa.",
"You have no voting power in your connected wallet.": "No tienes poder de voto en tu billetera conectada.",
"Revoke delegation": "Revocar delegación",
"Withdraw {{ value }} EXA": "Retirar {{ value }} EXA",
Expand All @@ -375,7 +374,6 @@
"Provide liquidity": "Proporcionar liquidez",
"Net APR": "TNA Neta",
"Your Account": "Tu Cuenta",
"Temporary disabled": "Temporalmente deshabilitado",
"Deposit EXA on Extra Finance and get {{apy}} APY": "Deposita EXA en Extra Finance y obtén {{apy}} TEA",
"Deposit EXA": "Deposite EXA",
"No approvals found!": "¡No se encontraron permisos!",
Expand Down Expand Up @@ -466,5 +464,6 @@
"Theme": "Tema",
"Language": "Idioma",
"Settings": "Configuración",
"The Health Factor represents how “safe” your leverage portfolio is, defined as the risk-adjusted proportion of collateral deposited versus the borrowed risk-adjusted amount. A health factor below 1x will be considered with a shortfall and open to liquidation.": "El Factor de Salud representa cuán “seguro“ es tu portafolio con apalancamiento, definido como la proporción ajustada al riesgo del colateral depositado frente al monto ajustado al riesgo que se ha tomado prestado. Un factor de salud por debajo de 1x se considerará con un déficit y estará abierto a la liquidación."
"The Health Factor represents how “safe” your leverage portfolio is, defined as the risk-adjusted proportion of collateral deposited versus the borrowed risk-adjusted amount. A health factor below 1x will be considered with a shortfall and open to liquidation.": "El Factor de Salud representa cuán “seguro“ es tu portafolio con apalancamiento, definido como la proporción ajustada al riesgo del colateral depositado frente al monto ajustado al riesgo que se ha tomado prestado. Un factor de salud por debajo de 1x se considerará con un déficit y estará abierto a la liquidación.",
"Token allowance surplus after operation": "Excedente de permisos de token luego de la operación"
}
2 changes: 2 additions & 0 deletions utils/handleOperationError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ function parse(name?: string): string {
return i18n.t('There is not enough liquidity in your account');
case 'InsufficientProtocolLiquidity':
return i18n.t('There is not enough liquidity in the protocol');
case 'AllowanceSurplus':
return i18n.t('Token allowance surplus after operation');
case 'Disagreement':
return i18n.t('Not enough slippage');
case 'InvalidPrice':
Expand Down

0 comments on commit 6005b69

Please sign in to comment.