diff --git a/apps/common/components/AmountInput.tsx b/apps/common/components/AmountInput.tsx index b72276f7b..e67a506d1 100644 --- a/apps/common/components/AmountInput.tsx +++ b/apps/common/components/AmountInput.tsx @@ -1,11 +1,11 @@ import {Renderable} from '@yearn-finance/web-lib/components/Renderable'; -import {isZero} from '@yearn-finance/web-lib/utils/isZero'; import type {ReactElement} from 'react'; +import type {TNormalizedBN} from '@common/types/types'; type TAmountInputProps = { - amount: string | number; - maxAmount?: string | number; + amount: TNormalizedBN; + maxAmount?: TNormalizedBN; maxLabel?: string; label?: string; placeholder?: string; @@ -31,13 +31,6 @@ export function AmountInput({ onLegendClick, onMaxClick }: TAmountInputProps): ReactElement { - let displayedAmount = amount.toString(); - if (isZero(displayedAmount) && !disabled) { - displayedAmount = ''; - } - if (isZero(displayedAmount) && disabled) { - displayedAmount = '0'; - } return (
{label && ( @@ -49,10 +42,10 @@ export function AmountInput({
onAmountChange(e.target.value) : undefined} placeholder={loading ? '' : placeholder ?? '0'} disabled={disabled} diff --git a/apps/common/hooks/useTokenPrice.ts b/apps/common/hooks/useTokenPrice.ts index 3aec104a5..fa6e2d18e 100644 --- a/apps/common/hooks/useTokenPrice.ts +++ b/apps/common/hooks/useTokenPrice.ts @@ -1,5 +1,6 @@ import {useMemo} from 'react'; +import {ETH_TOKEN_ADDRESS, YFI_ADDRESS} from '@yearn-finance/web-lib/utils/constants'; import {formatToNormalizedValue, toBigInt} from '@yearn-finance/web-lib/utils/format.bigNumber'; import {useYearn} from '@common/contexts/useYearn'; @@ -8,9 +9,15 @@ import type {TAddress} from '@yearn-finance/web-lib/types'; export function useTokenPrice(address: TAddress): number { const {prices} = useYearn(); - const tokenPrice = useMemo((): number => ( - formatToNormalizedValue(toBigInt(prices?.[address] || 0), 6) - ), [address, prices]); + const tokenPrice = useMemo((): number => { + if (address === YFI_ADDRESS) { + return 5150.96; //TODO: REMOVE + } + if (address === ETH_TOKEN_ADDRESS) { + return 1601.69; //TODO: REMOVE + } + return formatToNormalizedValue(toBigInt(prices?.[address] || 0), 6); + }, [address, prices]); return tokenPrice; } diff --git a/apps/veyfi/components/ClaimTab.tsx b/apps/veyfi/components/ClaimTab.tsx index 3950c32b3..0fe97b707 100644 --- a/apps/veyfi/components/ClaimTab.tsx +++ b/apps/veyfi/components/ClaimTab.tsx @@ -1,5 +1,4 @@ import {useCallback, useState} from 'react'; -import {formatUnits} from 'viem'; import {useVotingEscrow} from '@veYFI/contexts/useVotingEscrow'; import {withdrawUnlockedVeYFI} from '@veYFI/utils/actions'; import {VEYFI_CHAIN_ID} from '@veYFI/utils/constants'; @@ -7,7 +6,7 @@ import {validateNetwork} from '@veYFI/utils/validations'; import {Button} from '@yearn-finance/web-lib/components/Button'; import {useWeb3} from '@yearn-finance/web-lib/contexts/useWeb3'; import {useChainID} from '@yearn-finance/web-lib/hooks/useChainID'; -import {toBigInt} from '@yearn-finance/web-lib/utils/format.bigNumber'; +import {toBigInt, toNormalizedBN} from '@yearn-finance/web-lib/utils/format.bigNumber'; import {getTimeUntil} from '@yearn-finance/web-lib/utils/time'; import {defaultTxStatus} from '@yearn-finance/web-lib/utils/web3/transaction'; import {AmountInput} from '@common/components/AmountInput'; @@ -24,7 +23,7 @@ export function ClaimTab(): ReactElement { const hasLockedAmount = toBigInt(positions?.deposit?.underlyingBalance) > 0n; const timeUntilUnlock = positions?.unlockTime ? getTimeUntil(positions?.unlockTime) : 0; const isClaimable = hasLockedAmount && !timeUntilUnlock; - const claimableAmount = isClaimable ? positions?.deposit?.underlyingBalance : '0'; + const claimableAmount = toNormalizedBN(toBigInt(isClaimable ? positions?.deposit?.underlyingBalance : 0)); const {isValid: isValidNetwork} = validateNetwork({supportedNetwork: VEYFI_CHAIN_ID, walletNetwork: safeChainID}); const refreshData = useCallback(async (): Promise => { @@ -60,7 +59,7 @@ export function ClaimTab(): ReactElement {
diff --git a/apps/veyfi/components/RewardsTab.tsx b/apps/veyfi/components/RewardsTab.tsx index 211fef069..0f401c67e 100644 --- a/apps/veyfi/components/RewardsTab.tsx +++ b/apps/veyfi/components/RewardsTab.tsx @@ -7,9 +7,9 @@ import {validateNetwork} from '@veYFI/utils/validations'; import {Button} from '@yearn-finance/web-lib/components/Button'; import {useWeb3} from '@yearn-finance/web-lib/contexts/useWeb3'; import {toAddress, truncateHex} from '@yearn-finance/web-lib/utils/address'; -import {toBigInt, toNormalizedAmount} from '@yearn-finance/web-lib/utils/format.bigNumber'; +import {toBigInt, toNormalizedBN} from '@yearn-finance/web-lib/utils/format.bigNumber'; +import {formatAmount} from '@yearn-finance/web-lib/utils/format.number'; import {formatCounterValue} from '@yearn-finance/web-lib/utils/format.value'; -import {isZero} from '@yearn-finance/web-lib/utils/isZero'; import {defaultTxStatus} from '@yearn-finance/web-lib/utils/web3/transaction'; import {AmountInput} from '@common/components/AmountInput'; import {Dropdown} from '@common/components/Dropdown'; @@ -27,7 +27,7 @@ export function RewardsTab(): ReactElement { const refreshData = useCallback((): unknown => Promise.all([refreshGauges()]), [refreshGauges]); const [claimStatus, set_claimStatus] = useState(defaultTxStatus); const selectedGaugeAddress = toAddress(selectedGauge?.id); - const selectedGaugeRewards = toBigInt(positionsMap[selectedGaugeAddress]?.reward?.balance?.raw); + const selectedGaugeRewards = toNormalizedBN(toBigInt(positionsMap[selectedGaugeAddress]?.reward?.balance?.raw)); const onClaim = useCallback(async (): Promise => { const result = await GaugeActions.claimRewards({ @@ -74,16 +74,15 @@ export function RewardsTab(): ReactElement { />
diff --git a/apps/veyfi/contexts/useOption.tsx b/apps/veyfi/contexts/useOption.tsx index 7667847e8..318f0059b 100644 --- a/apps/veyfi/contexts/useOption.tsx +++ b/apps/veyfi/contexts/useOption.tsx @@ -1,6 +1,5 @@ -import React, {createContext, memo, useCallback, useContext, useEffect, useMemo} from 'react'; -import {ethers} from 'ethers'; -import {useAsync} from '@react-hookz/web'; +import React, {createContext, memo, useCallback, useContext, useState} from 'react'; +import {useDeepCompareMemo} from '@react-hookz/web'; import {VEYFI_DYFI_ABI} from '@veYFI/utils/abi/veYFIdYFI.abi'; import {VEYFI_OPTIONS_ABI} from '@veYFI/utils/abi/veYFIOptions.abi'; import {VEYFI_CHAIN_ID, VEYFI_DYFI_ADDRESS,VEYFI_OPTIONS_ADDRESS} from '@veYFI/utils/constants'; @@ -8,73 +7,40 @@ import {erc20ABI, readContract} from '@wagmi/core'; import {useWeb3} from '@yearn-finance/web-lib/contexts/useWeb3'; import {allowanceKey} from '@yearn-finance/web-lib/utils/address'; import {BIG_ZERO, ETH_TOKEN_ADDRESS, YFI_ADDRESS} from '@yearn-finance/web-lib/utils/constants'; -import {toBigInt, toNormalizedValue} from '@yearn-finance/web-lib/utils/format.bigNumber'; +import {toBigInt, toNormalizedBN, toNormalizedValue} from '@yearn-finance/web-lib/utils/format.bigNumber'; +import {useAsyncTrigger} from '@common/hooks/useAsyncEffect'; import {useTokenPrice} from '@common/hooks/useTokenPrice'; import type {ReactElement} from 'react'; import type {TDict} from '@yearn-finance/web-lib/types'; - -export type TOptionPosition = { - balance: bigint, -} +import type {TNormalizedBN} from '@common/types/types'; export type TOptionContext = { getRequiredEth: (amount: bigint) => Promise, price: number | undefined, - positions: TOptionPosition | undefined, + position: TNormalizedBN, allowances: TDict, - isLoading: boolean, refresh: () => void, } const defaultProps: TOptionContext = { getRequiredEth: async (): Promise => BIG_ZERO, price: undefined, - positions: undefined, + position: toNormalizedBN(0), allowances: {}, - isLoading: true, refresh: (): void => undefined }; const OptionContext = createContext(defaultProps); export const OptionContextApp = memo(function OptionContextApp({children}: {children: ReactElement}): ReactElement { - const {provider, address: userAddress, isActive} = useWeb3(); + const {address: userAddress, isActive} = useWeb3(); + const [price, set_price] = useState(undefined); + const [position, set_position] = useState(toNormalizedBN(0)); + const [allowances, set_allowances] = useState>({}); const yfiPrice = useTokenPrice(YFI_ADDRESS); const ethPrice = useTokenPrice(ETH_TOKEN_ADDRESS); - const [{result: price, status: fetchPriceStatus}, {execute: refreshPrice}] = useAsync(async (): Promise => { - if (!isActive || provider) { - return; - } - return priceFetcher(); - }, 0); - - const [{result: positions, status: fetchPositionsStatus}, {execute: refreshPositions}] = useAsync(async (): Promise => { - if (!isActive || provider) { - return; - } - return positionsFetcher(); - }, {balance: 0n}); - - const [{result: allowances, status: fetchAllowancesStatus}, {execute: refreshAllowances}] = useAsync(async (): Promise | undefined> => { - if (!isActive || provider) { - return; - } - return allowancesFetcher(); - }, {}); - - const refresh = useCallback((): void => { - refreshPrice(); - refreshPositions(); - refreshAllowances(); - }, [refreshPrice, refreshPositions, refreshAllowances]); - - useEffect((): void => { - refresh(); - }, [refresh]); - const getRequiredEth = useCallback(async (amount: bigint): Promise => { - // TODO: update once abi is available return readContract({ address: VEYFI_OPTIONS_ADDRESS, abi: VEYFI_OPTIONS_ABI, @@ -84,37 +50,36 @@ export const OptionContextApp = memo(function OptionContextApp({children}: {chil }); }, []); - const priceFetcher = useCallback(async (): Promise => { + const refreshPrice = useAsyncTrigger(async (): Promise => { + console.log(ethPrice, yfiPrice); if(!ethPrice || !yfiPrice) { return undefined; } - const oneOption = ethers.utils.parseEther('1'); - const requiredEthPerOption = await getRequiredEth(toBigInt(oneOption.toString())); + const oneOption = toBigInt(1e18); + const requiredEthPerOption = await getRequiredEth(oneOption); const requiredEthValuePerOption = toNormalizedValue(requiredEthPerOption, 18) * ethPrice; const pricePerOption = yfiPrice - requiredEthValuePerOption; - return pricePerOption; + set_price(pricePerOption); }, [ethPrice, yfiPrice, getRequiredEth]); - const positionsFetcher = useCallback(async (): Promise => { + const refreshPositions = useAsyncTrigger(async (): Promise => { if (!isActive || !userAddress) { - return undefined; + return; } - // TODO: update once abi is available - return { - balance: await readContract({ - address: VEYFI_DYFI_ADDRESS, - abi: VEYFI_DYFI_ABI, - functionName: 'balanceOf', - args: [userAddress], - chainId: VEYFI_CHAIN_ID - }) - }; + const dYFIBalance = await readContract({ + address: VEYFI_DYFI_ADDRESS, + abi: VEYFI_DYFI_ABI, + functionName: 'balanceOf', + args: [userAddress], + chainId: VEYFI_CHAIN_ID + }); + set_position(toNormalizedBN(dYFIBalance)); }, [isActive, userAddress]); - const allowancesFetcher = useCallback(async (): Promise> => { + const refreshAllowances = useAsyncTrigger(async (): Promise => { if (!isActive || !userAddress) { - return {}; + return; } const dYFIAllowanceOptions = await readContract({ @@ -125,19 +90,24 @@ export const OptionContextApp = memo(function OptionContextApp({children}: {chil chainId: VEYFI_CHAIN_ID }); - return ({ + set_allowances({ [allowanceKey(VEYFI_CHAIN_ID, VEYFI_DYFI_ADDRESS, VEYFI_OPTIONS_ADDRESS, userAddress)]: dYFIAllowanceOptions }); }, [isActive, userAddress]); - const contextValue = useMemo((): TOptionContext => ({ + const refresh = useCallback((): void => { + refreshPrice(); + refreshPositions(); + refreshAllowances(); + }, [refreshPrice, refreshPositions, refreshAllowances]); + + const contextValue = useDeepCompareMemo((): TOptionContext => ({ getRequiredEth, price, - positions, + position, allowances: allowances ?? {}, - isLoading: fetchPriceStatus === 'loading' || fetchPositionsStatus === 'loading' || fetchAllowancesStatus === 'loading', refresh - }), [allowances, fetchAllowancesStatus, fetchPositionsStatus, fetchPriceStatus, getRequiredEth, positions, price, refresh]); + }), [allowances, getRequiredEth, position, price, refresh]); return ( diff --git a/package.json b/package.json index 4968a54db..f3b6acafb 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "@rainbow-me/rainbowkit": "^1.1.2", "@wagmi/chains": "^1.8.0", "@wagmi/core": "^1.4.3", - "@yearn-finance/web-lib": "^3.0.56", + "@yearn-finance/web-lib": "^3.0.57", "axios": "^1.5.0", "dayjs": "^1.11.9", "eslint-plugin-react-hooks": "^4.6.0", diff --git a/yarn.lock b/yarn.lock index 861cf6031..e5ff280d7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3381,10 +3381,10 @@ resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== -"@yearn-finance/web-lib@^3.0.56": - version "3.0.56" - resolved "https://registry.yarnpkg.com/@yearn-finance/web-lib/-/web-lib-3.0.56.tgz#321e556abf0d8d8b2e4a854d70ab1fa7ec531ea0" - integrity sha512-DO3H4XHtH7jK+a4r8+rFeV3+UEnTtQWiRAldqUC0U5Oy44Hb1ha22yHulQG0yWEqw9CG6TLlWtbc2/S5V/nisw== +"@yearn-finance/web-lib@^3.0.57": + version "3.0.57" + resolved "https://registry.yarnpkg.com/@yearn-finance/web-lib/-/web-lib-3.0.57.tgz#a1918e313c1d53d48641c7de9a71e2f977379c9f" + integrity sha512-AOrv6MzQuTuF+VWkLXhqpMXWNVju8PiFDt3+qZTttfJB7QggeRTb7Hc2mJAVuyhW5CX/4xW4fDTs4+hpEBQp7A== dependencies: "@babel/core" "^7.23.0" "@headlessui/react" "^1.7.17"