Skip to content

refactor(web): use new gateway RTK API #4752

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

Merged
merged 8 commits into from
Jan 16, 2025
Merged

refactor(web): use new gateway RTK API #4752

merged 8 commits into from
Jan 16, 2025

Conversation

compojoom
Copy link
Contributor

@compojoom compojoom commented Jan 9, 2025

What it solves

The PR ads the @safe-global/store package to the web application. The store package exposes auto-generated endpoints for interaction with the gateway API. We can use the hooks in it to replace a lot of code from the old gateway sdk.

The benefit of using the store package is that RTK takes care of fetching and caching of the data. If we have multiple components on the page relying on the same piece of data only one fetch request will be sent.

Next to the new store package I've added the MSW package for testing our code. Instead of mocking the response on our RTK functions, we just mock json responses at endpoints that our code calls. MSW is helping in this by outputing endpoints that don't have a mocked response. Our code no longer needs to mock fetch and our tests behave more like they would do for the user. A network call will start with an undefined data, then will resolve with data or fail (depending on what we specify for the endpoint)

How this PR fixes it

How to test it

This PR changes the useCurrencies call from useAsync(getFiatCurrencies) to the new rtk hook: useBalancesGetSupportedFiatCodesV1Query

Going on the assets page one should see all supported currencies in the currencies dropdown.

Screenshots

Checklist

  • I've tested the branch on mobile 📱
  • I've documented how it affects the analytics (if at all) 📊
  • I've written a unit/e2e test for it (if applicable) 🧑‍💻

Instead of using an async call from the old safe-gateway-typescript-sdk,
we are now using the RTK hooks from the @safe-global/store package.
Copy link

github-actions bot commented Jan 9, 2025

Copy link

github-actions bot commented Jan 9, 2025

Coverage report for apps/web

St.
Category Percentage Covered / Total
🟡 Statements
77.42% (+3.17% 🔼)
13771/17788
🔴 Branches
56.85% (+4.85% 🔼)
3478/6118
🟡 Functions
62.69% (+5.34% 🔼)
2067/3297
🟡 Lines
78.84% (+3.05% 🔼)
12421/15754
Show new covered files 🐣
St.
File Statements Branches Functions Lines
🟢
... / gateway.ts
87.5% 75% 100% 100%
🟡
... / index.tsx
80% 100% 66.67% 78.95%
Show files with reduced coverage 🔻
St.
File Statements Branches Functions Lines
🟢
... / broadcast.ts
100%
90% (-10% 🔻)
100% 100%
🟢 src/utils/chains.ts 93.1%
90% (-2.31% 🔻)
100% 100%
🟢
... / safePass.ts
88.89% (-2.02% 🔻)
100% (+25% 🔼)
50%
85.71% (-3.17% 🔻)
🟢
... / pk-popup-store.ts
80% (-10% 🔻)
50% 0% 88.89%
🟢
... / utils.ts
90.91% (-0.34% 🔻)
71.88% (-8.77% 🔻)
90% (-0.48% 🔻)
95.08% (-0.23% 🔻)
🟢
... / firebase.ts
86.96% (+7.79% 🔼)
72.73% (-4.2% 🔻)
100%
89.47% (+9.47% 🔼)
🟢
... / useNotificationPreferences.ts
86.36% (-2.65% 🔻)
40% (-26.67% 🔻)
80.65% (-1.17% 🔻)
85.54% (-2.69% 🔻)
🟢
... / stake.ts
75% (-25% 🔻)
100% 100% 100%
🟡
... / index.tsx
67.65% (-0.92% 🔻)
42.11% 20%
69.84% (-0.93% 🔻)

Test suite run success

1761 tests passing in 239 suites.

Report generated by 🧪jest coverage report action from 1c6a94c

Copy link

github-actions bot commented Jan 9, 2025

📦 Next.js Bundle Analysis for @safe-global/web

This analysis was generated by the Next.js Bundle Analysis action. 🤖

⚠️ Global Bundle Size Increased

Page Size (compressed)
global 1.06 MB (🟡 +69.85 KB)
Details

The global bundle is the javascript bundle that loads alongside every page. It is in its own category because its impact is much higher - an increase to its size means that every page on your website loads slower, and a decrease means every page loads faster.

Any third party scripts you have added directly to your app using the <script> tag are not accounted for in this analysis

If you want further insight into what is behind the changes, give @next/bundle-analyzer a try!

Thirty-two Pages Changed Size

