import { useContracts } from "../../useContracts/useContracts"; import { useTokenDetails } from "../../useTokenDetails/useTokenDetails"; import { usePool } from "../../pools/usePool/usePool"; import { useEffect, useState } from "react"; import { parseUnits } from "ethers/lib/utils"; import { doTransaction } from "../../../utils/transactions/transactions"; import { useUserPositions } from "../useUserPositions/useUserPositions"; import { not } from "ramda"; import { useDepositHelper } from "../useDepositHelper/useDepositHelper"; import { config } from "../../../config"; import { recentlyTransferredAndBurnedPositionsState, UserPosition, } from "../../../state"; import { usePollForPositionChange } from "../usePollForPositionChange/usePollForPositionChange"; import { useWeb3Provider } from "../../useWeb3Provider/useWeb3Provider"; import { useRecoilState } from "recoil"; import { BigNumber, ContractTransaction } from "ethers"; /** * A hook to withdraw from an existing position (withdraw) */ export const useWithdraw = (positionId: number) => { const { account } = useWeb3Provider(); const [amount, setAmount] = useState(""); const [useWithdrawAndHarvest, setUseWithdrawAndHarvest] = useState(false); const [useWithdrawAll, setUseWithdrawAll] = useState(false); const [useWithdrawNativeToken, setUseWithdrawNativeToken] = useState(false); const [burnAfterWithdrawal, setBurnAfterWithdrawal] = useState(false); const { approveDepositHelperForAllRelics, depositHelperIsApprovedForRelics, isDepositHelperUsed, setIsDepositHelperUsed, } = useDepositHelper(); const { depositHelper, reliquary } = useContracts(); const { userPositions } = useUserPositions(); const [, setRecentlyBurned] = useRecoilState( recentlyTransferredAndBurnedPositionsState ); const { tokenDetails, fetchTokenDetails } = useTokenDetails(); const poll = usePollForPositionChange(positionId); const position = userPositions[positionId]; const pool = usePool(position.poolId); const { decimalPlaces = 18 } = tokenDetails[pool.lpAddress] || {}; const buildUnderlyingTransaction = () => { if (useWithdrawAll) { return () => depositHelper.withdrawAllAndHarvest( positionId, useWithdrawNativeToken, //giveEther useWithdrawAll //burn ); } return () => depositHelper.withdraw( parseUnits(amount, decimalPlaces), positionId, useWithdrawAndHarvest, useWithdrawNativeToken ); }; const buildLPTransaction = () => { if (useWithdrawAll) { return () => reliquary.multicall([ reliquary.interface.encodeFunctionData("withdrawAndHarvest", [ BigNumber.from(position.amountAsString), positionId, account!, ]), reliquary.interface.encodeFunctionData("burn", [positionId]), ]); } if (useWithdrawAndHarvest) { return () => reliquary.withdrawAndHarvest( parseUnits(amount, decimalPlaces), positionId, account! ); } return () => reliquary.withdraw(parseUnits(amount, decimalPlaces), positionId); }; const buildWithdrawTransaction = (): () => Promise => { if (isDepositHelperUsed) { return buildUnderlyingTransaction(); } return buildLPTransaction(); }; function notifySystemOfBurn() { setRecentlyBurned((prev) => [ ...prev, { id: positionId, event: "Burned", }, ]); } function updateUserTokenBalance() { if (isDepositHelperUsed) fetchTokenDetails(pool.lpAddress); else { fetchTokenDetails(pool.lpAddress); fetchTokenDetails(pool.underlyingFarmAsset[0].contractAddress); } } async function waitForPositionToUpdate() { const positionDidChange = (pos: UserPosition) => pos.amount < position.amount; await poll(positionDidChange); } async function finishWithdraw() { if (!useWithdrawAll) { await waitForPositionToUpdate(); updateUserTokenBalance(); } else { notifySystemOfBurn(); } setAmount(""); } const withdraw = async () => { try { if (isDepositHelperUsed && !depositHelperIsApprovedForRelics) { await approveDepositHelperForAllRelics(); } const transaction = buildWithdrawTransaction(); const receipt = await doTransaction(transaction); await finishWithdraw(); return receipt; } catch (e: any) { setAmount(""); throw e; } }; const toggleWithdrawAndHarvest = () => setUseWithdrawAndHarvest(not); useEffect(() => { fetchTokenDetails(pool.lpAddress); }, [pool.lpAddress]); return { amount, isDepositHelperUsed, setAmount, setIsDepositHelperUsed, setUseWithdrawAndHarvest, setUseWithdrawAll, setUseWithdrawNativeToken, toggleWithdrawAndHarvest, setBurnAfterWithdrawal, useWithdrawAll, burnAfterWithdrawal, underlyingAsset: config!.poolConfig[pool.poolId]!.underlyingFarmAsset, useWithdrawAndHarvest, withdraw, }; };