Skip to content

Commit

Permalink
Improvements for fetching data in the dApp (#914)
Browse files Browse the repository at this point in the history
Closes AENG-18

This PR improves code for fetching data in the dApp. What has been done

- Made each query a separate hook. This approach will allow us to use
queries whenever we want. Additionally, the code becomes more clear.
- Fixed for checking the status of fetched data, improvement for
`useIsFetchedWalletData`. The previous solution was wrong because
`useIsFetching` returns the number of queries that our application is
loading or fetching in the background. We should check the fetch status
for all the data we are interested in.
- Fixed a bug from AENG-18. The problem was solved by using the
`@tanstack/react-query` package to fetch activities. The data will be
reset together at the same time.

## UI

**Before** 


https://github.com/user-attachments/assets/440ef97d-ecf7-46bd-9260-ad0025412dda



**After**


https://github.com/user-attachments/assets/07371345-3624-41ab-8b72-87cfbcb4cd00


## Testing

Use React Query dev tools for testing. They help visualize all of the
inner workings of React Query.


https://github.com/user-attachments/assets/a966c8f4-98ab-4c4c-91eb-b50f60eea798

### What should be tested before merge

- [ ] Make sure that the issue described in AENG-18 is no longer exist.
- [ ] The skeleton of data loading works correctly.

Check if the data is fetched at the start of the app:
- [ ] TVL
- [ ] Total Mezo points
- [ ] Total Acre points

Check if the data is fetched when the wallet is connected:
- [ ] Bitcoin balance
- [ ] Bitcoin position
- [ ] Activities
- [ ] User Acre points

Check if the data is reset when the wallet is disconnected:
- [ ] Bitcoin balance
- [ ] Bitcoin position
- [ ] Activities
- [ ] User Acre points

Check if the data is fetched in the time interval. It is currently every
5 minutes:
- [ ] TVL
- [ ] Total Mezo points
- [ ] Total Acre points
- [ ] Bitcoin balance
- [ ] Bitcoin position
- [ ] Activities

Checks if the data is updated after the deposit is executed:
- [ ] Activities
- [ ] Bitcoin balance

Checks if the data is updated after the withdrawal is executed:
- [ ] Activities
- [ ] Bitcoin position
  • Loading branch information
kpyszkowski authored Dec 12, 2024
2 parents 49188fe + b69b1c0 commit f0a59c4
Show file tree
Hide file tree
Showing 33 changed files with 207 additions and 417 deletions.
Original file line number Diff line number Diff line change
@@ -1,35 +1,31 @@
import React, { useCallback, useRef } from "react"
import { ONE_SEC_IN_MILLISECONDS, queryKeysFactory } from "#/constants"
import {
useActionFlowPause,
useActionFlowTokenAmount,
useAppDispatch,
useBitcoinBalance,
useCancelPromise,
useDepositBTCTransaction,
useInvalidateQueries,
useStakeFlowContext,
useVerifyDepositAddress,
} from "#/hooks"
import { usePostHogCapture } from "#/hooks/posthog/usePostHogCapture"
import { PostHogEvent } from "#/posthog/events"
import { setStatus, setTxHash } from "#/store/action-flow"
import { ONE_SEC_IN_MILLISECONDS } from "#/constants"
import { PROCESS_STATUSES } from "#/types"
import { eip1193, logPromiseFailure } from "#/utils"
import { useTimeout } from "@chakra-ui/react"
import { useMutation } from "@tanstack/react-query"
import WalletInteractionModal from "../WalletInteractionModal"

const { userKeys } = queryKeysFactory

export default function DepositBTCModal() {
const tokenAmount = useActionFlowTokenAmount()
const { btcAddress, depositReceipt, stake } = useStakeFlowContext()
const verifyDepositAddress = useVerifyDepositAddress()
const dispatch = useAppDispatch()
const { handlePause } = useActionFlowPause()
const handleBitcoinBalanceInvalidation = useInvalidateQueries({
queryKey: userKeys.balance(),
})
const { refetch: refetchBitcoinBalance } = useBitcoinBalance()
const { handleCapture, handleCaptureWithCause } = usePostHogCapture()

const sessionId = useRef(Math.random())
Expand All @@ -39,9 +35,9 @@ export default function DepositBTCModal() {
)

const onStakeBTCSuccess = useCallback(() => {
handleBitcoinBalanceInvalidation()
logPromiseFailure(refetchBitcoinBalance())
dispatch(setStatus(PROCESS_STATUSES.SUCCEEDED))
}, [dispatch, handleBitcoinBalanceInvalidation])
}, [dispatch, refetchBitcoinBalance])

