Skip to content

Commit

Permalink
feat: add clear debt contract (#234)
Browse files Browse the repository at this point in the history
* feat: add clear debt contract

* fix: repay approval spender

* fix: wrong comment

* fix: fix sUSDC on base sepolia

* fix: update clear debt hook
  • Loading branch information
Rickk137 authored Apr 13, 2024
1 parent b9e3f8f commit 25b03c6
Show file tree
Hide file tree
Showing 6 changed files with 213 additions and 10 deletions.
13 changes: 12 additions & 1 deletion liquidity/lib/isBaseAndromeda/isBaseAndromeda.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
export const isBaseAndromeda = (id?: number | string, preset?: string) =>
(id?.toString() === '8453' || '84532') && preset === 'andromeda';

export function getRepayerContract(id?: number) {
switch (id) {
case 8453:
return '0xBD8004ea5c73E33d405d35d594221Efc733F7E37';
case 84532:
return '0xD00a601eafC2C131F46105827AFB02b925Adf62A';
default:
return '';
}
}

export function getUSDCAddress(id?: number) {
switch (id) {
case 8453:
Expand Down Expand Up @@ -28,6 +39,6 @@ export const sUSDC = '0xC74eA762cF06c9151cE074E6a569a5945b6302E7';

// Base Sepolia
export const BASE_SEPOLIA_fUSDC = '0xc43708f8987Df3f3681801e5e640667D86Ce3C30';
export const BASE_SEPOLIA_sUSDC = '0x434Aa3FDb11798EDaB506D4a5e48F70845a66219';
export const BASE_SEPOLIA_sUSDC = '0x8069c44244e72443722cfb22DcE5492cba239d39';

export const USDC_BASE_MARKET = '1';
1 change: 1 addition & 0 deletions liquidity/lib/useClearDebt/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './useClearDebt';
24 changes: 24 additions & 0 deletions liquidity/lib/useClearDebt/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "@snx-v3/useClearDebt",
"private": true,
"main": "index.ts",
"version": "0.0.1",
"dependencies": {
"@snx-v3/fetchPythPrices": "workspace:*",
"@snx-v3/isBaseAndromeda": "workspace:*",
"@snx-v3/tsHelpers": "workspace:*",
"@snx-v3/txnReducer": "workspace:*",
"@snx-v3/useAllCollateralPriceIds": "workspace:*",
"@snx-v3/useBlockchain": "workspace:*",
"@snx-v3/useCoreProxy": "workspace:*",
"@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",
"ethers": "^5.7.2",
"react": "^18.2.0"
}
}
146 changes: 146 additions & 0 deletions liquidity/lib/useClearDebt/useClearDebt.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import { useReducer } from 'react';
import { useCoreProxy } from '@snx-v3/useCoreProxy';
import { formatGasPriceForTransaction } from '@snx-v3/useGasOptions';
import { useMutation } from '@tanstack/react-query';
import { useNetwork, useProvider, useSigner } from '@snx-v3/useBlockchain';
import { initialState, reducer } from '@snx-v3/txnReducer';
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 = [
{
inputs: [
{ internalType: 'contract ISynthetixCore', name: 'synthetixCore', type: 'address' },
{ internalType: 'contract ISpotMarket', name: 'spotMarket', type: 'address' },
{ internalType: 'uint128', name: 'accountId', type: 'uint128' },
{ internalType: 'uint128', name: 'poolId', type: 'uint128' },
{ internalType: 'address', name: 'collateralType', type: 'address' },
{ internalType: 'uint128', name: 'spotMarketId', type: 'uint128' },
],
name: 'depositDebtToRepay',
outputs: [],
stateMutability: 'nonpayable',
type: 'function',
},
];

export const useClearDebt = ({
accountId,
poolId,
collateralTypeAddress,
availableUSDCollateral,
debt,
}: {
accountId?: string;
poolId?: string;
collateralTypeAddress?: string;
availableUSDCollateral?: Wei;
debt?: Wei;
}) => {
const [txnState, dispatch] = useReducer(reducer, initialState);
const { data: CoreProxy } = useCoreProxy();
const { data: UsdProxy } = useUSDProxy();
const { data: SpotMarketProxy } = useSpotMarketProxy();
const { data: collateralPriceIds } = useAllCollateralPriceIds();

const signer = useSigner();
const { network } = useNetwork();
const { gasSpeed } = useGasSpeed();
const provider = useProvider();

const mutation = useMutation({
mutationFn: async () => {
if (!signer || !network || !provider) throw new Error('No signer or network');

if (
!(
CoreProxy &&
poolId &&
accountId &&
collateralTypeAddress &&
UsdProxy &&
SpotMarketProxy &&
collateralPriceIds
)
) {
return;
}

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

if (!availableUSDCollateral) return;

try {
dispatch({ type: 'prompting' });

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

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

const callsPromise = Promise.all([depositDebtToRepay, burn].filter(notNil));

const walletAddress = await signer.getAddress();

const collateralPriceCallsPromise = fetchPriceUpdates(
collateralPriceIds,
network.isTestnet
).then((signedData) =>
priceUpdatesToPopulatedTx(walletAddress, collateralPriceIds, signedData)
);

const [calls, gasPrices, collateralPriceCalls] = await Promise.all([
callsPromise,
getGasPrice({ provider }),
collateralPriceCallsPromise,
]);

const allCalls = collateralPriceCalls.concat(calls);

const erc7412Tx = await withERC7412(network, allCalls, 'useRepay', 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,
};
};
16 changes: 7 additions & 9 deletions liquidity/ui/src/pages/Manage/RepayAllDebt.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,15 @@ import { Button, Flex, Text } from '@chakra-ui/react';
import { Amount } from '@snx-v3/Amount';
import { LiquidityPosition } from '@snx-v3/useLiquidityPosition';
import { wei } from '@synthetixio/wei';
import { getUSDCAddress, isBaseAndromeda } from '@snx-v3/isBaseAndromeda';
import { getRepayerContract, getUSDCAddress, isBaseAndromeda } from '@snx-v3/isBaseAndromeda';
import { useNetwork } from '@snx-v3/useBlockchain';
import { useRepayBaseAndromeda } from '../../../../lib/useRepayBaseAndromeda';
import { useParams, useSearchParams } from 'react-router-dom';
import { useCallback, useMemo } from 'react';
import { useQueryClient } from '@tanstack/react-query';
import { useApprove } from '@snx-v3/useApprove';
import { parseUnits } from '@snx-v3/format';
import { useSpotMarketProxy } from '../../../../lib/useSpotMarketProxy';
import { useTokenBalance } from '@snx-v3/useTokenBalance';
import { useClearDebt } from '../../../../lib/useClearDebt';

export const RepayAllDebt = ({ liquidityPosition }: { liquidityPosition: LiquidityPosition }) => {
const { network } = useNetwork();
Expand All @@ -24,8 +23,6 @@ export const RepayAllDebt = ({ liquidityPosition }: { liquidityPosition: Liquidi
const debtExists = liquidityPosition.debt.gt(0.01);
const currentDebt = debtExists ? liquidityPosition.debt : wei(0);

const { data: SpotMarketProxy } = useSpotMarketProxy();

const { data: tokenBalance } = useTokenBalance(
isBase ? getUSDCAddress(network?.id) : liquidityPosition.tokenAddress
);
Expand All @@ -39,12 +36,12 @@ export const RepayAllDebt = ({ liquidityPosition }: { liquidityPosition: Liquidi
exec: execRepay,
settle: settleRepay,
isLoading,
} = useRepayBaseAndromeda({
} = useClearDebt({
accountId: searchParams.get('accountId') || '',
poolId: params.poolId,
collateralTypeAddress: liquidityPosition?.tokenAddress,
debtChange: currentDebt,
availableUSDCollateral: liquidityPosition.accountCollateral.availableCollateral,
debt: currentDebt,
});

const {
Expand All @@ -53,8 +50,9 @@ export const RepayAllDebt = ({ liquidityPosition }: { liquidityPosition: Liquidi
isLoading: approvalLoading,
} = useApprove({
contractAddress: getUSDCAddress(network?.id),
amount: parseUnits(currentDebt.toString(), 6).add(1),
spender: SpotMarketProxy?.address,
//slippage for approval
amount: parseUnits(currentDebt.toString(), 6).mul(110).div(100),
spender: getRepayerContract(network?.id),
});

const submit = useCallback(async () => {
Expand Down
23 changes: 23 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6770,6 +6770,29 @@ __metadata:
languageName: unknown
linkType: soft

"@snx-v3/useClearDebt@workspace:liquidity/lib/useClearDebt":
version: 0.0.0-use.local
resolution: "@snx-v3/useClearDebt@workspace:liquidity/lib/useClearDebt"
dependencies:
"@snx-v3/fetchPythPrices": "workspace:*"
"@snx-v3/isBaseAndromeda": "workspace:*"
"@snx-v3/tsHelpers": "workspace:*"
"@snx-v3/txnReducer": "workspace:*"
"@snx-v3/useAllCollateralPriceIds": "workspace:*"
"@snx-v3/useBlockchain": "workspace:*"
"@snx-v3/useCoreProxy": "workspace:*"
"@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"
ethers: "npm:^5.7.2"
react: "npm:^18.2.0"
languageName: unknown
linkType: soft

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

0 comments on commit 25b03c6

Please sign in to comment.