From 6284eb190de3eda2fcf04848f0fb10aee7921b13 Mon Sep 17 00:00:00 2001 From: MK <53529533+magiziz@users.noreply.github.com> Date: Tue, 31 Dec 2024 14:12:54 +0000 Subject: [PATCH] fix: prevent unnecessary retries for balance endpoint on unsupported networks (#3564) --- .changeset/great-feet-impress.md | 23 ++++++++++++ packages/common/src/utils/ConstantsUtil.ts | 5 ++- .../core/src/controllers/AccountController.ts | 4 +- .../index.ts | 15 +++++++- ...w3m-account-wallet-features-widget.test.ts | 37 ++++++++++++++++++- 5 files changed, 79 insertions(+), 5 deletions(-) create mode 100644 .changeset/great-feet-impress.md diff --git a/.changeset/great-feet-impress.md b/.changeset/great-feet-impress.md new file mode 100644 index 0000000000..4c5e124e23 --- /dev/null +++ b/.changeset/great-feet-impress.md @@ -0,0 +1,23 @@ +--- +'@reown/appkit-scaffold-ui': patch +'@reown/appkit-common': patch +'@reown/appkit-core': patch +'@reown/appkit-adapter-bitcoin': patch +'@reown/appkit-adapter-ethers': patch +'@reown/appkit-adapter-ethers5': patch +'@reown/appkit-adapter-solana': patch +'@reown/appkit-adapter-wagmi': patch +'@reown/appkit': patch +'@reown/appkit-utils': patch +'@reown/appkit-cdn': patch +'@reown/appkit-cli': patch +'@reown/appkit-experimental': patch +'@reown/appkit-polyfills': patch +'@reown/appkit-siwe': patch +'@reown/appkit-siwx': patch +'@reown/appkit-ui': patch +'@reown/appkit-wallet': patch +'@reown/appkit-wallet-button': patch +--- + +Fixed an issue where the balance endpoint was being called every 30 seconds for unsupported networks. \ No newline at end of file diff --git a/packages/common/src/utils/ConstantsUtil.ts b/packages/common/src/utils/ConstantsUtil.ts index 485c2c5e06..69a462f672 100644 --- a/packages/common/src/utils/ConstantsUtil.ts +++ b/packages/common/src/utils/ConstantsUtil.ts @@ -48,5 +48,8 @@ export const ConstantsUtil = { '0x55d398326f99059fF775485246999027B3197955', // Arbitrum '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9' - ] + ], + HTTP_STATUS_CODES: { + SERVICE_UNAVAILABLE: 503 + } } as const diff --git a/packages/core/src/controllers/AccountController.ts b/packages/core/src/controllers/AccountController.ts index f478ff8fe0..0e300a09bb 100644 --- a/packages/core/src/controllers/AccountController.ts +++ b/packages/core/src/controllers/AccountController.ts @@ -234,12 +234,11 @@ export const AccountController = { ChainController.setAccountProp('farcasterUrl', farcasterUrl, chain) }, - async fetchTokenBalance() { + async fetchTokenBalance(onError?: (error: unknown) => void) { const chainId = ChainController.state.activeCaipNetwork?.caipNetworkId const chain = ChainController.state.activeCaipNetwork?.chainNamespace const caipAddress = ChainController.state.activeCaipAddress const address = caipAddress ? CoreHelperUtil.getPlainAddress(caipAddress) : undefined - if ( state.lastRetry && !CoreHelperUtil.isAllowedRetry(state.lastRetry, 30 * ConstantsUtil.ONE_SEC_MS) @@ -262,6 +261,7 @@ export const AccountController = { } catch (error) { state.lastRetry = Date.now() + onError?.(error) SnackController.showError('Token Balance Unavailable') } }, diff --git a/packages/scaffold-ui/src/partials/w3m-account-wallet-features-widget/index.ts b/packages/scaffold-ui/src/partials/w3m-account-wallet-features-widget/index.ts index 1498718643..e17395b30a 100644 --- a/packages/scaffold-ui/src/partials/w3m-account-wallet-features-widget/index.ts +++ b/packages/scaffold-ui/src/partials/w3m-account-wallet-features-widget/index.ts @@ -222,7 +222,20 @@ export class W3mAccountWalletFeaturesWidget extends LitElement { } private watchSwapValues() { - this.watchTokenBalance = setInterval(() => AccountController.fetchTokenBalance(), 10000) + this.watchTokenBalance = setInterval( + () => AccountController.fetchTokenBalance(error => this.onTokenBalanceError(error)), + 10_000 + ) + } + + private onTokenBalanceError(error: unknown) { + if (error instanceof Error && error.cause instanceof Response) { + const statusCode = error.cause.status + + if (statusCode === CommonConstantsUtil.HTTP_STATUS_CODES.SERVICE_UNAVAILABLE) { + clearInterval(this.watchTokenBalance) + } + } } private listContentTemplate() { diff --git a/packages/scaffold-ui/test/partials/w3m-account-wallet-features-widget.test.ts b/packages/scaffold-ui/test/partials/w3m-account-wallet-features-widget.test.ts index 838ce06665..19f24639b9 100644 --- a/packages/scaffold-ui/test/partials/w3m-account-wallet-features-widget.test.ts +++ b/packages/scaffold-ui/test/partials/w3m-account-wallet-features-widget.test.ts @@ -4,12 +4,15 @@ import { fixture, elementUpdated } from '@open-wc/testing' import { AccountController, CoreHelperUtil, RouterController } from '@reown/appkit-core' import { html } from 'lit' import { HelpersUtil } from '../utils/HelpersUtil' +import { ConstantsUtil as CommonConstantsUtil } from '@reown/appkit-common' // --- Constants ---------------------------------------------------- // const WALLET_FEATURE_WIDGET_TEST_ID = 'w3m-account-wallet-features-widget' const MOCK_ADDRESS = '0xcd2a3d9f938e13cd947ec05abc7fe734df8dd826' const PROFILE_BUTTON = 'w3m-profile-button' +const SERVICE_UNAVAILABLE_MESSAGE = 'Service Unavailable' + const ACCOUNT = { namespace: 'eip155', address: '0x123', @@ -22,7 +25,7 @@ describe('W3mAccountWalletFeaturesWidget', () => { }) afterEach(() => { - vi.clearAllMocks() + vi.resetAllMocks() }) it('it should not return any components if address is not provided in AccountController', () => { @@ -106,4 +109,36 @@ describe('W3mAccountWalletFeaturesWidget', () => { expect(pushSpy).toHaveBeenCalledWith('Profile') }) + + it('should clearInterval when fetchTokenBalance fails after 10 seconds', async () => { + vi.useFakeTimers() + vi.spyOn(global, 'setInterval') + vi.spyOn(global, 'clearInterval') + vi.spyOn(AccountController, 'state', 'get').mockReturnValue({ + ...AccountController.state, + address: ACCOUNT.address + }) + + const element: W3mAccountWalletFeaturesWidget = await fixture( + html`` + ) + + expect(setInterval).toHaveBeenCalled() + + const response = new Response(SERVICE_UNAVAILABLE_MESSAGE, { + status: CommonConstantsUtil.HTTP_STATUS_CODES.SERVICE_UNAVAILABLE + }) + + const error = new Error(SERVICE_UNAVAILABLE_MESSAGE, { cause: response }) + + vi.spyOn(AccountController, 'fetchTokenBalance').mockImplementation(async callback => { + callback?.(error) + }) + + vi.advanceTimersByTime(10_000) + + expect(clearInterval).toHaveBeenCalledWith((element as any).watchTokenBalance) + + vi.useRealTimers() + }) })