Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: rfox refactor #7079

Merged
merged 59 commits into from
Jun 11, 2024
Merged
Show file tree
Hide file tree
Changes from 54 commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
339a6da
wip: rfox bridge final wire-up
gomesalexandre Jun 5, 2024
4a3746e
feat: copy
gomesalexandre Jun 5, 2024
622e04c
feat: remove dummy brige quote and wire-up from stake
gomesalexandre Jun 5, 2024
b0c0e4b
feat: tackle TODOs
gomesalexandre Jun 5, 2024
6807f28
feat: handle continue/back
gomesalexandre Jun 5, 2024
df94417
fix: derp
gomesalexandre Jun 5, 2024
0a959e1
feat: continue to confirm
gomesalexandre Jun 5, 2024
5548f47
feat: asset/stakingAsset discrimination
gomesalexandre Jun 5, 2024
748994c
feat: bridge approval/bridge fees skeleton
gomesalexandre Jun 5, 2024
d7497be
feat: composite short name for not enough fee asset balance
gomesalexandre Jun 5, 2024
cf9fccf
feat: bridge step balance checks
gomesalexandre Jun 5, 2024
2a10c9d
fix: pass state from confirm to status
gomesalexandre Jun 5, 2024
cb26621
feat: and from status to confirm too
gomesalexandre Jun 5, 2024
0a776f1
fix: derp
gomesalexandre Jun 5, 2024
32b33ba
feat: better loading state at bridge confirm time
gomesalexandre Jun 5, 2024
e0f0513
fix: uh oh
gomesalexandre Jun 5, 2024
3371953
feat: improve beard oil
gomesalexandre Jun 5, 2024
070084e
feat: copy
gomesalexandre Jun 5, 2024
84afc16
feat: two hard things in software engineering mang
gomesalexandre Jun 6, 2024
d8164fa
feat: 60s polling interval for tradeStatus
gomesalexandre Jun 6, 2024
675ad17
feat: consistent confirmedQuote terminology
gomesalexandre Jun 6, 2024
1213fe5
feat: approve mutation void param
gomesalexandre Jun 6, 2024
ac29474
feat: copy
gomesalexandre Jun 6, 2024
bbf2839
feat: tackle self-review comment
gomesalexandre Jun 6, 2024
7aa945a
feat: remove useless opt chain
gomesalexandre Jun 7, 2024
f1ae068
fix: merge
gomesalexandre Jun 7, 2024
5231def
feat: two birds one stone
gomesalexandre Jun 7, 2024
7d40c75
fix: do display approval fee even when not enough fee
gomesalexandre Jun 7, 2024
5ec32e8
feat: rm useless lint disable
gomesalexandre Jun 7, 2024
b4a0eea
feat: useCallback handleAssetChange
gomesalexandre Jun 7, 2024
bbf36ac
[skip ci] wip: rfox bridge refactor PoC
gomesalexandre Jun 6, 2024
47a0d53
feat: cleanup
gomesalexandre Jun 6, 2024
fe3829f
fix: don't make approval fees row disappear on approve mutation
gomesalexandre Jun 6, 2024
5a0bdf1
chore: saner naming
gomesalexandre Jun 6, 2024
2b9bde2
feat: remove useless non-null assert and cast
gomesalexandre Jun 7, 2024
cc52b35
feat: don't wrap invalidateQueries in IIAFE
gomesalexandre Jun 7, 2024
ed4e52c
feat: empty flex shorthand across rfox
gomesalexandre Jun 7, 2024
63852a5
feat: forgotten approvalCallData in enabled
gomesalexandre Jun 7, 2024
f1f9660
feat: add safety in handleApprove
gomesalexandre Jun 7, 2024
5bc05fa
feat: extract isTradeQuoteQueryEnabled
gomesalexandre Jun 7, 2024
f8f4f1e
feat: bump react-query to latest
gomesalexandre Jun 7, 2024
0d36e7b
fix: types after react-query bump
gomesalexandre Jun 7, 2024
889bde8
feat: bump @lukemorales/query-key-factory to latest
gomesalexandre Jun 7, 2024
1f3673b
fix: types after @lukemorales/query-key-factory bump
gomesalexandre Jun 7, 2024
976ecbc
poc: type-safety
gomesalexandre Jun 7, 2024
f4d4d07
feat: holy molly refactor I did it
gomesalexandre Jun 7, 2024
47c1185
feat: the big short(ening of LoC)
gomesalexandre Jun 10, 2024
4ef5223
feat: sane naming makes everything saner
gomesalexandre Jun 10, 2024
dbc5531
feat: unstake too
gomesalexandre Jun 10, 2024
40da2c5
Merge branch 'develop' into feat_rfox_bridge_p2
0xApotheosis Jun 11, 2024
6a707a4
Merge branch 'feat_rfox_bridge_p2' into feat_rfox_bridge_refactor_poc
0xApotheosis Jun 11, 2024
e513cda
Merge remote-tracking branch 'origin/develop' into feat_rfox_bridge_r…
gomesalexandre Jun 11, 2024
f12e79d
feat: hooks queryKeys memo
gomesalexandre Jun 11, 2024
06e83d9
feat: cleanup
gomesalexandre Jun 11, 2024
b9028df
feat: explicit props/return types instead of ugly Fn type
gomesalexandre Jun 11, 2024
393010f
feat: paranoia
gomesalexandre Jun 11, 2024
0ce565c
feat: refetchInterval and its fren as required
gomesalexandre Jun 11, 2024
8313551
feat: claim gas refactor (#7094)
0xApotheosis Jun 11, 2024
34bff51
feat: add PartialFields type util
gomesalexandre Jun 11, 2024
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
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@
"@keepkey/hdwallet-keepkey-rest": "1.40.42",
"@keepkey/keepkey-sdk": "0.2.57",
"@lifi/sdk": "^2.5.0",
"@lukemorales/query-key-factory": "^1.3.2",
"@lukemorales/query-key-factory": "^1.3.4",
"@metamask/detect-provider": "^1.2.0",
"@react-spring/web": "^9.5.2",
"@reduxjs/toolkit": "^1.9.3",
Expand All @@ -111,7 +111,7 @@
"@shapeshiftoss/types": "workspace:^",
"@shapeshiftoss/unchained-client": "workspace:^",
"@sniptt/monads": "^0.5.10",
"@tanstack/react-query": "^5.0.5",
"@tanstack/react-query": "^5.40.1",
"@uniswap/sdk": "^3.0.3",
"@uniswap/sdk-core": "^4.0.9",
"@uniswap/v3-sdk": "^3.10.0",
Expand Down
68 changes: 68 additions & 0 deletions src/hooks/queries/useEvmFees.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import type { ChainId } from '@shapeshiftoss/caip'
import { skipToken, useQuery } from '@tanstack/react-query'
import { useMemo } from 'react'
import { reactQueries } from 'react-queries'
import { selectEvmFees } from 'react-queries/selectors'
import { useWallet } from 'hooks/useWallet/useWallet'
import {
assertGetEvmChainAdapter,
getFeesWithWallet,
type GetFeesWithWalletArgs,
isGetFeesWithWalletArgs,
} from 'lib/utils/evm'
import {
selectFeeAssetByChainId,
selectMarketDataByAssetIdUserCurrency,
} from 'state/slices/selectors'
import { useAppSelector } from 'state/store'

type UseEvmFeesProps = Omit<
GetFeesWithWalletArgs,
'wallet' | 'adapter' | 'accountNumber' | 'data'
> & {
accountNumber: number | undefined
data: string | undefined
chainId: ChainId
enabled?: boolean
staleTime?: number
refetchInterval?: number | false | undefined
gomesalexandre marked this conversation as resolved.
Show resolved Hide resolved
refetchIntervalInBackground?: boolean
}

export const useEvmFees = (props: UseEvmFeesProps) => {
gomesalexandre marked this conversation as resolved.
Show resolved Hide resolved
const wallet = useWallet().state.wallet

const {
enabled = true,
staleTime,
refetchInterval,
refetchIntervalInBackground,
...input
} = props
gomesalexandre marked this conversation as resolved.
Show resolved Hide resolved

const adapter = useMemo(() => assertGetEvmChainAdapter(input.chainId), [input.chainId])

const feeAsset = useAppSelector(state => selectFeeAssetByChainId(state, input.chainId))
const feeAssetMarketData = useAppSelector(state =>
selectMarketDataByAssetIdUserCurrency(state, feeAsset?.assetId ?? ''),
)

const getFeesWithWalletInput = useMemo(
() => ({ ...input, adapter, wallet }),
[adapter, input, wallet],
)

const query = useQuery({
queryKey: reactQueries.common.evmFees(input).queryKey,
queryFn:
isGetFeesWithWalletArgs(getFeesWithWalletInput) && enabled
? () => getFeesWithWallet(getFeesWithWalletInput)
: skipToken,
gomesalexandre marked this conversation as resolved.
Show resolved Hide resolved
select: feeAsset ? fees => selectEvmFees(fees, feeAsset, feeAssetMarketData) : undefined,
staleTime,
refetchInterval,
refetchIntervalInBackground,
})

return query
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ethChainId } from '@shapeshiftoss/caip'
import { type HDWallet, supportsETH } from '@shapeshiftoss/hdwallet-core'
import type {
GetEvmTradeQuoteInput,
SingleHopTradeQuoteSteps,
Expand All @@ -14,6 +15,23 @@ import { v4 as uuid } from 'uuid'
import { fetchArbitrumBridgeSwap } from '../utils/fetchArbitrumBridgeSwap'
import { assertValidTrade } from '../utils/helpers'

export type GetEvmTradeQuoteInputWithWallet = Omit<GetEvmTradeQuoteInput, 'supportsEIP1559'> & {
wallet: HDWallet
}

gomesalexandre marked this conversation as resolved.
Show resolved Hide resolved
export const getTradeQuoteWithWallet = async (inputWithWallet: GetEvmTradeQuoteInputWithWallet) => {
const { wallet, ...input } = inputWithWallet
const supportsEIP1559 = supportsETH(wallet) && (await wallet.ethSupportsEIP1559())

return getTradeQuote({
...input,
sellAsset: input.sellAsset,
buyAsset: input.buyAsset,
accountNumber: input.accountNumber,
supportsEIP1559,
})
}

gomesalexandre marked this conversation as resolved.
Show resolved Hide resolved
export async function getTradeQuote(
input: GetEvmTradeQuoteInput,
): Promise<Result<TradeQuote, SwapErrorRight>> {
Expand Down
22 changes: 21 additions & 1 deletion src/lib/utils/evm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,16 @@ type GetFeesArgs = GetFeesCommonArgs & {
supportsEIP1559: boolean
}

type GetFeesWithWalletArgs = GetFeesCommonArgs & {
export type MaybeGetFeesWithWalletArgs = {
adapter: EvmChainAdapter | undefined
data: string | undefined
wallet: HDWallet | null
to: string
value: string
accountNumber: number | undefined
}

gomesalexandre marked this conversation as resolved.
Show resolved Hide resolved
export type GetFeesWithWalletArgs = GetFeesCommonArgs & {
accountNumber: number
wallet: HDWallet
}
Expand All @@ -91,6 +100,17 @@ export type Fees = evm.Fees & {
networkFeeCryptoBaseUnit: string
}

export type EvmFees = {
fees: Fees
txFeeFiat: string
networkFeeCryptoBaseUnit: string
}

export const isGetFeesWithWalletArgs = (
input: MaybeGetFeesWithWalletArgs,
): input is GetFeesWithWalletArgs =>
Boolean(input.adapter && input.accountNumber !== undefined && input.wallet && input.data)
gomesalexandre marked this conversation as resolved.
Show resolved Hide resolved
gomesalexandre marked this conversation as resolved.
Show resolved Hide resolved

export const getFeesWithWallet = async (args: GetFeesWithWalletArgs): Promise<Fees> => {
const { accountNumber, adapter, wallet, ...rest } = args

Expand Down
2 changes: 1 addition & 1 deletion src/pages/Lending/Pool/components/Repay/RepayInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ export const RepayInput = ({
assetId: repaymentAsset?.assetId,
spender: inboundAddressData?.router,
from: userAddress,
amount: toBaseUnit(
amountCryptoBaseUnit: toBaseUnit(
// Add 5% buffer to the repayment allowance to avoid asset rates fluctuations ending up in more asset needed to repay
confirmedQuote?.repaymentAmountCryptoPrecision ?? 0,
repaymentAsset?.precision ?? 0,
Expand Down
2 changes: 1 addition & 1 deletion src/pages/Lending/hooks/useLendingCloseQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ export const useLendingQuoteCloseQuery = ({
repaymentAccountId: _repaymentAccountId,
collateralAccountId: _collateralAccountId,
enabled = true,
}: UseLendingQuoteCloseQueryProps & QueryObserverOptions) => {
}: UseLendingQuoteCloseQueryProps & Pick<QueryObserverOptions, 'enabled'>) => {
gomesalexandre marked this conversation as resolved.
Show resolved Hide resolved
const { data: lendingPositionData } = useLendingPositionData({
assetId: _collateralAssetId,
accountId: _collateralAccountId,
Expand Down
2 changes: 1 addition & 1 deletion src/pages/Lending/hooks/useLendingQuoteQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ export const useLendingQuoteOpenQuery = ({
borrowAssetId: _borrowAssetId,
depositAmountCryptoPrecision: _depositAmountCryptoPrecision,
enabled = true,
}: UseLendingQuoteQueryProps & QueryObserverOptions) => {
}: UseLendingQuoteQueryProps & Pick<QueryObserverOptions, 'enabled'>) => {
gomesalexandre marked this conversation as resolved.
Show resolved Hide resolved
const [_borrowAssetReceiveAddress, setBorrowAssetReceiveAddress] = useState<string | null>(null)

const wallet = useWallet().state.wallet
Expand Down
2 changes: 1 addition & 1 deletion src/pages/Lending/hooks/useRepaymentLockData.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const useRepaymentLockData = ({
// Let the parent pass its own query options
// enabled will be used in conjunction with this hook's own isRepaymentLockQueryEnabled to determine whether or not to run the query
enabled = true,
}: UseLendingPositionDataProps & QueryObserverOptions) => {
}: UseLendingPositionDataProps & Pick<QueryObserverOptions, 'enabled'>) => {
gomesalexandre marked this conversation as resolved.
Show resolved Hide resolved
const { data: blockHeight } = useQuery({
// @lukemorales/query-key-factory only returns queryFn and queryKey - all others will be ignored in the returned object
// We use the block query to get the current height, so we obviously need to mark it stale at the end of each THOR block
Expand Down
22 changes: 5 additions & 17 deletions src/pages/RFOX/components/ChangeAddress/ChangeAddress.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
import { fromAccountId } from '@shapeshiftoss/caip'
import { useQueryClient } from '@tanstack/react-query'
import { foxStakingV1Abi } from 'contracts/abis/FoxStakingV1'
import { RFOX_PROXY_CONTRACT_ADDRESS } from 'contracts/constants'
import { AnimatePresence } from 'framer-motion'
import React, { lazy, Suspense, useCallback, useState } from 'react'
import { MemoryRouter, Route, Switch, useLocation } from 'react-router'
import { makeSuspenseful } from 'utils/makeSuspenseful'
import type { Address } from 'viem'
import { getAddress } from 'viem'
import { arbitrum } from 'viem/chains'
import { useReadContract } from 'wagmi'
import { useStakingInfoQuery } from 'pages/RFOX/hooks/useStakingInfoQuery'

import type { ChangeAddressRouteProps, RfoxChangeAddressQuote } from './types'
import { ChangeAddressRoutePaths } from './types'
Expand Down Expand Up @@ -61,17 +56,10 @@ export const ChangeAddressRoutes: React.FC<ChangeAddressRouteProps> = ({ headerC
const [changeAddressTxid, setChangeAddressTxid] = useState<string | undefined>()
const [confirmedQuote, setConfirmedQuote] = useState<RfoxChangeAddressQuote | undefined>()

const { queryKey: stakingInfoQueryKey } = useReadContract({
abi: foxStakingV1Abi,
address: RFOX_PROXY_CONTRACT_ADDRESS,
functionName: 'stakingInfo',
args: [
// actually defined by the time we actually consume the queryKey
confirmedQuote
? getAddress(fromAccountId(confirmedQuote.stakingAssetAccountId).account)
: ('' as Address),
],
chainId: arbitrum.id,
const { queryKey: stakingInfoQueryKey } = useStakingInfoQuery({
stakingAssetAccountAddress: confirmedQuote
? fromAccountId(confirmedQuote.stakingAssetAccountId).account
: undefined,
})

const handleTxConfirmed = useCallback(async () => {
Expand Down
50 changes: 26 additions & 24 deletions src/pages/RFOX/components/ChangeAddress/ChangeAddressConfirm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,19 @@ import {
} from '@chakra-ui/react'
import { fromAccountId, fromAssetId } from '@shapeshiftoss/caip'
import { CONTRACT_INTERACTION } from '@shapeshiftoss/chain-adapters'
import { useMutation, useQuery } from '@tanstack/react-query'
import { useMutation } from '@tanstack/react-query'
import { foxStakingV1Abi } from 'contracts/abis/FoxStakingV1'
import { RFOX_PROXY_CONTRACT_ADDRESS } from 'contracts/constants'
import { useCallback, useMemo } from 'react'
import { useTranslate } from 'react-polyglot'
import { reactQueries } from 'react-queries'
import { useHistory } from 'react-router'
import { encodeFunctionData } from 'viem'
import { Amount } from 'components/Amount/Amount'
import type { RowProps } from 'components/Row/Row'
import { Row } from 'components/Row/Row'
import { SlideTransition } from 'components/SlideTransition'
import { RawText } from 'components/Text'
import { useEvmFees } from 'hooks/queries/useEvmFees'
import { useWallet } from 'hooks/useWallet/useWallet'
import { middleEllipsis } from 'lib/utils'
import {
Expand All @@ -36,7 +36,6 @@ import {
selectAccountNumberByAccountId,
selectAssetById,
selectFeeAssetByChainId,
selectMarketDataByAssetIdUserCurrency,
selectTxById,
} from 'state/slices/selectors'
import { serializeTxIndex } from 'state/slices/txHistorySlice/utils'
Expand Down Expand Up @@ -66,8 +65,9 @@ export const ChangeAddressConfirm: React.FC<
const feeAsset = useAppSelector(state =>
selectFeeAssetByChainId(state, fromAssetId(confirmedQuote.stakingAssetId).chainId),
)
const feeAssetMarketData = useAppSelector(state =>
selectMarketDataByAssetIdUserCurrency(state, feeAsset?.assetId ?? ''),
const adapter = useMemo(
() => (feeAsset ? assertGetEvmChainAdapter(fromAssetId(feeAsset.assetId).chainId) : undefined),
[feeAsset],
)

const stakingAssetAccountAddress = useMemo(
Expand All @@ -93,28 +93,25 @@ export const ChangeAddressConfirm: React.FC<
})
}, [confirmedQuote.newRuneAddress])

const isGetChangeAddressFeesEnabled = useMemo(
() => Boolean(wallet && feeAsset && feeAssetMarketData),
[wallet, feeAsset, feeAssetMarketData],
const changeAddressFeesQueryInput = useMemo(
() => ({
to: RFOX_PROXY_CONTRACT_ADDRESS,
chainId: fromAssetId(confirmedQuote.stakingAssetId).chainId,
accountNumber: stakingAssetAccountNumber,
data: callData,
value: '0',
}),
[callData, confirmedQuote.stakingAssetId, stakingAssetAccountNumber],
)

const {
data: changeAddressFees,
isLoading: isChangeAddressFeesLoading,
isSuccess: isChangeAddressFeesSuccess,
} = useQuery({
...reactQueries.common.evmFees({
to: RFOX_PROXY_CONTRACT_ADDRESS,
from: stakingAssetAccountAddress,
accountNumber: stakingAssetAccountNumber!, // see isGetChangeAddressFeesEnabled
data: callData,
value: '0', // contract call
wallet: wallet!, // see isGetChangeAddressFeesEnabled
feeAsset: feeAsset!, // see isGetChangeAddressFeesEnabled
feeAssetMarketData: feeAssetMarketData!, // see isGetChangeAddressFeesEnabled
}),
} = useEvmFees({
...changeAddressFeesQueryInput,
enabled: true,
staleTime: 30_000,
enabled: isGetChangeAddressFeesEnabled,
// Ensures fees are refetched at an interval, including when the app is in the background
refetchIntervalInBackground: true,
// Yeah this is arbitrary but come on, Arb is cheap
Expand All @@ -136,9 +133,14 @@ export const ChangeAddressConfirm: React.FC<
isSuccess: isChangeAddressMutationSuccess,
} = useMutation({
mutationFn: async () => {
if (!wallet || stakingAssetAccountNumber === undefined || !stakingAsset || !callData) return

const adapter = assertGetEvmChainAdapter(stakingAsset.chainId)
if (
!wallet ||
stakingAssetAccountNumber === undefined ||
!stakingAsset ||
!callData ||
!adapter
)
return

const buildCustomTxInput = await createBuildCustomTxInput({
accountNumber: stakingAssetAccountNumber,
Expand Down Expand Up @@ -221,7 +223,7 @@ export const ChangeAddressConfirm: React.FC<
<IconButton onClick={handleGoBack} variant='ghost' aria-label='back' icon={backIcon} />
</Flex>
<Flex textAlign='center'>{translate('common.confirm')}</Flex>
<Flex flex={1}></Flex>
<Flex flex={1} />
</CardHeader>
<CardBody>
<Stack spacing={6}>{changeAddressCard}</Stack>
Expand Down
Loading
Loading