Skip to content

Commit

Permalink
fix: undelegate with repay in single tx (#240)
Browse files Browse the repository at this point in the history
  • Loading branch information
Rickk137 authored Apr 13, 2024
1 parent 25b03c6 commit 19f8bf4
Show file tree
Hide file tree
Showing 9 changed files with 223 additions and 12 deletions.
16 changes: 15 additions & 1 deletion liquidity/components/UndelegateModal/UndelegateModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import { useContractErrorParser } from '@snx-v3/useContractErrorParser';
import { ContractError } from '@snx-v3/ContractError';
import { useQueryClient } from '@tanstack/react-query';
import { useNetwork } from '@snx-v3/useBlockchain';
import { useUndelegateBaseAndromeda } from '../../lib/useUndelegateBaseAndromeda';
import { isBaseAndromeda } from '@snx-v3/isBaseAndromeda';

export const UndelegateModalUi: FC<{
amount: Wei;
Expand Down Expand Up @@ -112,6 +114,14 @@ export const UndelegateModal: UndelegateModalProps = ({ onClose, isOpen, liquidi
collateralChange,
currentCollateral: currentCollateral,
});
const { exec: undelegateBaseAndromeda } = useUndelegateBaseAndromeda({
accountId: params.accountId,
poolId: params.poolId,
collateralTypeAddress: liquidityPosition?.tokenAddress,
collateralChange,
currentCollateral: currentCollateral,
liquidityPosition,
});

const { data: CoreProxy } = useCoreProxy();
const errorParserCoreProxy = useContractErrorParser(CoreProxy);
Expand All @@ -123,7 +133,11 @@ export const UndelegateModal: UndelegateModalProps = ({ onClose, isOpen, liquidi
services: {
[ServiceNames.undelegate]: async () => {
try {
await execUndelegate();
if (isBaseAndromeda(network?.id, network?.preset)) {
await undelegateBaseAndromeda();
} else {
await execUndelegate();
}
await queryClient.invalidateQueries({
queryKey: [`${network?.id}-${network?.preset}`, 'LiquidityPosition'],
exact: false,
Expand Down
1 change: 1 addition & 0 deletions liquidity/components/UndelegateModal/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"@snx-v3/ContractError": "workspace:*",
"@snx-v3/ManagePositionContext": "workspace:*",
"@snx-v3/Multistep": "workspace:*",
"@snx-v3/isBaseAndromeda": "workspace:*",
"@snx-v3/useBlockchain": "workspace:*",
"@snx-v3/useCollateralTypes": "workspace:*",
"@snx-v3/useContractErrorParser": "workspace:*",
Expand Down
1 change: 0 additions & 1 deletion liquidity/lib/useClearDebt/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
"@snx-v3/useGasOptions": "workspace:*",
"@snx-v3/useGasPrice": "workspace:*",
"@snx-v3/useGasSpeed": "workspace:*",
"@snx-v3/useUSDProxy": "workspace:*",
"@snx-v3/withERC7412": "workspace:*",
"@synthetixio/wei": "^2.74.4",
"@tanstack/react-query": "^5.8.3",
Expand Down
5 changes: 1 addition & 4 deletions liquidity/lib/useClearDebt/useClearDebt.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,14 @@ import Wei from '@synthetixio/wei';
import { BigNumber, Contract } from 'ethers';
import { getGasPrice } from '@snx-v3/useGasPrice';
import { useGasSpeed } from '@snx-v3/useGasSpeed';
import { useUSDProxy } from '@snx-v3/useUSDProxy';
import { notNil } from '@snx-v3/tsHelpers';
import { withERC7412 } from '@snx-v3/withERC7412';
import { useAllCollateralPriceIds } from '@snx-v3/useAllCollateralPriceIds';
import { fetchPriceUpdates, priceUpdatesToPopulatedTx } from '@snx-v3/fetchPythPrices';
import { useSpotMarketProxy } from '../useSpotMarketProxy';
import { USDC_BASE_MARKET, getRepayerContract } from '@snx-v3/isBaseAndromeda';

const DEBT_REPAYER_ABI = [
export const DEBT_REPAYER_ABI = [
{
inputs: [
{ internalType: 'contract ISynthetixCore', name: 'synthetixCore', type: 'address' },
Expand Down Expand Up @@ -48,7 +47,6 @@ export const useClearDebt = ({
}) => {
const [txnState, dispatch] = useReducer(reducer, initialState);
const { data: CoreProxy } = useCoreProxy();
const { data: UsdProxy } = useUSDProxy();
const { data: SpotMarketProxy } = useSpotMarketProxy();
const { data: collateralPriceIds } = useAllCollateralPriceIds();

Expand All @@ -67,7 +65,6 @@ export const useClearDebt = ({
poolId &&
accountId &&
collateralTypeAddress &&
UsdProxy &&
SpotMarketProxy &&
collateralPriceIds
)
Expand Down
1 change: 1 addition & 0 deletions liquidity/lib/useUndelegateBaseAndromeda/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './useUndelegateBaseAndromeda';
26 changes: 26 additions & 0 deletions liquidity/lib/useUndelegateBaseAndromeda/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "@snx-v3/useUndelegateBaseAndromeda",
"private": true,
"main": "index.ts",
"version": "0.0.1",
"dependencies": {
"@snx-v3/fetchPythPrices": "workspace:*",
"@snx-v3/format": "workspace:*",
"@snx-v3/isBaseAndromeda": "workspace:*",
"@snx-v3/tsHelpers": "workspace:*",
"@snx-v3/txnReducer": "workspace:*",
"@snx-v3/useAllCollateralPriceIds": "workspace:*",
"@snx-v3/useApprove": "workspace:*",
"@snx-v3/useBlockchain": "workspace:*",
"@snx-v3/useCoreProxy": "workspace:*",
"@snx-v3/useGasOptions": "workspace:*",
"@snx-v3/useGasPrice": "workspace:*",
"@snx-v3/useGasSpeed": "workspace:*",
"@snx-v3/useLiquidityPosition": "workspace:*",
"@snx-v3/withERC7412": "workspace:*",
"@synthetixio/wei": "^2.74.4",
"@tanstack/react-query": "^5.8.3",
"ethers": "^5.7.2",
"react": "^18.2.0"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import { useReducer } from 'react';
import { useCoreProxy } from '@snx-v3/useCoreProxy';
import { useMutation } from '@tanstack/react-query';
import { useNetwork, useProvider, useSigner } from '@snx-v3/useBlockchain';
import { initialState, reducer } from '@snx-v3/txnReducer';
import Wei, { wei } from '@synthetixio/wei';
import { BigNumber, Contract, PopulatedTransaction } from 'ethers';
import { formatGasPriceForTransaction } from '@snx-v3/useGasOptions';
import { getGasPrice } from '@snx-v3/useGasPrice';
import { useGasSpeed } from '@snx-v3/useGasSpeed';
import { withERC7412 } from '@snx-v3/withERC7412';
import { useAllCollateralPriceIds } from '@snx-v3/useAllCollateralPriceIds';
import { fetchPriceUpdates, priceUpdatesToPopulatedTx } from '@snx-v3/fetchPythPrices';
import { LiquidityPosition } from '@snx-v3/useLiquidityPosition';
import { useApprove } from '@snx-v3/useApprove';
import { USDC_BASE_MARKET, getRepayerContract, getUSDCAddress } from '@snx-v3/isBaseAndromeda';
import { parseUnits } from '@snx-v3/format';
import { DEBT_REPAYER_ABI } from '../useClearDebt';
import { useSpotMarketProxy } from '../useSpotMarketProxy';
import { notNil } from '@snx-v3/tsHelpers';

export const useUndelegateBaseAndromeda = ({
accountId,
poolId,
collateralTypeAddress,
collateralChange,
currentCollateral,
liquidityPosition,
}: {
accountId?: string;
poolId?: string;
collateralTypeAddress?: string;
currentCollateral: Wei;
collateralChange: Wei;
liquidityPosition?: LiquidityPosition;
}) => {
const [txnState, dispatch] = useReducer(reducer, initialState);
const { data: CoreProxy } = useCoreProxy();
const { data: SpotMarketProxy } = useSpotMarketProxy();

const signer = useSigner();
const { gasSpeed } = useGasSpeed();
const provider = useProvider();
const { data: collateralPriceUpdates } = useAllCollateralPriceIds();
const { network } = useNetwork();

const debtExists = liquidityPosition?.debt.gt(0.01);
const currentDebt = debtExists && liquidityPosition ? liquidityPosition.debt : wei(0);

const { approve, requireApproval } = useApprove({
contractAddress: getUSDCAddress(network?.id),
//slippage for approval
amount: parseUnits(currentDebt.toString(), 6).mul(110).div(100),
spender: getRepayerContract(network?.id),
});

const mutation = useMutation({
mutationFn: async () => {
if (!signer || !network || !provider) throw new Error('No signer or network');
if (
!(CoreProxy && poolId && collateralTypeAddress && collateralPriceUpdates && SpotMarketProxy)
)
return;
if (collateralChange.eq(0)) return;
if (currentCollateral.eq(0)) return;
try {
dispatch({ type: 'prompting' });

if (debtExists && requireApproval) {
await approve(false);
}

const transactions: Promise<PopulatedTransaction>[] = [];

if (debtExists) {
const repayer = new Contract(getRepayerContract(network.id), DEBT_REPAYER_ABI, signer);

const depositDebtToRepay = repayer.populateTransaction.depositDebtToRepay(
CoreProxy.address,
SpotMarketProxy.address,
accountId,
poolId,
collateralTypeAddress,
USDC_BASE_MARKET
);
transactions.push(depositDebtToRepay);

const burn = CoreProxy.populateTransaction.burnUsd(
BigNumber.from(accountId),
BigNumber.from(poolId),
collateralTypeAddress,
currentDebt?.mul(110).div(100).toBN().toString() || '0'
);
transactions.push(burn);
}

const populatedTxnPromised = CoreProxy.populateTransaction.delegateCollateral(
BigNumber.from(accountId),
BigNumber.from(poolId),
collateralTypeAddress,
currentCollateral.add(collateralChange).toBN(),
wei(1).toBN()
);

const walletAddress = await signer.getAddress();

const callsPromise = Promise.all([...transactions, populatedTxnPromised].filter(notNil));

const collateralPriceCallsPromise = fetchPriceUpdates(
collateralPriceUpdates,
network.isTestnet
).then((signedData) =>
priceUpdatesToPopulatedTx(walletAddress, collateralPriceUpdates, signedData)
);
const [calls, gasPrices, collateralPriceCalls] = await Promise.all([
callsPromise,
getGasPrice({ provider }),
collateralPriceCallsPromise,
]);
const allCalls = collateralPriceCalls.concat(...calls);

const erc7412Tx = await withERC7412(
network,
allCalls,
'useUndelegate',
CoreProxy.interface
);

const gasOptionsForTransaction = formatGasPriceForTransaction({
gasLimit: erc7412Tx.gasLimit,
gasPrices,
gasSpeed,
});

const txn = await signer.sendTransaction({ ...erc7412Tx, ...gasOptionsForTransaction });
dispatch({ type: 'pending', payload: { txnHash: txn.hash } });

await txn.wait();
dispatch({ type: 'success' });
} catch (error: any) {
dispatch({ type: 'error', payload: { error } });
throw error;
}
},
});
return {
mutation,
txnState,
settle: () => dispatch({ type: 'settled' }),
isLoading: mutation.isPending,
exec: mutation.mutateAsync,
};
};
5 changes: 0 additions & 5 deletions liquidity/ui/src/pages/Manage/Undelegate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import React, { FC, useContext } from 'react';
import { useParams } from '@snx-v3/useParams';
import { isBaseAndromeda } from '@snx-v3/isBaseAndromeda';
import { useNetwork } from '@snx-v3/useBlockchain';
import { RepayAllDebt } from './RepayAllDebt';

export const UndelegateUi: FC<{
collateralChange: Wei;
Expand Down Expand Up @@ -190,10 +189,6 @@ export const Undelegate = ({ liquidityPosition }: { liquidityPosition?: Liquidit
}
const max = maxUndelegate();

if (liquidityPosition?.debt.gt(0.01) && isBaseAndromeda(network?.id, network?.preset)) {
return <RepayAllDebt liquidityPosition={liquidityPosition} />;
}

return (
<UndelegateUi
displaySymbol={collateralType.displaySymbol}
Expand Down
27 changes: 26 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6189,6 +6189,7 @@ __metadata:
"@snx-v3/ContractError": "workspace:*"
"@snx-v3/ManagePositionContext": "workspace:*"
"@snx-v3/Multistep": "workspace:*"
"@snx-v3/isBaseAndromeda": "workspace:*"
"@snx-v3/useBlockchain": "workspace:*"
"@snx-v3/useCollateralTypes": "workspace:*"
"@snx-v3/useContractErrorParser": "workspace:*"
Expand Down Expand Up @@ -6784,7 +6785,6 @@ __metadata:
"@snx-v3/useGasOptions": "workspace:*"
"@snx-v3/useGasPrice": "workspace:*"
"@snx-v3/useGasSpeed": "workspace:*"
"@snx-v3/useUSDProxy": "workspace:*"
"@snx-v3/withERC7412": "workspace:*"
"@synthetixio/wei": "npm:^2.74.4"
"@tanstack/react-query": "npm:^5.8.3"
Expand Down Expand Up @@ -7214,6 +7214,31 @@ __metadata:
languageName: unknown
linkType: soft

"@snx-v3/useUndelegateBaseAndromeda@workspace:liquidity/lib/useUndelegateBaseAndromeda":
version: 0.0.0-use.local
resolution: "@snx-v3/useUndelegateBaseAndromeda@workspace:liquidity/lib/useUndelegateBaseAndromeda"
dependencies:
"@snx-v3/fetchPythPrices": "workspace:*"
"@snx-v3/format": "workspace:*"
"@snx-v3/isBaseAndromeda": "workspace:*"
"@snx-v3/tsHelpers": "workspace:*"
"@snx-v3/txnReducer": "workspace:*"
"@snx-v3/useAllCollateralPriceIds": "workspace:*"
"@snx-v3/useApprove": "workspace:*"
"@snx-v3/useBlockchain": "workspace:*"
"@snx-v3/useCoreProxy": "workspace:*"
"@snx-v3/useGasOptions": "workspace:*"
"@snx-v3/useGasPrice": "workspace:*"
"@snx-v3/useGasSpeed": "workspace:*"
"@snx-v3/useLiquidityPosition": "workspace:*"
"@snx-v3/withERC7412": "workspace:*"
"@synthetixio/wei": "npm:^2.74.4"
"@tanstack/react-query": "npm:^5.8.3"
ethers: "npm:^5.7.2"
react: "npm:^18.2.0"
languageName: unknown
linkType: soft

"@snx-v3/useVaultsData@workspace:*, @snx-v3/useVaultsData@workspace:liquidity/lib/useVaultsData":
version: 0.0.0-use.local
resolution: "@snx-v3/useVaultsData@workspace:liquidity/lib/useVaultsData"
Expand Down

0 comments on commit 19f8bf4

Please sign in to comment.