diff --git a/mobile-app/app/components/__snapshots__/PinTextInput.test.tsx.snap b/mobile-app/app/components/__snapshots__/PinTextInput.test.tsx.snap index 533f83c45d..3fe3dc5f20 100644 --- a/mobile-app/app/components/__snapshots__/PinTextInput.test.tsx.snap +++ b/mobile-app/app/components/__snapshots__/PinTextInput.test.tsx.snap @@ -232,7 +232,7 @@ exports[`Pin text input should match snapshot 1`] = ` "bottom": 0, "fontSize": 1, "left": 0, - "opacity": 0.01, + "opacity": 0.015, "position": "absolute", "right": 0, "top": 0, diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/Announcements.tsx b/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/Announcements.tsx index ec18d30243..b5e03bc5f1 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/Announcements.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/Announcements.tsx @@ -25,6 +25,11 @@ import { useServiceProviderContext, useThemeContext, } from "@waveshq/walletkit-ui"; +import { useCustomServiceProviderContext } from "@contexts/CustomServiceProvider"; +import { useSelector } from "react-redux"; +import { RootState } from "@store"; +import { useDomainContext } from "@contexts/DomainContext"; +import { useEVMProvider } from "@contexts/EVMProvider"; import { blockChainIsDownContent, useDeFiChainStatus, @@ -41,9 +46,14 @@ export function Announcements(): JSX.Element { useDeFiChainStatus(); const { isCustomUrl } = useServiceProviderContext(); - const { isBlockchainDown } = useApiStatus(); + const { chainId } = useEVMProvider(); + const { isEvmFeatureEnabled } = useDomainContext(); + const { isCustomEvmUrl, isCustomEthRpcUrl } = + useCustomServiceProviderContext(); + const { evmUrlHasError } = useSelector((state: RootState) => state.evm); + const customServiceProviderIssue: AnnouncementData[] = [ { lang: { @@ -70,25 +80,25 @@ export function Announcements(): JSX.Element { "0.0.0", language, hiddenAnnouncements, - emergencyMsgContent + emergencyMsgContent, ); const blockchainIsDownAnnouncement = findDisplayedAnnouncementForVersion( "0.0.0", language, hiddenAnnouncements, - blockchainStatusAnnouncement + blockchainStatusAnnouncement, ); const oceanIsDownAnnouncement = findDisplayedAnnouncementForVersion( "0.0.0", language, hiddenAnnouncements, - oceanStatusAnnouncement + oceanStatusAnnouncement, ); const announcement = findDisplayedAnnouncementForVersion( nativeApplicationVersion ?? "0.0.0", language, hiddenAnnouncements, - announcements + announcements, ); /* @@ -108,13 +118,17 @@ export function Announcements(): JSX.Element { // To display warning message in Announcement banner when blockchain is down for > 45 mins if (isBlockchainDown && !isCustomUrl) { return setEmergencyMsgContent(blockChainIsDownContent); - } else if (isBlockchainDown && isCustomUrl) { + } else if ( + (isBlockchainDown && isCustomUrl) || + (isEvmFeatureEnabled && isCustomEvmUrl && evmUrlHasError) || + (isEvmFeatureEnabled && isCustomEthRpcUrl && !chainId) + ) { return setEmergencyMsgContent(customServiceProviderIssue); } else { return setEmergencyMsgContent(undefined); } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isBlockchainDown]); + }, [isBlockchainDown, evmUrlHasError, chainId]); if (!isSuccess || announcementToDisplay === undefined) { return <>; @@ -265,7 +279,7 @@ export function AnnouncementBannerV2({ "border-mono-dark-v2-900": isOtherAnnouncement && !isLight, "border-orange-v2": announcement.type === "OUTAGE", "border-red-v2": announcement.type === "EMERGENCY", - } + }, ), containerStyle?.style, ]} @@ -364,7 +378,7 @@ export function findDisplayedAnnouncementForVersion( version: string, language: string, hiddenAnnouncements: string[], - announcements?: AnnouncementData[] + announcements?: AnnouncementData[], ): Announcement | undefined { if (announcements === undefined || announcements.length === 0) { return; @@ -393,7 +407,7 @@ export function findDisplayedAnnouncementForVersion( function getDisplayAnnouncement( hiddenAnnouncements: string[], - announcement: AnnouncementData + announcement: AnnouncementData, ): boolean { if (announcement === undefined) { return false; diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/DFIBalanceCard.test.tsx b/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/DFIBalanceCard.test.tsx index 5c5f11e026..51ae8df6ab 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/DFIBalanceCard.test.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/DFIBalanceCard.test.tsx @@ -117,6 +117,7 @@ describe("DFI Balance Card", () => { evmWalletDetails: null, evmTokenBalances: [], hasFetchedEvmTokens: true, + evmUrlHasError: false, }, }; const store = configureStore({ diff --git a/shared/store/evm.ts b/shared/store/evm.ts index ec5fd0b9d5..99dc3ba8f6 100644 --- a/shared/store/evm.ts +++ b/shared/store/evm.ts @@ -33,14 +33,18 @@ interface EvmState { evmWalletDetails: EvmWalletDetails | null; evmTokenBalances: EvmTokenBalance[]; hasFetchedEvmTokens: boolean; + evmUrlHasError: boolean; } const initialState: EvmState = { evmWalletDetails: null, evmTokenBalances: [], hasFetchedEvmTokens: false, + evmUrlHasError: false, }; +const SUCCESS_STATUS_CODE = 200; + export const fetchEvmWalletDetails = createAsyncThunk( "wallet/fetchEvmWalletDetails", async ({ @@ -58,15 +62,19 @@ export const fetchEvmWalletDetails = createAsyncThunk( if (isPlayground(network) && provider !== null) { const balance = await provider.getBalance(evmAddress); return { - coin_balance: balance.toString(), + data: { + coin_balance: balance.toString(), + }, + statusCode: SUCCESS_STATUS_CODE, }; } const response = await fetch(`${evmUrl}/api/v2/addresses/${evmAddress}`); + const statusCode = response.status; const data = await response.json(); if (data.message === "Not found") { - return {}; + return { data: {}, statusCode }; } - return data; + return { data, statusCode }; }, ); @@ -101,17 +109,21 @@ export const fetchEvmTokenBalances = createAsyncThunk( }; }); const res = await Promise.all(tokens); - return res.filter((each) => each.value !== "0"); + return { + data: res.filter((each) => each.value !== "0"), + statusCode: SUCCESS_STATUS_CODE, + }; } const response = await fetch( `${evmUrl}/api/v2/addresses/${evmAddress}/token-balances`, ); + const statusCode = response.status; const data = await response.json(); if (data.message === "Not found") { - return []; + return { data: [], statusCode }; } - return data; + return { data, statusCode }; }, ); @@ -122,16 +134,32 @@ export const evm = createSlice({ extraReducers: (builder) => { builder.addCase( fetchEvmWalletDetails.fulfilled, - (state, action: PayloadAction) => { - state.evmWalletDetails = action.payload; + ( + state, + action: PayloadAction<{ data: EvmWalletDetails; statusCode: number }>, + ) => { + state.evmWalletDetails = action.payload.data; + state.evmUrlHasError = + action.payload.statusCode !== SUCCESS_STATUS_CODE; }, ); builder.addCase( fetchEvmTokenBalances.fulfilled, - (state, action: PayloadAction) => { - state.evmTokenBalances = action.payload; + ( + state, + action: PayloadAction<{ data: EvmTokenBalance[]; statusCode: number }>, + ) => { + state.evmTokenBalances = action.payload.data; state.hasFetchedEvmTokens = true; + state.evmUrlHasError = + action.payload.statusCode !== SUCCESS_STATUS_CODE; }, ); + builder.addCase(fetchEvmWalletDetails.rejected, (state) => { + state.evmUrlHasError = true; + }); + builder.addCase(fetchEvmTokenBalances.rejected, (state) => { + state.evmUrlHasError = true; + }); }, });