const onError = useCallback(
(error: unknown) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,37 @@ import {
useActionFlowPause,
useActionFlowTokenAmount,
useAppDispatch,
useBitcoinPosition,
useCancelPromise,
useInvalidateQueries,
useModal,
useTimeout,
useTransactionDetails,
} from "#/hooks"
import { ACTION_FLOW_TYPES, PROCESS_STATUSES } from "#/types"
import { dateToUnixTimestamp, eip1193 } from "#/utils"
import { ACTION_FLOW_TYPES, Activity, PROCESS_STATUSES } from "#/types"
import { dateToUnixTimestamp, eip1193, logPromiseFailure } from "#/utils"
import { setStatus } from "#/store/action-flow"
import { useInitializeWithdraw } from "#/acre-react/hooks"
import { ONE_SEC_IN_MILLISECONDS, queryKeysFactory } from "#/constants"
import { activityInitialized } from "#/store/wallet"
import { useMutation } from "@tanstack/react-query"
import { useMutation, useQueryClient } from "@tanstack/react-query"
import { PostHogEvent } from "#/posthog/events"
import { usePostHogCapture } from "#/hooks/posthog/usePostHogCapture"
import BuildTransactionModal from "./BuildTransactionModal"
import WalletInteractionModal from "../WalletInteractionModal"

const { userKeys } = queryKeysFactory

type WithdrawalStatus = "building-data" | "built-data" | "signature"

export default function SignMessageModal() {
const [status, setWaitingStatus] = useState<WithdrawalStatus>("building-data")

const dispatch = useAppDispatch()
const queryClient = useQueryClient()
const tokenAmount = useActionFlowTokenAmount()
const amount = tokenAmount?.amount
const { closeModal } = useModal()
const { handlePause } = useActionFlowPause()
const initializeWithdraw = useInitializeWithdraw()
const handleBitcoinPositionInvalidation = useInvalidateQueries({
queryKey: userKeys.position(),
})
const { refetch: refetchBitcoinPosition } = useBitcoinPosition()

const sessionId = useRef(Math.random())
const { cancel, resolve, sessionIdToPromise } = useCancelPromise(
sessionId.current,
Expand All @@ -59,10 +56,10 @@ export default function SignMessageModal() {
}, [resolve])

const onSignMessageSuccess = useCallback(() => {
handleBitcoinPositionInvalidation()
logPromiseFailure(refetchBitcoinPosition())
dispatch(setStatus(PROCESS_STATUSES.SUCCEEDED))
handleCapture(PostHogEvent.WithdrawalSuccess)
}, [dispatch, handleBitcoinPositionInvalidation, handleCapture])
}, [dispatch, refetchBitcoinPosition, handleCapture])