The following pages changed size from the code in this PR compared to its base branch:

Page Size (compressed) First Load
/ 509 B (🟢 -1 B) 1.06 MB
/address-book 23.21 KB (🟡 +143 B) 1.08 MB
/apps 35.97 KB (🟡 +2.25 KB) 1.09 MB
/apps/custom 34.03 KB (🟡 +2.25 KB) 1.09 MB
/apps/open 55.56 KB (🟡 +1.95 KB) 1.11 MB
/balances 30.01 KB (🟡 +314 B) 1.09 MB
/balances/nfts 9.52 KB (🟢 -23 B) 1.07 MB
/bridge 2.55 KB (🟢 -5 B) 1.06 MB
/cookie 8.77 KB (🟡 +1 B) 1.07 MB
/home 61.54 KB (🟡 +2.28 KB) 1.12 MB
/licenses 2.46 KB (🟢 -1 B) 1.06 MB
/new-safe/advanced-create 26.38 KB (🟢 -72 B) 1.08 MB
/new-safe/create 25.53 KB (🟢 -64 B) 1.08 MB
/privacy 14.57 KB (🟡 +2 B) 1.07 MB
/settings/appearance 2.25 KB (🟡 +1 B) 1.06 MB
/settings/cookies 1.87 KB (🟡 +1 B) 1.06 MB
/settings/modules 4.06 KB (🟡 +3 B) 1.06 MB
/settings/notifications 6.34 KB (🟢 -14.98 KB) 1.06 MB
/settings/safe-apps 20.35 KB (🟡 +2.08 KB) 1.08 MB
/settings/security 2.34 KB (🟡 +2 B) 1.06 MB
/settings/setup 30.83 KB (🟡 +102 B) 1.09 MB
/share/safe-app 7.55 KB (🟢 -8 B) 1.06 MB
/stake 617 B (🟢 -2 B) 1.06 MB
/swap 763 B (🟡 +3 B) 1.06 MB
/terms 12.93 KB (🟡 +1 B) 1.07 MB
/transactions 99.45 KB (🟡 +2.88 KB) 1.15 MB
/transactions/history 99.41 KB (🟡 +2.88 KB) 1.15 MB
/transactions/messages 60.25 KB (🟡 +1.95 KB) 1.12 MB
/transactions/msg 56.5 KB (🟡 +1.95 KB) 1.11 MB
/transactions/queue 49.36 KB (🟡 +1.96 KB) 1.11 MB
/transactions/tx 48.71 KB (🟡 +1.95 KB) 1.1 MB
/welcome/accounts 408 B (🟡 +1 B) 1.06 MB
Details

Only the gzipped size is provided here based on an expert tip.

First Load is the size of the global bundle plus the bundle for the individual page. If a user were to show up to your website and land on a given page, the first load size represents the amount of javascript that user would need to download. If next/link is used, subsequent page loads would only need to download that page's bundle (the number in the "Size" column), since the global bundle has already been downloaded.

Any third party scripts you have added directly to your app using the <script> tag are not accounted for in this analysis

Next to the size is how much the size has increased or decreased compared with the base branch of this PR. If this percentage has increased by 20% or more, there will be a red status indicator applied, indicating that special attention should be given to this.

Moving the msw handlers to the shared test package. This way we can
reuse the same handlers in the web app as we are calling the same
endpoints.
Mock Service Worker (MSW) is an API mocking library. With MSW we can
intercept outgoing requests, observe them, and respond to them using
mocked responses. This simplifies our tests a lot.

Up until now we were mocking the method that would do a network request.
This always required knowledge of the internal workings of our APIs.

MSW runs in the background and outputs a warning in the terminal when we
are trying to access a network resource for which we haven’t mocked a
response. This way we only need to provide dummy data for our endpoints
instead of fiddling with internal logic.

Updating to MSW outlined problems in JSDOM and I had to update to
jest-fixed-jsdom. We were manually fixing some of those problems like
missing global fetch, response and request objects. Now our jsdom
environment has the global objects that are available both in the
browser and in node, so we don’t introduce pollyfills and maintain them.
Copy link

github-actions bot commented Jan 13, 2025

Coverage (52%)
File% Stmts% Branch% Funcs% LinesUncovered Line #s
All files51.8145.7947.2152.15 
src0000 
   react-app-env.d.ts0000 
src/components/Alert10091.66100100 
   Alert.tsx10091.6610010055
   index.ts0000 
