Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions portal/app/[locale]/btc-yield/_hooks/useDeposit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { depositToken } from 'hemi-btc-staking-actions/actions'
import { useNativeTokenBalance, useTokenBalance } from 'hooks/useBalance'
import { useHemi } from 'hooks/useHemi'
import { useHemiWalletClient } from 'hooks/useHemiClient'
import { useNeedsApproval } from 'hooks/useNeedsApproval'
import { buildAllowanceQueryKey } from 'utils/allowanceQueryKey'
import { parseTokenUnits } from 'utils/token'
import { useAccount } from 'wagmi'

Expand Down Expand Up @@ -52,11 +52,11 @@ export const useDeposit = function ({

const { hemiWalletClient } = useHemiWalletClient()

const { allowanceQueryKey } = useNeedsApproval({
address: token.address,
amount,
const allowanceQueryKey = buildAllowanceQueryKey({
chainId: token.chainId,
owner: address,
spender: vaultAddress,
tokenAddress: token.address,
})

const poolDepositsQueryKey = getPoolDepositsQueryKey(token.chainId)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { useAllowance } from '@hemilabs/react-hooks/useAllowance'
import { type UseQueryOptions } from '@tanstack/react-query'
import { DrawerParagraph } from 'components/drawer'
import { HemiFees } from 'components/hemiFees'
import {
Expand All @@ -8,7 +10,6 @@ import { type StepPropsWithoutPosition } from 'components/reviewOperation/step'
import { Spinner } from 'components/spinner'
import { ToastLoader } from 'components/toast/toastLoader'
import { stakeManagerAddresses } from 'hemi-viem-stake-actions'
import { useAllowance } from 'hooks/useAllowance'
import { useAmount } from 'hooks/useAmount'
import { useNativeTokenBalance, useTokenBalance } from 'hooks/useBalance'
import { useEstimateApproveErc20Fees } from 'hooks/useEstimateApproveErc20Fees'
Expand All @@ -21,10 +22,11 @@ import {
type StakeStatusEnumType,
type StakeToken,
} from 'types/stake'
import { normalizeTokenAddressForAllowance } from 'utils/allowanceQueryKey'
import { getNativeToken, isNativeToken } from 'utils/nativeToken'
import { canSubmit } from 'utils/stake'
import { parseTokenUnits } from 'utils/token'
import { formatUnits } from 'viem'
import { type Address, formatUnits, isAddress } from 'viem'
import { useAccount } from 'wagmi'

import { useEstimateStakeFees } from '../../_hooks/useEstimateStakeFees'
Expand All @@ -45,6 +47,11 @@ import { StakeCallToAction } from './stakeCallToAction'
import { StrategyDetails } from './strategyDetails'
import { SubmitButton } from './submitButton'

type AllowanceQuery = Omit<
UseQueryOptions<bigint, Error, bigint>,
'queryFn' | 'queryKey' | 'enabled'
> & { enabled?: boolean }

type Props = {
closeDrawer: () => void
heading: string
Expand All @@ -61,6 +68,28 @@ const useBalance = function (token: StakeToken) {
return isNativeToken(token) ? nativeBalance : tokenBalance
}

const stakeRequiresErc20Approval = ({
allowance,
amount,
operatesNativeToken,
}: {
allowance: bigint
amount: bigint
operatesNativeToken: boolean
}) => !operatesNativeToken && allowance < amount

const isStakeAllowanceQueryEnabled = ({
address,
operatesNativeToken,
spender,
tokenAddress,
}: {
address: Address | undefined
operatesNativeToken: boolean
spender: Address | undefined
tokenAddress: string
}) => !operatesNativeToken && !!address && isAddress(tokenAddress) && !!spender

export const StakeOperation = function ({
closeDrawer,
heading,
Expand All @@ -73,17 +102,23 @@ export const StakeOperation = function ({
const [amountInput, setAmountInput] = useAmount()
const operatesNativeToken = isNativeToken(token)
const spender = stakeManagerAddresses[token.chainId]
const erc20Address = normalizeTokenAddressForAllowance(token.address)

const { data: allowance = BigInt(0), isPending } = useAllowance(
token.address,
{
args: {
owner: address,
spender,
},
chainId: token.chainId,
},
)
const query: AllowanceQuery = {
enabled: isStakeAllowanceQueryEnabled({
address,
operatesNativeToken,
spender,
tokenAddress: token.address,
}),
}

const { data: allowance = BigInt(0), isPending } = useAllowance({
owner: address,
query,
spender,
token: { address: erc20Address, chainId: token.chainId },
})

const amount = parseTokenUnits(amountInput, token)

Expand Down Expand Up @@ -215,7 +250,11 @@ export const StakeOperation = function ({
const canStake =
allowanceLoaded && balanceLoaded && !isSubmitting && isSubmitValid

const requiresApproval = allowance < parseTokenUnits(amountInput, token)
const requiresApproval = stakeRequiresErc20Approval({
allowance,
amount,
operatesNativeToken,
})

const handleStake = () => stake({ amountInput })

Expand Down
12 changes: 7 additions & 5 deletions portal/app/[locale]/stake/_hooks/useStake.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { useEnsureConnectedTo } from '@hemilabs/react-hooks/useEnsureConnectedTo'
import { useMutation, useQueryClient } from '@tanstack/react-query'
import { stakeManagerAddresses } from 'hemi-viem-stake-actions'
import { useAllowance } from 'hooks/useAllowance'
import { useNativeTokenBalance, useTokenBalance } from 'hooks/useBalance'
import { useHemiClient, useHemiWalletClient } from 'hooks/useHemiClient'
import { useNetworkType } from 'hooks/useNetworkType'
Expand All @@ -13,10 +12,11 @@ import {
type StakeStatusEnumType,
type StakeToken,
} from 'types/stake'
import { buildAllowanceQueryKey } from 'utils/allowanceQueryKey'
import { isNativeToken } from 'utils/nativeToken'
import { stake } from 'utils/stake'
import { parseTokenUnits } from 'utils/token'
import { Hash } from 'viem'
import { type Hash } from 'viem'
import { useAccount } from 'wagmi'

import { getStakedBalanceQueryKey } from './useStakedBalance'
Expand All @@ -25,9 +25,11 @@ export const useStake = function (token: StakeToken) {
const operatesNativeToken = isNativeToken(token)
const { address } = useAccount()
const ensureConnectedTo = useEnsureConnectedTo()
const { queryKey: allowanceQueryKey } = useAllowance(token.address, {
args: { owner: address, spender: stakeManagerAddresses[token.chainId] },
const allowanceKey = buildAllowanceQueryKey({
chainId: token.chainId,
owner: address,
spender: stakeManagerAddresses[token.chainId],
tokenAddress: token.address,
})
const [networkType] = useNetworkType()
const hemiPublicClient = useHemiClient()
Expand Down Expand Up @@ -108,7 +110,7 @@ export const useStake = function (token: StakeToken) {
setStakeStatus(StakeStatusEnum.APPROVAL_TX_COMPLETED)
if (!operatesNativeToken) {
// invalidate allowance after an erc20 approval took place
queryClient.invalidateQueries({ queryKey: allowanceQueryKey })
queryClient.invalidateQueries({ queryKey: allowanceKey })
}
},
onTokenApprove: () =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'
import { EventEmitter } from 'events'
import { useNativeTokenBalance, useTokenBalance } from 'hooks/useBalance'
import { useHemiWalletClient } from 'hooks/useHemiClient'
import { useNeedsApproval } from 'hooks/useNeedsApproval'
import { useUmami } from 'hooks/useUmami'
import {
type StakingDashboardOperation,
StakingDashboardStatus,
type StakingDashboardToken,
type StakingPosition,
} from 'types/stakingDashboard'
import { buildAllowanceQueryKey } from 'utils/allowanceQueryKey'
import { parseTokenUnits } from 'utils/token'
import { getVeHemiContractAddress, IncreaseAmountEvents } from 've-hemi-actions'
import { increaseAmount } from 've-hemi-actions/actions'
Expand Down Expand Up @@ -65,11 +65,11 @@ export const useIncreaseAmount = function ({

const { hemiWalletClient } = useHemiWalletClient()

const { allowanceQueryKey } = useNeedsApproval({
address: token.address,
amount,
const allowanceQueryKey = buildAllowanceQueryKey({
chainId: token.chainId,
owner: address,
spender: veHemiAddress,
tokenAddress: token.address,
})

return useMutation({
Expand Down
8 changes: 4 additions & 4 deletions portal/app/[locale]/staking-dashboard/_hooks/useStake.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'
import { EventEmitter } from 'events'
import { useNativeTokenBalance, useTokenBalance } from 'hooks/useBalance'
import { useHemiWalletClient } from 'hooks/useHemiClient'
import { useNeedsApproval } from 'hooks/useNeedsApproval'
import { useUmami } from 'hooks/useUmami'
import {
StakingDashboardOperation,
StakingDashboardStatus,
StakingDashboardToken,
StakingPosition,
} from 'types/stakingDashboard'
import { buildAllowanceQueryKey } from 'utils/allowanceQueryKey'
import { parseTokenUnits } from 'utils/token'
import {
CreateLockEvents,
Expand Down Expand Up @@ -71,11 +71,11 @@ export const useStake = function ({

const { hemiWalletClient } = useHemiWalletClient()

const { allowanceQueryKey } = useNeedsApproval({
address: token.address,
amount,
const allowanceQueryKey = buildAllowanceQueryKey({
chainId: token.chainId,
owner: address,
spender: veHemiAddress,
tokenAddress: token.address,
})

return useMutation({
Expand Down
12 changes: 6 additions & 6 deletions portal/app/[locale]/tunnel/_hooks/useDeposit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
} from 'hemi-tunnel-actions'
import { useNativeTokenBalance, useTokenBalance } from 'hooks/useBalance'
import { useL1StandardBridgeAddress } from 'hooks/useL1StandardBridgeAddress'
import { useNeedsApproval } from 'hooks/useNeedsApproval'
import { useTunnelHistory } from 'hooks/useTunnelHistory'
import { useUmami } from 'hooks/useUmami'
import { useContext } from 'react'
Expand All @@ -21,11 +20,12 @@ import {
EvmDepositStatus,
MessageDirection,
} from 'types/tunnel'
import { buildAllowanceQueryKey } from 'utils/allowanceQueryKey'
import { findChainById } from 'utils/chain'
import { getEvmL1PublicClient } from 'utils/chainClients'
import { isNativeAddress } from 'utils/nativeToken'
import { parseTokenUnits } from 'utils/token'
import { Chain, zeroAddress } from 'viem'
import { type Chain, zeroAddress } from 'viem'
import { useAccount, useWalletClient } from 'wagmi'

import { useTunnelOperation } from './useTunnelOperation'
Expand Down Expand Up @@ -76,11 +76,11 @@ export const useDeposit = function ({

const depositingNative = isNativeAddress(fromToken.address)

const { allowanceQueryKey } = useNeedsApproval({
address: fromToken.address,
amount,
const allowanceQueryKey = buildAllowanceQueryKey({
chainId: fromToken.chainId,
spender: l1StandardBridgeAddress,
owner: address,
spender: depositingNative ? undefined : l1StandardBridgeAddress,
tokenAddress: fromToken.address,
})

return useMutation({
Expand Down
36 changes: 0 additions & 36 deletions portal/hooks/useAllowance.ts

This file was deleted.

35 changes: 28 additions & 7 deletions portal/hooks/useNeedsApproval.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import { useAllowance } from 'hooks/useAllowance'
import { Address, Chain } from 'viem'
import { useAllowance } from '@hemilabs/react-hooks/useAllowance'
import { type UseQueryOptions } from '@tanstack/react-query'
import { normalizeTokenAddressForAllowance } from 'utils/allowanceQueryKey'
import { isNativeAddress } from 'utils/nativeToken'
import { type Address, type Chain, isAddress } from 'viem'
import { useAccount } from 'wagmi'

type AllowanceQuery = Omit<
UseQueryOptions<bigint, Error, bigint>,
'queryFn' | 'queryKey' | 'enabled'
> & { enabled?: boolean }

export const useNeedsApproval = function ({
address,
amount,
Expand All @@ -14,20 +22,33 @@ export const useNeedsApproval = function ({
chainId: Chain['id']
}) {
const { address: owner } = useAccount()
const effectiveSpender = isNativeAddress(address) ? undefined : spender
const token = {
address: normalizeTokenAddressForAllowance(address),
chainId,
}

const query: AllowanceQuery = {
enabled:
!isNativeAddress(address) &&
isAddress(address) &&
!!owner &&
!!effectiveSpender,
}

const {
data: allowance = BigInt(0),
isError,
isLoading,
queryKey: allowanceQueryKey,
status: allowanceStatus,
} = useAllowance(address, {
args: { owner, spender },
chainId,
} = useAllowance({
owner,
query,
spender: effectiveSpender,
token,
Comment thread
arielmergen marked this conversation as resolved.
})

return {
allowanceQueryKey,
isAllowanceError: isError,
isAllowanceLoading: isLoading,
needsApproval: amount > allowance && allowanceStatus === 'success',
Expand Down
Loading
Loading