const onSignMessageError = useCallback(
(error: unknown) => {
Expand Down Expand Up @@ -103,38 +100,44 @@ export default function SignMessageModal() {
onSignMessageCallback,
)

dispatch(
activityInitialized({
// Note that the withdraw id returned from the Acre SDK while fetching
// the withdrawals has the following pattern:
// `<redemptionKey>-<count>`. The redemption key returned during the
// withdrawal initialization does not contain the `-<count>` suffix
// because there may be delay between indexing the Acre subgraph and
// the time when a transaction was actually made and it's hard to get
// the exact number of the redemptions with the same key. Eg:
// - a user initialized a withdraw,
// - the Acre SDK is asking the subgraph for the number of withdrawals
// with the same redemption key,
// - the Acre subgraph may or may not be up to date with the chain and
// we are not sure if we should add +1 to the counter or the
// returned value already includes the requested withdraw from the
// first step. So we can't create the correct withdraw id.
// So here we set the id as a redemption key. Only one pending
// withdrawal can exist with the same redemption key, so when the user
// can initialize the next withdrawal with the same redemption key, we
// assume the dapp should already re-fetch all withdrawals with the
// correct IDs and move the `pending` redemption to `completed`
// section with the proper id.
id: redemptionKey,
type: "withdraw",
status: "pending",
// This is a requested amount. The amount of BTC received will be
// around: `amount - transactionFee.total`.
amount: amount - transactionFee.acre,
initializedAt: dateToUnixTimestamp(),
// The message is signed immediately after the initialization.
finalizedAt: dateToUnixTimestamp(),
}),
queryClient.setQueriesData(
{ queryKey: queryKeysFactory.userKeys.activities() },
(oldData: Activity[] | undefined) => {
const newActivity: Activity = {
// Note that the withdraw id returned from the Acre SDK while fetching
// the withdrawals has the following pattern:
// `<redemptionKey>-<count>`. The redemption key returned during the
// withdrawal initialization does not contain the `-<count>` suffix
// because there may be delay between indexing the Acre subgraph and
// the time when a transaction was actually made and it's hard to get
// the exact number of the redemptions with the same key. Eg:
// - a user initialized a withdraw,
// - the Acre SDK is asking the subgraph for the number of withdrawals
// with the same redemption key,
// - the Acre subgraph may or may not be up to date with the chain and
// we are not sure if we should add +1 to the counter or the
// returned value already includes the requested withdraw from the
// first step. So we can't create the correct withdraw id.
// So here we set the id as a redemption key. Only one pending
// withdrawal can exist with the same redemption key, so when the user
// can initialize the next withdrawal with the same redemption key, we
// assume the dapp should already re-fetch all withdrawals with the
// correct IDs and move the `pending` redemption to `completed`
// section with the proper id.
id: redemptionKey,
type: "withdraw",
status: "pending",
// This is a requested amount. The amount of BTC received will be
// around: `amount - transactionFee.total`.
amount: amount - transactionFee.acre,
initializedAt: dateToUnixTimestamp(),
// The message is signed immediately after the initialization.
finalizedAt: dateToUnixTimestamp(),
}

if (oldData) return [newActivity, ...oldData]
return [newActivity]
},
)
},
onSuccess: onSignMessageSuccess,
Expand Down
8 changes: 4 additions & 4 deletions dapp/src/components/TransactionModal/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React, { useEffect } from "react"
import { StakeFlowProvider } from "#/contexts"
import {
useActivities,
useAppDispatch,
useFetchActivities,
useIsSignedMessage,
useTransactionModal,
} from "#/hooks"
Expand All @@ -18,7 +18,7 @@ type TransactionModalProps = { type: ActionFlowType } & BaseModalProps

function TransactionModalBase({ type, closeModal }: TransactionModalProps) {
const dispatch = useAppDispatch()
const fetchActivities = useFetchActivities()
const { refetch: refetchActivities } = useActivities()

useEffect(() => {
dispatch(setType(type))
Expand All @@ -28,9 +28,9 @@ function TransactionModalBase({ type, closeModal }: TransactionModalProps) {
useEffect(() => {
return () => {
dispatch(resetState())
logPromiseFailure(fetchActivities())
logPromiseFailure(refetchActivities())
}
}, [dispatch, fetchActivities])
}, [dispatch, refetchActivities])

return (
<StakeFlowProvider>
Expand Down
1 change: 1 addition & 0 deletions dapp/src/constants/queryKeysFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const userKeys = {
all: ["user"] as const,
balance: () => [...userKeys.all, "balance"] as const,
position: () => [...userKeys.all, "position"] as const,
activities: () => [...userKeys.all, "activities"] as const,
pointsData: () => [...userKeys.all, "points-data"] as const,
}

Expand Down
9 changes: 6 additions & 3 deletions dapp/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,23 @@ export * from "./useVerifyDepositAddress"
export { default as useStatistics } from "./useStatistics"
export * from "./useDisconnectWallet"
export { default as useWalletConnectionAlert } from "./useWalletConnectionAlert"
export { default as useInvalidateQueries } from "./useInvalidateQueries"
export { default as useResetWalletState } from "./useResetWalletState"
export { default as useMobileMode } from "./useMobileMode"
export { default as useBitcoinRecoveryAddress } from "./useBitcoinRecoveryAddress"
export { default as useIsFetchedWalletData } from "./useIsFetchedWalletData"
export { default as useLocalStorage } from "./useLocalStorage"
export { default as useReferral } from "./useReferral"
export { default as useMats } from "./useMats"
export { default as useIsEmbed } from "./useIsEmbed"
export { default as useTriggerConnectWalletModal } from "./useTriggerConnectWalletModal"
export { default as useLastUsedBtcAddress } from "./useLastUsedBtcAddress"
export { default as useAcrePoints } from "./useAcrePoints"
export { default as useAggregatedAcrePointsData } from "./useAggregatedAcrePointsData"
export { default as useSignMessageAndCreateSession } from "./useSignMessageAndCreateSession"
export { default as useAccessCode } from "./useAccessCode"
export { default as useFormField } from "./useFormField"
export { default as useDepositBTCTransaction } from "./useDepositBTCTransaction"
export { default as useCancelPromise } from "./useCancelPromise"
export { default as useActivitiesCount } from "./useActivitiesCount"
export { default as useActivities } from "./useActivities"
export { default as useBitcoinBalance } from "./useBitcoinBalance"
export { default as useBitcoinPosition } from "./useBitcoinPosition"
export { default as useMats } from "./useMats"
1 change: 0 additions & 1 deletion dapp/src/hooks/orangeKit/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,3 @@ export * from "./useConnectors"
export * from "./useAccountsChangedUnisat"
export * from "./useAccountsChangedOKX"
export * from "./useAccountChangedOKX"
export { default as useBitcoinBalance } from "./useBitcoinBalance"
2 changes: 0 additions & 2 deletions dapp/src/hooks/sdk/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
export * from "./useInitializeAcreSdk"
export * from "./useFetchMinDepositAmount"
export * from "./useInitDataFromSdk"
export * from "./useFetchActivities"
export * from "./useMinWithdrawAmount"
export { default as useBitcoinPosition } from "./useBitcoinPosition"
41 changes: 0 additions & 41 deletions dapp/src/hooks/sdk/useFetchActivities.ts

This file was deleted.

19 changes: 0 additions & 19 deletions dapp/src/hooks/sdk/useInitDataFromSdk.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,5 @@
import { useEffect } from "react"
import { useInterval } from "@chakra-ui/react"
import { logPromiseFailure } from "#/utils"
import { REFETCH_INTERVAL_IN_MILLISECONDS } from "#/constants"
import { useFetchMinDepositAmount } from "./useFetchMinDepositAmount"
import { useFetchActivities } from "./useFetchActivities"
import { useWallet } from "../useWallet"

export function useInitDataFromSdk() {
const { address } = useWallet()
const fetchActivities = useFetchActivities()

useEffect(() => {
if (address) {
logPromiseFailure(fetchActivities())
}
}, [address, fetchActivities])

useFetchMinDepositAmount()
useInterval(
() => logPromiseFailure(fetchActivities()),
REFETCH_INTERVAL_IN_MILLISECONDS,
)
}
4 changes: 1 addition & 3 deletions dapp/src/hooks/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ export * from "./useActionFlowStatus"
export * from "./useActionFlowActiveStep"
export * from "./useActionFlowTokenAmount"
export * from "./useActionFlowTxHash"
export * from "./useAllActivitiesCount"
export * from "./useActionFlowPause"
export * from "./useIsSignedMessage"
export { default as useHasFetchedActivities } from "./useHasFetchedActivities"
export { default as useActivities } from "./useActivities"
export { default as useWalletAddress } from "./useWalletAddress"
9 changes: 0 additions & 9 deletions dapp/src/hooks/store/useActivities.ts

This file was deleted.

6 changes: 0 additions & 6 deletions dapp/src/hooks/store/useAllActivitiesCount.ts

This file was deleted.

8 changes: 0 additions & 8 deletions dapp/src/hooks/store/useHasFetchedActivities.ts

This file was deleted.

6 changes: 6 additions & 0 deletions dapp/src/hooks/store/useWalletAddress.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { selectWalletAddress } from "#/store/wallet"
import { useAppSelector } from "./useAppSelector"

export default function useWalletAddress() {
return useAppSelector(selectWalletAddress)
}
13 changes: 13 additions & 0 deletions dapp/src/hooks/useAcrePointsData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { queryKeysFactory, REFETCH_INTERVAL_IN_MILLISECONDS } from "#/constants"
import { useQuery } from "@tanstack/react-query"
import { acreApi } from "#/utils"

const { acreKeys } = queryKeysFactory

export default function useAcrePointsData() {
return useQuery({
queryKey: [...acreKeys.pointsData()],
queryFn: async () => acreApi.getPointsData(),
refetchInterval: REFETCH_INTERVAL_IN_MILLISECONDS,
})
}
Loading

0 comments on commit f0a59c4

Please sign in to comment.