src/components/Badge87.587.510087.5 
   Badge.tsx85.7187.510085.7149
   index.ts0000 
   theme.ts100100100100 
src/components/BlurredIdenticonBackground0000 
   BlurredIdenticonBackground.tsx000014–51
   index.tsx0000 
src/components/ChainsDisplay10084.61100100 
   ChainsDisplay.tsx10084.6110010015–18
   index.ts0000 
src/components/Container10075100100 
   Container.tsx1007510010032
   index.ts0000 
src/components/CopyButton010000 
   CopyButton.tsx0100005–10
   index.ts0000 
src/components/DataRow100100100100 
   DataRow.tsx100100100100 
   index.ts0000 
src/components/Dropdown88.46607088 
   Dropdown.tsx81.256057.1481.2555, 63, 128
   index.ts0000 
   sheetComponents.tsx100100100100 
src/components/EthAddress0000 
   ETHAddress.tsx000011–12
   index.ts0000 
src/components/Fiat100100100100 
   Fiat.tsx100100100100 
   index.ts0000 
src/components/Identicon100100100100 
   Identicon.tsx100100100100 
   index.ts0000 
src/components/InnerShadow100100100100 
   InnerShadow.tsx100100100100 
   index.ts0000 
src/components/Logo100100100100 
   Logo.tsx100100100100 
   index.ts0000 
src/components/SafeButton100100100100 
   SafeButton.tsx100100100100 
   index.ts0000 
src/components/SafeFontIcon87.585.7110087.5 
   SafeFontIcon.tsx87.585.7110087.528
   index.ts0000 
src/components/SafeListItem10066.66100100 
   SafeListItem.tsx10066.6610010074–88
   index.tsx0000 
src/components/SafeTab250026.31 
   SafeTab.tsx44.44100044.4413–25
   SafeTabBar.tsx9.09001018–38
   index.tsx0000 
   types.ts0000 
src/components/StatusBanners/PendingTransactions10050100100 
   PendingTransactions.tsx1005010010017
   index.tsx0000 
src/components/Tab0000 
   TabNameContext.tsx00003–10
src/components/Title100100100100 
   LargeHeaderTitle.tsx100100100100 
   NavBarTitle.tsx100100100100 
   index.ts0000 
src/components/TxInfo23.84.545023.8 
   TxInfo.tsx23.84.545023.845–96, 100
   index.tsx0000 
src/components/navigation100100100100 
   TabBarIcon.tsx100100100100 
   index.ts0000 
src/components/transactions-list/Card/AccountCard10075100100 
   AccountCard.tsx1007510010052
   index.ts0000 
src/components/transactions-list/Card/AssetsCard100100100100 
   AssetsCard.tsx100100100100 
   index.tsx0000 
src/components/transactions-list/Card/TxBatchCard100100100100 
   TxBatchCard.tsx100100100100 
   index.tsx0000 
src/components/transactions-list/Card/TxConflictingCard010000 
   TxConflictingCard.tsx01000013–31
   index.tsx0000 
src/components/transactions-list/Card/TxContractInteractionCard100100100100 
   TxContractInteractionCard.tsx100100100100 
   index.tsx0000 
src/components/transactions-list/Card/TxCreationCard100100100100 
   TxCreationCard.tsx100100100100 
   index.ts0000 
src/components/transactions-list/Card/TxGroupedCard90.9757590.9 
   TxGroupedCard.tsx90.9757590.957
   index.tsx0000 
src/components/transactions-list/Card/TxRejectionCard100100100100 
   TxRejectionCard.tsx100100100100 
   index.tsx0000 
src/components/transactions-list/Card/TxSafeAppCard100100100100 
   TxSafeAppCard.tsx100100100100 
   index.tsx0000 
src/components/transactions-list/Card/TxSettingsCard10050100100 
   TxSettingsCard.tsx1005010010017
   index.tsx0000 
src/components/transactions-list/Card/TxSwapCard100100100100 
   TxSwapCard.tsx100100100100 
   index.tsx0000 
src/components/transactions-list/Card/TxTokenCard88.8880.5510088.88 
   TxTokenCard.tsx88.8880.5510088.8840, 70
   index.tsx0000 
src/config44.4483.33044.44 
   constants.ts10083.3310010015
   ethers.ts01000010–38
src/features/Assets010000 
   Assets.container.tsx0100009–21
   index.tsx0000 
   styles.ts010010003
src/features/Assets/components/AccountItem91.6668.7510090.9 
   AccountItem.tsx91.6668.7510090.924
   index.ts0000 
