diff --git a/mobile-app/app/api/transaction/transfer_domain.ts b/mobile-app/app/api/transaction/transfer_domain.ts index 9468a86fd3..5e75a702d2 100644 --- a/mobile-app/app/api/transaction/transfer_domain.ts +++ b/mobile-app/app/api/transaction/transfer_domain.ts @@ -12,7 +12,7 @@ import { fromAddress, Eth } from "@defichain/jellyfish-address"; import { NetworkName } from "@defichain/jellyfish-network"; import { ConvertDirection } from "@screens/enum"; import { parseUnits } from "ethers/lib/utils"; -import { getEthRpcUrl } from "@store/evmApi"; +import { getEthRpcUrl } from "@store/evm"; import TransferDomainV1 from "../../contracts/TransferDomainV1.json"; const TD_CONTRACT_ADDR = "0xdf00000000000000000000000000000000000001"; diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/hooks/EvmTokenBalances.ts b/mobile-app/app/screens/AppNavigator/screens/Portfolio/hooks/EvmTokenBalances.ts index f7e1263204..20e9f66bfc 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/hooks/EvmTokenBalances.ts +++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/hooks/EvmTokenBalances.ts @@ -2,10 +2,6 @@ import { useEffect, useState } from "react"; import { formatEther, formatUnits } from "viem"; import { WalletToken, useNetworkContext } from "@waveshq/walletkit-ui"; import { utils } from "ethers"; -import { - useGetEvmAddressDetailsMutation, - useGetEvmTokenBalancesMutation, -} from "@store/evmApi"; import { DomainType, useDomainContext } from "@contexts/DomainContext"; import { useSelector } from "react-redux"; import { RootState } from "@store"; @@ -13,6 +9,8 @@ import { useIsFocused } from "@react-navigation/native"; import { TokenData } from "@defichain/whale-api-client/dist/api/tokens"; import { useLogger } from "@shared-contexts/NativeLoggingProvider"; import { useWalletContext } from "@shared-contexts/WalletContext"; +import { useAppDispatch } from "@hooks/useAppDispatch"; +import { fetchEvmWalletDetails, fetchEvmTokenBalances } from "@store/evm"; interface AssociatedToken { [key: string]: TokenData; @@ -23,8 +21,6 @@ export function useEvmTokenBalances(): { evmTokens: WalletToken[] } { const [evmTokens, setEvmTokens] = useState([]); const [allTokensWithAddress, setAllTokensWithAddress] = useState({}); - const [getEvmAddressDetails] = useGetEvmAddressDetailsMutation(); - const [getTokenBalances] = useGetEvmTokenBalancesMutation(); const blockCount = useSelector((state: RootState) => state.block.count); const { network } = useNetworkContext(); const isFocused = useIsFocused(); @@ -32,6 +28,15 @@ export function useEvmTokenBalances(): { evmTokens: WalletToken[] } { const logger = useLogger(); const { allTokens } = useSelector((state: RootState) => state.wallet); + const { evmWalletDetails, evmTokenBalances } = useSelector( + (state: RootState) => state.evm, + ); + const dispatch = useAppDispatch(); + + useEffect(() => { + dispatch(fetchEvmWalletDetails({ network, evmAddress })); + dispatch(fetchEvmTokenBalances({ network, evmAddress })); + }, [network, evmAddress, blockCount]); useEffect(() => { setAllTokensWithAddress( @@ -42,6 +47,7 @@ export function useEvmTokenBalances(): { evmTokens: WalletToken[] } { }, {}), ); }, [allTokens]); + const getEvmTokens = async () => { const dfiToken: WalletToken = { id: "0-EVM", @@ -56,18 +62,12 @@ export function useEvmTokenBalances(): { evmTokens: WalletToken[] } { avatarSymbol: "EvmDFI", }; try { - const details = await getEvmAddressDetails({ - network, - evmAddress, - }).unwrap(); - const evmDfiBalance = formatEther(BigInt(details.coin_balance ?? 0)); - const tokensBalances = await getTokenBalances({ - network, - evmAddress, - }).unwrap(); + const evmDfiBalance = formatEther( + BigInt(evmWalletDetails?.coin_balance ?? 0), + ); dfiToken.amount = evmDfiBalance; setEvmTokens( - tokensBalances.reduce( + evmTokenBalances.reduce( (current: WalletToken[], each) => { const tokenAddress = each?.token?.address; const tokenDetails = allTokensWithAddress[tokenAddress] ?? null; @@ -106,7 +106,7 @@ export function useEvmTokenBalances(): { evmTokens: WalletToken[] } { if (isFocused && domain === DomainType.EVM) { getEvmTokens(); } - }, [evmAddress, blockCount, isFocused, domain]); + }, [evmAddress, blockCount, isFocused, domain, evmWalletDetails]); return { evmTokens }; } diff --git a/shared/store/evmApi.ts b/shared/store/evm.ts similarity index 55% rename from shared/store/evmApi.ts rename to shared/store/evm.ts index a5eba6f375..e724c53069 100644 --- a/shared/store/evmApi.ts +++ b/shared/store/evm.ts @@ -1,38 +1,93 @@ -import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react"; -import { EnvironmentNetwork } from "@waveshq/walletkit-core"; import { SecuredStoreAPI } from "@api"; +import { PayloadAction, createAsyncThunk, createSlice } from "@reduxjs/toolkit"; +import { EnvironmentNetwork } from "@waveshq/walletkit-core"; -export const evmApi = createApi({ - reducerPath: "evmApi", - baseQuery: fetchBaseQuery({ baseUrl: "" }), - endpoints: (builder) => ({ - getEvmAddressDetails: builder.mutation< - EvmAddressDetails, - { network: EnvironmentNetwork; evmAddress: string } - >({ - query: ({ network = EnvironmentNetwork.TestNet, evmAddress }) => ({ - url: `${getBlockscoutUrl(network)}/api/v2/addresses/${evmAddress}`, - method: "GET", - }), - }), - getEvmTokenBalances: builder.mutation< - EvmTokenBalance[], - { network: EnvironmentNetwork; evmAddress: string } - >({ - query: ({ network = EnvironmentNetwork.TestNet, evmAddress }) => ({ - url: `${getBlockscoutUrl( - network, - )}/api/v2/addresses/${evmAddress}/token-balances`, - method: "GET", - }), - }), - }), -}); +interface EvmWalletDetails { + hash: string; + name: string; + coin_balance: string; + exchange_rate: string; + implementation_address: string; + block_number_balance_updated_at: number; + creator_address_hash: string; + creation_tx_hash: string; +} -export const { - useGetEvmAddressDetailsMutation, - useGetEvmTokenBalancesMutation, -} = evmApi; +interface EvmToken { + address: string; + decimals: string; + name: string; + symbol: string; + type: string; +} + +interface EvmTokenBalance { + token_id: string; + value: string; + token: EvmToken; +} + +interface EvmState { + evmWalletDetails: EvmWalletDetails | null; + evmTokenBalances: EvmTokenBalance[]; +} + +const initialState: EvmState = { + evmWalletDetails: null, + evmTokenBalances: [], +}; + +export const fetchEvmWalletDetails = createAsyncThunk( + "wallet/fetchEvmWalletDetails", + async ({ + network, + evmAddress, + }: { + network: EnvironmentNetwork; + evmAddress: string; + }) => { + const url = getBlockscoutUrl(network); + const response = await fetch(`${url}/api/v2/addresses/${evmAddress}`); + return await response.json(); + }, +); + +export const fetchEvmTokenBalances = createAsyncThunk( + "wallet/fetchEvmTokenBalances", + async ({ + network, + evmAddress, + }: { + network: EnvironmentNetwork; + evmAddress: string; + }) => { + const url = getBlockscoutUrl(network); + const response = await fetch( + `${url}/api/v2/addresses/${evmAddress}/token-balances`, + ); + return await response.json(); + }, +); + +export const evm = createSlice({ + name: "evm", + initialState, + reducers: {}, + extraReducers: (builder) => { + builder.addCase( + fetchEvmWalletDetails.fulfilled, + (state, action: PayloadAction) => { + state.evmWalletDetails = action.payload; + }, + ); + builder.addCase( + fetchEvmTokenBalances.fulfilled, + (state, action: PayloadAction) => { + state.evmTokenBalances = action.payload; + }, + ); + }, +}); const getBlockscoutUrl = (network: EnvironmentNetwork) => { // TODO: Add proper blockscout url for each network @@ -67,28 +122,3 @@ export const getEthRpcUrl = async () => { return "https://changi.dfi.team"; // TODO: add final eth rpc url for mainnet, with proper domain name } }; - -interface EvmToken { - address: string; - decimals: string; - name: string; - symbol: string; - type: string; -} - -interface EvmTokenBalance { - token_id: string; - value: string; - token: EvmToken; -} - -interface EvmAddressDetails { - hash: string; - name: string; - coin_balance: string; - exchange_rate: string; - implementation_address: string; - block_number_balance_updated_at: number; - creator_address_hash: string; - creation_tx_hash: string; -} diff --git a/shared/store/index.ts b/shared/store/index.ts index 7a2cfddefa..d12dce4261 100644 --- a/shared/store/index.ts +++ b/shared/store/index.ts @@ -13,7 +13,7 @@ import { authentication } from "./authentication"; import { loans } from "./loans"; import { auctions } from "./auctions"; import { futureSwaps } from "./futureSwap"; -import { evmApi } from "./evmApi"; +import { evm } from "./evm"; /** * RootState for DeFiChain Wallet App * @@ -37,13 +37,12 @@ export function initializeStore() { [statusWebsiteSlice.reducerPath]: statusWebsiteSlice.reducer, userPreferences: userPreferences.reducer, futureSwaps: futureSwaps.reducer, - [evmApi.reducerPath]: evmApi.reducer, + evm: evm.reducer, }, middleware: (getDefaultMiddleware) => getDefaultMiddleware({ serializableCheck: false }) .concat(announcementWebsiteSlice.middleware) - .concat(statusWebsiteSlice.middleware) - .concat(evmApi.middleware), + .concat(statusWebsiteSlice.middleware), }); }