src/features/Assets/components/AccountItem/hooks5002553.84 
   useEditAccountItem.ts5002553.8415–29
src/features/Assets/components/AssetsHeader0000 
   AssetsHeader.container.tsx0100006–13
   AssetsHeader.tsx000015
   index.tsx0000 
   styles.ts010010003
src/features/Assets/components/Balance0000 
   Balance.container.tsx01000014–36
   Balance.tsx000025–42
   ChainItems.tsx000017–28
   index.tsx0000 
src/features/Assets/components/Fallback10075100100 
   Fallback.tsx1007510010012
   index.ts0000 
src/features/Assets/components/MyAccounts88.2310066.66100 
   MyAccounts.container.tsx100100100100 
   MyAccountsFooter.tsx71.4210033.33100 
   index.ts0000 
src/features/Assets/components/MyAccounts/hooks43.7533.335044.82 
   useMyAccountsService.ts100100100100 
   useMyAccountsSortable.ts000012–38
src/features/Assets/components/NFTs10081.81100100 
   NFTItem.tsx100501001008
   NFTs.container.tsx10088.8810010026
   index.tsx0000 
src/features/Assets/components/Navbar0000 
   Navbar.tsx000018–66
   index.tsx0000 
src/features/Assets/components/NoFunds100100100100 
   EmptyToken.tsx100100100100 
   NoFunds.tsx100100100100 
   index.ts0000 
src/features/Assets/components/Tokens100100100100 
   Tokens.container.tsx100100100100 
   index.tsx0000 
src/features/Notifications010000 
   Notifications.container.tsx0100004–5
   index.tsx0000 
src/features/Onboarding100100100100 
   Onboarding.container.tsx100100100100 
   index.ts0000 
src/features/Onboarding/components/OnboardingCarousel9510087.595 
   CarouselFeedback.tsx100100100100 
   CarouselItem.tsx100100100100 
   OnboardingCarousel.tsx83.331008083.3318
   index.ts0000 
   items.tsx100100100100 
src/features/Onboarding/components/OnboardingHeader100100100100 
   OnboardingHeader.tsx100100100100 
   index.ts0000 
src/features/Onboarding/components/ParticlesLogo100100100100 
   ParticlesLogo.tsx100100100100 
   index.ts0000 
src/features/PendingTx0000 
   PendingTx.container.tsx0100006–8
   index.tsx0000 
   utils.tsx000021–133
src/features/PendingTx/components/PendingTxList0000 
   PendingTxList.container.tsx000033–63
   index.ts0000 
src/features/Settings0000 
   Settings.container.tsx00007–14
   Settings.tsx000020–137
   index.tsx0000 
src/features/Settings/components/AppSettings010000 
   AppSettings.container.tsx0100007–20
   AppSettings.tsx01000010–11
   index.ts0000 
src/features/Settings/components/IdenticonWithBadge10050100100 
   IdenticonWithBadge.tsx1005010010021–22
   index.ts0000 
src/features/Settings/components/Navbar0000 
   Navbar.tsx01000010–27
   SettingsButton.tsx0100006–15
   SettingsMenu.tsx000017–81
   index.ts0000 
src/features/Signers010000 
   Signers.container.tsx0100003–4
   index.tsx0000 
src/features/TxHistory0000 
   TxHistory.container.tsx000011–37
   index.tsx0000 
   utils.tsx000018–58
src/features/TxHistory/components/TxHistoryList0000 
   TxHistoryList.tsx000018–32
   index.ts0000 
src/hooks/useCopyAndDispatchToast100100100100 
   index.ts100100100100 
src/hooks/useInfiniteScroll75508073.33 
   index.ts0000 
   useInfiniteScroll.ts75508073.3330–35
src/hooks/usePendingTxs0000 
   index.ts000015–40
src/hooks/useSign805010080 
   index.ts0000 
   useSign.ts80501008034, 43, 55, 62, 67
src/hooks/useTransactionType91.6679.1610091.66 
   index.tsx91.6679.1610091.66116–124
src/navigation0000 
   useScrollableHeader.tsx000022–47
src/services/exceptions88.8810010088.88 
   utils.ts88.8810010088.8814
src/store47.674.1633.3346.25 
   activeSafeSlice.ts751005071.4219–22
   constants.ts500050309–322
   index.ts91.665010091.6644
   myAccountsSlice.ts83.33100508013
   safesSlice.ts37.510012.538.4638–48, 57–58
   storage.ts7.14007.1412–67
   txHistorySlice.ts100100100100 
src/store/chains68.421004075 
   index.ts68.42100407517, 30–33
src/store/hooks100100100100 
   index.ts100100100100 
src/theme100100100100 
   navigation.ts100100100100 
   tamagui.config.ts100100100100 
   tokens.ts100100100100 
src/theme/helpers10081.81100100 
   utils.ts10081.8110010037, 41
src/theme/palettes100100100100 
   darkPalette.ts100100100100 
   lightPalette.ts100100100100 
src/theme/provider59.0927.776059.09 
   font.tsx90501009034
   safeTheme.tsx10037.510010019–34
   toastProvider.tsx000010–29
src/utils55.7631.558.4955.1 
   date.ts9666.6685.7110031, 35–39
   formatters.ts908010088.889
   gateway.ts100100100100 
   logger.ts000010–85
   transaction-guards.ts79.24606880.7650–56, 66, 98, 102, 116, 120
   transactions.tsx00004–29

afterAll(() => {
// @ts-ignore
delete global.fetch
global.fetch = originalGlobalFetch
})
Copy link
Contributor Author

@compojoom compojoom Jan 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@iamacook you wrote the original version of those tests. Why were you deleting the global.fetch object? I didn't fully get it. Can you maybe check if those tests make sense with the new fixed jsdom environment. Maybe you did those things because jsdom was broken and we can simplify them now(less mocking?).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The response is stubbed in each test.

Comment on lines +141 to +143
if (!options?.skipBroadcast) {
listenToBroadcast(store)
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in jsdom the BroadcastChannel object was actually missing. Note that it is generally available in the Browser and in Node. With the jest-fixed-jsdom this object was now available and jest was complaining that we have open listeners. That's why I added this line to be able to control when we need the broadcast listeners in the tests.

@@ -0,0 +1,62 @@
import { http, HttpResponse } from 'msw'
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The handlers are now shared between web and mobile. The idea for this handlers would be to have default data for the endpoints we use across the project. We should combine this with the fake builders.

note how every response endpoint specifies the type of the returned JSON. With this whenever a type in the store package change we can be sure that we also need to update a test as the type would become invalid.

@compojoom compojoom requested a review from katspaugh January 13, 2025 16:00
@@ -71,7 +71,7 @@ describe('useNotificationTracking', () => {
})

const _entries = await entries(createNotificationTrackingIndexedDb())
expect(Object.fromEntries(_entries)).toStrictEqual({
expect(Object.fromEntries(_entries)).toEqual({
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was this change necessary?

Comment on lines +10 to +57
items: [
{
tokenInfo: {
name: 'Ethereum',
symbol: 'ETH',
decimals: 18,
address: '0x',
type: 'ERC20',
logoUri: 'https://safe-transaction-assets.safe.global/chains/1/chain_logo.png',
},
balance: '1000000000000000000',
fiatBalance: '2000',
fiatConversion: '2000',
},
],
fiatTotal: '2000',
})
}),
http.get<never, never, CollectiblePage>(`${GATEWAY_URL}/v2/chains/:chainId/safes/:safeAddress/collectibles`, () => {
return HttpResponse.json({
count: 2,
next: null,
previous: null,
results: [
{
id: '1',
address: '0x123',
tokenName: 'Cool NFT',
tokenSymbol: 'CNFT',
logoUri: 'https://example.com/nft1.png',
name: 'NFT #1',
description: 'A cool NFT',
uri: 'https://example.com/nft1.json',
imageUri: 'https://example.com/nft1.png',
},
{
id: '2',
address: '0x456',
tokenName: 'Another NFT',
tokenSymbol: 'ANFT',
logoUri: 'https://example.com/nft2.png',
name: 'NFT #2',
description: 'Another cool NFT',
uri: 'https://example.com/nft2.json',
imageUri: 'https://example.com/nft2.png',
},
],
})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: not necessary here but if there are builders, we could use them here to have dynamic mock data.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think that we should move some of the builders to the test package. But that would be something for a different PR.

Funny enough since the last test was setting it to false we were going
back to the correct value, but this was just chance :)
Copy link
Member

@katspaugh katspaugh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

@compojoom compojoom merged commit 672fdcc into dev Jan 16, 2025
17 checks passed
@compojoom compojoom deleted the rtk-safe branch January 16, 2025 08:59
@github-actions github-actions bot locked and limited conversation to collaborators Jan 16, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants