From c7dc3aafe55aa363fd4035da31543c583f9f29e3 Mon Sep 17 00:00:00 2001 From: Tomas Martykan Date: Mon, 10 Feb 2025 13:48:05 +0100 Subject: [PATCH] feat(suite-native): add walletconnect --- .../connect-dependencies.txt | 1 + .../mobile-dependencies.txt | 5 + suite-native/app/package.json | 7 + suite-native/app/src/initActions.ts | 6 + .../app/src/navigation/RootStackNavigator.tsx | 14 +- suite-native/app/tsconfig.json | 3 + .../src/__tests__/featureFlagsSlice.test.ts | 3 + .../feature-flags/src/featureFlagsSlice.ts | 3 + suite-native/intl/src/en.ts | 28 ++++ .../module-connect-popup/package.json | 1 + .../src/hooks/useConnectPopupNavigation.ts | 23 ++- .../module-connect-popup/src/index.ts | 2 + .../src/screens/WalletConnectPairScreen.tsx | 107 ++++++++++++++ .../WalletConnectSessionPopupScreen.tsx | 137 ++++++++++++++++++ .../module-connect-popup/tsconfig.json | 3 + .../src/components/FeatureFlags.tsx | 1 + .../src/components/FeaturesSettings.tsx | 12 ++ suite-native/navigation/src/navigators.ts | 2 + suite-native/navigation/src/routes.ts | 2 + suite-native/state/package.json | 1 + suite-native/state/src/reducers.ts | 5 + suite-native/state/tsconfig.json | 3 + yarn.lock | 99 +++++++++++++ 23 files changed, 462 insertions(+), 6 deletions(-) create mode 100644 suite-native/module-connect-popup/src/screens/WalletConnectPairScreen.tsx create mode 100644 suite-native/module-connect-popup/src/screens/WalletConnectSessionPopupScreen.tsx diff --git a/scripts/list-outdated-dependencies/connect-dependencies.txt b/scripts/list-outdated-dependencies/connect-dependencies.txt index 407d7632e35..dec6e2dc0b9 100644 --- a/scripts/list-outdated-dependencies/connect-dependencies.txt +++ b/scripts/list-outdated-dependencies/connect-dependencies.txt @@ -94,3 +94,4 @@ scroll-into-view-if-needed @reown/walletkit @walletconnect/core @walletconnect/utils +@walletconnect/react-native-compat diff --git a/scripts/list-outdated-dependencies/mobile-dependencies.txt b/scripts/list-outdated-dependencies/mobile-dependencies.txt index 9790db953fa..2a5984b204e 100644 --- a/scripts/list-outdated-dependencies/mobile-dependencies.txt +++ b/scripts/list-outdated-dependencies/mobile-dependencies.txt @@ -77,3 +77,8 @@ fantasticon @whatwg-node/events abortcontroller-polyfill event-target-shim +@react-native-async-storage/async-storage +@types/fast-text-encoding +@types/react-native-get-random-values +fast-text-encoding +react-native-get-random-values \ No newline at end of file diff --git a/suite-native/app/package.json b/suite-native/app/package.json index dad471adb95..4ad09a14af6 100644 --- a/suite-native/app/package.json +++ b/suite-native/app/package.json @@ -23,6 +23,7 @@ "dependencies": { "@gorhom/bottom-sheet": "5.0.5", "@mobily/ts-belt": "^3.13.1", + "@react-native-async-storage/async-storage": "^2.1.1", "@react-native-community/netinfo": "^11.4.1", "@react-native/metro-config": "^0.76.1", "@react-navigation/bottom-tabs": "6.6.1", @@ -42,6 +43,7 @@ "@suite-common/token-definitions": "workspace:*", "@suite-common/wallet-core": "workspace:*", "@suite-common/wallet-types": "workspace:*", + "@suite-common/walletconnect": "workspace:*", "@suite-native/accounts": "workspace:*", "@suite-native/alerts": "workspace:*", "@suite-native/analytics": "workspace:*", @@ -83,6 +85,7 @@ "@trezor/styles": "workspace:*", "@trezor/theme": "workspace:*", "@trezor/trezor-user-env-link": "workspace:*", + "@walletconnect/react-native-compat": "^2.18.0", "@whatwg-node/events": "0.1.2", "abortcontroller-polyfill": "1.7.6", "buffer": "^6.0.3", @@ -104,6 +107,7 @@ "expo-system-ui": "^4.0.2", "expo-updates": "0.26.6", "expo-video": "^2.0.1", + "fast-text-encoding": "^1.0.6", "lottie-react-native": "^7.1.0", "node-libs-browser": "^2.2.1", "react": "18.2.0", @@ -111,6 +115,7 @@ "react-native": "0.76.1", "react-native-edge-to-edge": "^1.3.1", "react-native-gesture-handler": "^2.21.0", + "react-native-get-random-values": "^1.11.0", "react-native-keyboard-aware-scroll-view": "0.9.5", "react-native-mmkv": "2.12.2", "react-native-quick-crypto": "^0.7.6", @@ -132,8 +137,10 @@ "@react-native/babel-preset": "^0.75.2", "@suite-common/test-utils": "workspace:^", "@trezor/connect-mobile": "workspace:^", + "@types/fast-text-encoding": "^1", "@types/jest": "^29.5.12", "@types/node": "22.10.1", + "@types/react-native-get-random-values": "^1", "babel-plugin-transform-inline-environment-variables": "^0.4.4", "babel-plugin-transform-remove-console": "^6.9.4", "detox": "^20.25.6", diff --git a/suite-native/app/src/initActions.ts b/suite-native/app/src/initActions.ts index 8fefd6c7920..fc016b9d784 100644 --- a/suite-native/app/src/initActions.ts +++ b/suite-native/app/src/initActions.ts @@ -9,7 +9,9 @@ import { initStakeDataThunk, periodicFetchFiatRatesThunk, } from '@suite-common/wallet-core'; +import { walletConnectInitThunk } from '@suite-common/walletconnect'; import { initAnalyticsThunk } from '@suite-native/analytics'; +import { FeatureFlag, selectIsFeatureFlagEnabled } from '@suite-native/feature-flags'; import { selectFiatCurrencyCode } from '@suite-native/settings'; import { setIsAppReady, setIsConnectInitialized } from '@suite-native/state/src/appSlice'; @@ -49,6 +51,10 @@ export const applicationInit = createThunk( // Create Portfolio Tracker device if it doesn't exist dispatch(createImportedDeviceThunk()); + + if (selectIsFeatureFlagEnabled(getState(), FeatureFlag.IsWalletConnectEnabled)) { + dispatch(walletConnectInitThunk()); + } } catch (error) { console.error(error); } finally { diff --git a/suite-native/app/src/navigation/RootStackNavigator.tsx b/suite-native/app/src/navigation/RootStackNavigator.tsx index 21e90b75323..84a7fc5295d 100644 --- a/suite-native/app/src/navigation/RootStackNavigator.tsx +++ b/suite-native/app/src/navigation/RootStackNavigator.tsx @@ -10,7 +10,11 @@ import { } from '@suite-native/module-accounts-management'; import { AddCoinAccountStackNavigator } from '@suite-native/module-add-accounts'; import { AuthorizeDeviceStackNavigator } from '@suite-native/module-authorize-device'; -import { ConnectPopupScreen } from '@suite-native/module-connect-popup'; +import { + ConnectPopupScreen, + WalletConnectPairScreen, + WalletConnectSessionPopupScreen, +} from '@suite-native/module-connect-popup'; import { DevUtilsStackNavigator } from '@suite-native/module-dev-utils'; import { DeviceSettingsStackNavigator } from '@suite-native/module-device-settings'; import { OnboardingStackNavigator } from '@suite-native/module-onboarding'; @@ -76,6 +80,14 @@ export const RootStackNavigator = () => { /> + + { isTradingEnabled: true, isDeviceOnboardingEnabled: true, IsFwRevisionCheckEnabled: true, + isWalletConnectEnabled: true, }); }); @@ -56,6 +57,7 @@ describe('featureFlagsSlice', () => { isTradingEnabled: false, isDeviceOnboardingEnabled: false, IsFwRevisionCheckEnabled: false, + isWalletConnectEnabled: false, }); }); @@ -83,6 +85,7 @@ describe('featureFlagsSlice', () => { isTradingEnabled: false, isDeviceOnboardingEnabled: false, IsFwRevisionCheckEnabled: false, + isWalletConnectEnabled: false, }); }); }); diff --git a/suite-native/feature-flags/src/featureFlagsSlice.ts b/suite-native/feature-flags/src/featureFlagsSlice.ts index b9da94ffe29..b54f152cfdb 100644 --- a/suite-native/feature-flags/src/featureFlagsSlice.ts +++ b/suite-native/feature-flags/src/featureFlagsSlice.ts @@ -12,6 +12,7 @@ export const FeatureFlag = { IsDeviceOnboardingEnabled: 'isDeviceOnboardingEnabled', IsTradingEnabled: 'isTradingEnabled', IsFwRevisionCheckEnabled: 'IsFwRevisionCheckEnabled', + IsWalletConnectEnabled: 'isWalletConnectEnabled', } as const; export type FeatureFlag = (typeof FeatureFlag)[keyof typeof FeatureFlag]; @@ -31,6 +32,7 @@ export const featureFlagsInitialState: FeatureFlagsState = { [FeatureFlag.IsDeviceOnboardingEnabled]: isDebugEnv() && !isDetoxTestBuild(), [FeatureFlag.IsTradingEnabled]: isDebugEnv(), [FeatureFlag.IsFwRevisionCheckEnabled]: isDevelopOrDebugEnv(), + [FeatureFlag.IsWalletConnectEnabled]: isDevelopOrDebugEnv(), }; export const featureFlagsPersistedKeys: Array = [ @@ -42,6 +44,7 @@ export const featureFlagsPersistedKeys: Array = [ FeatureFlag.IsDeviceOnboardingEnabled, FeatureFlag.IsTradingEnabled, FeatureFlag.IsFwRevisionCheckEnabled, + FeatureFlag.IsWalletConnectEnabled, ]; export const featureFlagsSlice = createSlice({ diff --git a/suite-native/intl/src/en.ts b/suite-native/intl/src/en.ts index af955b561eb..a61b98dee47 100644 --- a/suite-native/intl/src/en.ts +++ b/suite-native/intl/src/en.ts @@ -288,6 +288,7 @@ export const en = { title: 'Trezor Connect Mobile', callback: 'Callback', confirm: 'Confirm', + cancel: 'Cancel', areYouSureMessage: 'Are you sure you want to continue?\nMake sure you trust the source.', connectionStatus: { loading: 'Loading...', @@ -303,6 +304,29 @@ export const en = { bottomSheets: { confirmOnDeviceMessage: 'Go to your device and verify the details of the operation.', }, + walletConnect: { + title: 'WalletConnect', + message: + 'An external app is trying to connect to your Trezor Suite. Make sure you trust the source!', + connect: 'Connect', + pairingUrl: 'Enter pairing URL', + scanQR: 'Scan QR code', + activeConnections: 'Active connections', + noActiveConnections: 'No active connections', + disconnect: 'Disconnect', + serviceStatus: { + verified: 'Verified', + unknown: 'Unknown', + dangerous: 'Dangerous', + }, + errors: { + requestExpired: + 'Request has expired. Please go back to the application and try again.', + isScam: 'The request was detected as a scam and was blocked automatically.', + unableToVerify: + 'We were unable to verify the request authenticity. Please make sure you trust the source.', + }, + }, }, moduleDevice: { incompatibleFirmwareModalAppendix: { @@ -605,6 +629,10 @@ export const en = { title: 'Device checks', subtitle: 'Authenticity and security checks', }, + walletConnect: { + title: 'WalletConnect', + subtitle: 'Use external apps using the WalletConnect protocol', + }, }, support: { title: 'Support', diff --git a/suite-native/module-connect-popup/package.json b/suite-native/module-connect-popup/package.json index 60b5d225703..eb94cb1abc2 100644 --- a/suite-native/module-connect-popup/package.json +++ b/suite-native/module-connect-popup/package.json @@ -14,6 +14,7 @@ "@reduxjs/toolkit": "1.9.5", "@suite-common/suite-types": "workspace:*", "@suite-common/wallet-core": "workspace:*", + "@suite-common/walletconnect": "workspace:*", "@suite-native/atoms": "workspace:*", "@suite-native/config": "workspace:*", "@suite-native/device": "workspace:*", diff --git a/suite-native/module-connect-popup/src/hooks/useConnectPopupNavigation.ts b/suite-native/module-connect-popup/src/hooks/useConnectPopupNavigation.ts index b4d03a3a4f9..962762f295a 100644 --- a/suite-native/module-connect-popup/src/hooks/useConnectPopupNavigation.ts +++ b/suite-native/module-connect-popup/src/hooks/useConnectPopupNavigation.ts @@ -5,6 +5,7 @@ import { useNavigation } from '@react-navigation/native'; import * as Linking from 'expo-linking'; import { connectPopupDeeplinkThunk, selectConnectPopupCall } from '@suite-common/connect-popup'; +import { selectPendingProposal, walletConnectPairThunk } from '@suite-common/walletconnect'; import { isDevelopOrDebugEnv } from '@suite-native/config'; import { FeatureFlag, useFeatureFlag } from '@suite-native/feature-flags'; import { @@ -30,26 +31,38 @@ const isConnectPopupUrl = (url: string): boolean => { return false; }; +const isWalletConnectUrl = (url: string): boolean => + url.startsWith('trezorsuitelite://walletconnect'); + // TODO: will be necessary to handle if device is not connected/unlocked so we probably want to wait until user unlock device // we already have some modals like biometrics or coin enabled which are waiting for device to be connected export const useConnectPopupNavigation = () => { const featureFlagEnabled = useFeatureFlag(FeatureFlag.IsConnectPopupEnabled); + const featureFlagWalletConnectEnabled = useFeatureFlag(FeatureFlag.IsWalletConnectEnabled); const navigation = useNavigation(); const dispatch = useDispatch(); const connectPopupCall = useSelector(selectConnectPopupCall); + const walletConnectProposal = useSelector(selectPendingProposal); // Handle deeplink const url = Linking.useURL(); useEffect(() => { - if (!featureFlagEnabled) return; - if (!url || !isConnectPopupUrl(url)) return; - dispatch(connectPopupDeeplinkThunk({ url })); - }, [url, featureFlagEnabled, dispatch]); + if (!featureFlagEnabled || !url) return; + + if (isConnectPopupUrl(url)) { + dispatch(connectPopupDeeplinkThunk({ url })); + } else if (featureFlagWalletConnectEnabled && isWalletConnectUrl(url)) { + dispatch(walletConnectPairThunk({ uri: url })); + } + }, [url, featureFlagEnabled, featureFlagWalletConnectEnabled, dispatch]); useEffect(() => { if (connectPopupCall) { navigation.navigate(RootStackRoutes.ConnectPopup); } - }, [connectPopupCall, navigation]); + if (walletConnectProposal && !walletConnectProposal.expired) { + navigation.navigate(RootStackRoutes.WalletConnectSessionPopup); + } + }, [connectPopupCall, walletConnectProposal, navigation]); }; diff --git a/suite-native/module-connect-popup/src/index.ts b/suite-native/module-connect-popup/src/index.ts index ce81e7177e3..c0ee146b07f 100644 --- a/suite-native/module-connect-popup/src/index.ts +++ b/suite-native/module-connect-popup/src/index.ts @@ -1,3 +1,5 @@ export * from './screens/ConnectPopupScreen'; +export * from './screens/WalletConnectSessionPopupScreen'; +export * from './screens/WalletConnectPairScreen'; export * from './hooks/useConnectPopupNavigation'; export * from './hooks/useIsConnectPopupOpened'; diff --git a/suite-native/module-connect-popup/src/screens/WalletConnectPairScreen.tsx b/suite-native/module-connect-popup/src/screens/WalletConnectPairScreen.tsx new file mode 100644 index 00000000000..9f3fc7d64d7 --- /dev/null +++ b/suite-native/module-connect-popup/src/screens/WalletConnectPairScreen.tsx @@ -0,0 +1,107 @@ +import { useState } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; + +import { + selectSessions, + walletConnectDisconnectThunk, + walletConnectPairThunk, +} from '@suite-common/walletconnect'; +import { Button, Divider, HStack, IconButton, Input, Text, VStack } from '@suite-native/atoms'; +import { Translation } from '@suite-native/intl'; +import { Screen, ScreenHeader } from '@suite-native/navigation'; +import { ScanQRBottomSheet } from '@suite-native/qr-code'; + +export const WalletConnectPairScreen = () => { + const dispatch = useDispatch(); + const sessions = useSelector(selectSessions); + + const [uri, setUri] = useState(''); + const [qrVisible, setQrVisible] = useState(false); + + const handlePair = () => { + dispatch(walletConnectPairThunk({ uri })); + setUri(''); + }; + const handleQr = () => { + setQrVisible(true); + }; + + return ( + + + + } + /> + } + > + + + + } + /> + + + + + + + + : + + {sessions.map(session => ( + + + {session.peer.metadata.name} + {session.peer.metadata.url} + + {session.topic} + + + + + + + ))} + {sessions.length === 0 && ( + + + + )} + + + + } + isVisible={qrVisible} + onCodeScanned={setUri} + onClose={() => setQrVisible(false)} + /> + + ); +}; diff --git a/suite-native/module-connect-popup/src/screens/WalletConnectSessionPopupScreen.tsx b/suite-native/module-connect-popup/src/screens/WalletConnectSessionPopupScreen.tsx new file mode 100644 index 00000000000..ec910d2e58f --- /dev/null +++ b/suite-native/module-connect-popup/src/screens/WalletConnectSessionPopupScreen.tsx @@ -0,0 +1,137 @@ +import { useDispatch, useSelector } from 'react-redux'; + +import { useNavigation } from '@react-navigation/native'; + +import { + selectPendingProposal, + sessionProposalApproveThunk, + sessionProposalRejectThunk, +} from '@suite-common/walletconnect'; +import { + AlertBox, + Badge, + Button, + HStack, + Image, + Text, + TitleHeader, + VStack, +} from '@suite-native/atoms'; +import { Translation } from '@suite-native/intl'; +import { Screen, ScreenHeader } from '@suite-native/navigation'; + +export const WalletConnectSessionPopupScreen = () => { + const navigation = useNavigation(); + + const dispatch = useDispatch(); + const pendingProposal = useSelector(selectPendingProposal); + + const handleAccept = () => { + if (pendingProposal?.eventId) + dispatch(sessionProposalApproveThunk({ eventId: pendingProposal?.eventId })); + navigation.goBack(); + }; + const handleReject = () => { + if (pendingProposal?.eventId) + dispatch(sessionProposalRejectThunk({ eventId: pendingProposal?.eventId })); + navigation.goBack(); + }; + + return ( + + + + } + /> + } + > + + + + {!pendingProposal?.isScam && pendingProposal?.validation === 'VALID' && ( + + } + /> + )} + {!pendingProposal?.isScam && pendingProposal?.validation === 'UNKNOWN' && ( + + } + /> + )} + {(pendingProposal?.isScam || pendingProposal?.validation === 'INVALID') && ( + + } + /> + )} + + + + + + {pendingProposal?.isScam && ( + } + /> + )} + {pendingProposal?.validation === 'INVALID' && ( + + } + /> + )} + + {pendingProposal?.expired && ( + + } + /> + )} + + + + + + + + ); +}; diff --git a/suite-native/module-connect-popup/tsconfig.json b/suite-native/module-connect-popup/tsconfig.json index c3c0c910538..a0e1b1e0890 100644 --- a/suite-native/module-connect-popup/tsconfig.json +++ b/suite-native/module-connect-popup/tsconfig.json @@ -8,6 +8,9 @@ { "path": "../../suite-common/wallet-core" }, + { + "path": "../../suite-common/walletconnect" + }, { "path": "../atoms" }, { "path": "../config" }, { "path": "../device" }, diff --git a/suite-native/module-dev-utils/src/components/FeatureFlags.tsx b/suite-native/module-dev-utils/src/components/FeatureFlags.tsx index 911f4fa82d5..78d75aaf9f0 100644 --- a/suite-native/module-dev-utils/src/components/FeatureFlags.tsx +++ b/suite-native/module-dev-utils/src/components/FeatureFlags.tsx @@ -14,6 +14,7 @@ const featureFlagsTitleMap = { [FeatureFlagEnum.IsDeviceOnboardingEnabled]: 'Device onboarding', [FeatureFlagEnum.IsTradingEnabled]: 'Trading', [FeatureFlagEnum.IsFwRevisionCheckEnabled]: 'Firmware Revision Check', + [FeatureFlagEnum.IsWalletConnectEnabled]: 'WalletConnect', } as const satisfies Record; const FeatureFlag = ({ featureFlag }: { featureFlag: FeatureFlagEnum }) => { diff --git a/suite-native/module-settings/src/components/FeaturesSettings.tsx b/suite-native/module-settings/src/components/FeaturesSettings.tsx index bde29cfdb96..ad8a8676e16 100644 --- a/suite-native/module-settings/src/components/FeaturesSettings.tsx +++ b/suite-native/module-settings/src/components/FeaturesSettings.tsx @@ -22,6 +22,7 @@ export const FeaturesSettings = () => { const isDevButtonVisible = useAtomValue(isDevButtonVisibleAtom); const isUsbDeviceConnectFeatureEnabled = useFeatureFlag(FeatureFlag.IsDeviceConnectEnabled); const isFwRevisionCheckEnabled = useFeatureFlag(FeatureFlag.IsFwRevisionCheckEnabled); + const isWalletConnectEnabled = useFeatureFlag(FeatureFlag.IsWalletConnectEnabled); const navigation = useNavigation>(); const navigateTo = useSettingsNavigateTo(); @@ -85,6 +86,17 @@ export const FeaturesSettings = () => { )} )} + {isWalletConnectEnabled && ( + } + subtitle={ + + } + onPress={() => navigation.navigate(RootStackRoutes.WalletConnectPair)} + testID="@settings/wallet-connect" + /> + )} ); }; diff --git a/suite-native/navigation/src/navigators.ts b/suite-native/navigation/src/navigators.ts index 558afeb8296..5852029586e 100644 --- a/suite-native/navigation/src/navigators.ts +++ b/suite-native/navigation/src/navigators.ts @@ -212,6 +212,8 @@ export type RootStackParamList = { [RootStackRoutes.SendStack]: NavigatorScreenParams; [RootStackRoutes.CoinEnablingInit]: undefined; [RootStackRoutes.ConnectPopup]: undefined; + [RootStackRoutes.WalletConnectSessionPopup]: undefined; + [RootStackRoutes.WalletConnectPair]: undefined; [RootStackRoutes.SettingsScreenStack]: NavigatorScreenParams; }; diff --git a/suite-native/navigation/src/routes.ts b/suite-native/navigation/src/routes.ts index 298fa5b139c..84c86d781da 100644 --- a/suite-native/navigation/src/routes.ts +++ b/suite-native/navigation/src/routes.ts @@ -15,6 +15,8 @@ export enum RootStackRoutes { AddCoinAccountStack = 'AddCoinAccountStack', CoinEnablingInit = 'CoinEnablingInit', ConnectPopup = 'ConnectPopup', + WalletConnectSessionPopup = 'WalletConnectSessionPopup', + WalletConnectPair = 'WalletConnectPair', SettingsScreenStack = 'SettingsScreenStack', } diff --git a/suite-native/state/package.json b/suite-native/state/package.json index d8c1d1360d2..3fc4c626de7 100644 --- a/suite-native/state/package.json +++ b/suite-native/state/package.json @@ -21,6 +21,7 @@ "@suite-common/toast-notifications": "workspace:*", "@suite-common/token-definitions": "workspace:*", "@suite-common/wallet-core": "workspace:*", + "@suite-common/walletconnect": "workspace:*", "@suite-native/blockchain": "workspace:*", "@suite-native/device": "workspace:*", "@suite-native/device-authorization": "workspace:*", diff --git a/suite-native/state/src/reducers.ts b/suite-native/state/src/reducers.ts index 68f1d9db7b0..caf32ce8007 100644 --- a/suite-native/state/src/reducers.ts +++ b/suite-native/state/src/reducers.ts @@ -20,6 +20,9 @@ import { prepareStakeReducer, prepareTransactionsReducer, } from '@suite-common/wallet-core'; +// Suite Native has circular in @suite-native/test-utils -> @suite-native/state -> ... -> @suite-native/test-utils +// This is causing problems handling types in WalletConnect, so we import the reducer directly instead of the whole module +import { prepareWalletConnectReducer } from '@suite-common/walletconnect/src/walletConnectReducer'; import { deviceAuthorizationReducer } from '@suite-native/device-authorization'; import { DiscoveryConfigState, @@ -63,6 +66,7 @@ const sendFormReducer = sendFormSlice.prepareReducer(extraDependencies); const stakeReducer = prepareStakeReducer(extraDependencies); const firmwareReducer = prepareFirmwareReducer(extraDependencies); const connectPopupReducer = prepareConnectPopupReducer(extraDependencies); +const walletConnectReducer = prepareWalletConnectReducer(extraDependencies); export const prepareRootReducers = async () => { const appSettingsPersistedReducer = await preparePersistReducer({ @@ -85,6 +89,7 @@ export const prepareRootReducers = async () => { fees: feesReducer, stake: stakeReducer, connectPopup: connectPopupReducer, + walletConnect: walletConnectReducer, }); const walletPersistedReducer = await preparePersistReducer({ diff --git a/suite-native/state/tsconfig.json b/suite-native/state/tsconfig.json index 6554093272b..b12495f364c 100644 --- a/suite-native/state/tsconfig.json +++ b/suite-native/state/tsconfig.json @@ -25,6 +25,9 @@ { "path": "../../suite-common/wallet-core" }, + { + "path": "../../suite-common/walletconnect" + }, { "path": "../blockchain" }, { "path": "../device" }, { "path": "../device-authorization" }, diff --git a/yarn.lock b/yarn.lock index 92cd0077479..7fdd401055b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6885,6 +6885,17 @@ __metadata: languageName: node linkType: hard +"@react-native-async-storage/async-storage@npm:^2.1.1": + version: 2.1.1 + resolution: "@react-native-async-storage/async-storage@npm:2.1.1" + dependencies: + merge-options: "npm:^3.0.4" + peerDependencies: + react-native: ^0.0.0-0 || >=0.65 <1.0 + checksum: 10/ae65d10606e2ba307dc7a4362612c3568fdae3833dae407810c2f457ab1a6ec2c50f2979c8afbf6477b56c8033b8f332038c54e617165618d1b5305e91784300 + languageName: node + linkType: hard + "@react-native-community/cli-clean@npm:15.1.2": version: 15.1.2 resolution: "@react-native-community/cli-clean@npm:15.1.2" @@ -10537,6 +10548,7 @@ __metadata: "@gorhom/bottom-sheet": "npm:5.0.5" "@jest/globals": "npm:^29.7.0" "@mobily/ts-belt": "npm:^3.13.1" + "@react-native-async-storage/async-storage": "npm:^2.1.1" "@react-native-community/cli": "npm:^15.1.2" "@react-native-community/netinfo": "npm:^11.4.1" "@react-native/babel-preset": "npm:^0.75.2" @@ -10559,6 +10571,7 @@ __metadata: "@suite-common/token-definitions": "workspace:*" "@suite-common/wallet-core": "workspace:*" "@suite-common/wallet-types": "workspace:*" + "@suite-common/walletconnect": "workspace:*" "@suite-native/accounts": "workspace:*" "@suite-native/alerts": "workspace:*" "@suite-native/analytics": "workspace:*" @@ -10601,8 +10614,11 @@ __metadata: "@trezor/styles": "workspace:*" "@trezor/theme": "workspace:*" "@trezor/trezor-user-env-link": "workspace:*" + "@types/fast-text-encoding": "npm:^1" "@types/jest": "npm:^29.5.12" "@types/node": "npm:22.10.1" + "@types/react-native-get-random-values": "npm:^1" + "@walletconnect/react-native-compat": "npm:^2.18.0" "@whatwg-node/events": "npm:0.1.2" abortcontroller-polyfill: "npm:1.7.6" babel-plugin-transform-inline-environment-variables: "npm:^0.4.4" @@ -10628,6 +10644,7 @@ __metadata: expo-system-ui: "npm:^4.0.2" expo-updates: "npm:0.26.6" expo-video: "npm:^2.0.1" + fast-text-encoding: "npm:^1.0.6" jest: "npm:^29.7.0" jest-junit: "npm:^16.0.0" lottie-react-native: "npm:^7.1.0" @@ -10638,6 +10655,7 @@ __metadata: react-native: "npm:0.76.1" react-native-edge-to-edge: "npm:^1.3.1" react-native-gesture-handler: "npm:^2.21.0" + react-native-get-random-values: "npm:^1.11.0" react-native-keyboard-aware-scroll-view: "npm:0.9.5" react-native-mmkv: "npm:2.12.2" react-native-quick-crypto: "npm:^0.7.6" @@ -11266,6 +11284,7 @@ __metadata: "@reduxjs/toolkit": "npm:1.9.5" "@suite-common/suite-types": "workspace:*" "@suite-common/wallet-core": "workspace:*" + "@suite-common/walletconnect": "workspace:*" "@suite-native/atoms": "workspace:*" "@suite-native/config": "workspace:*" "@suite-native/device": "workspace:*" @@ -11705,6 +11724,7 @@ __metadata: "@suite-common/toast-notifications": "workspace:*" "@suite-common/token-definitions": "workspace:*" "@suite-common/wallet-core": "workspace:*" + "@suite-common/walletconnect": "workspace:*" "@suite-native/blockchain": "workspace:*" "@suite-native/device": "workspace:*" "@suite-native/device-authorization": "workspace:*" @@ -14076,6 +14096,13 @@ __metadata: languageName: node linkType: hard +"@types/fast-text-encoding@npm:^1": + version: 1.0.3 + resolution: "@types/fast-text-encoding@npm:1.0.3" + checksum: 10/34ec2bbaf3e3ee36b7b74375293becc735378f77e9cd93b810ad988b42991ee80d30fb942e6ba03adfc1f0cb0e2024a0aeee84475847563ed6782e21c4c0f5f0 + languageName: node + linkType: hard + "@types/file-saver@npm:^2.0.6": version: 2.0.7 resolution: "@types/file-saver@npm:2.0.7" @@ -14764,6 +14791,13 @@ __metadata: languageName: node linkType: hard +"@types/react-native-get-random-values@npm:^1": + version: 1.8.2 + resolution: "@types/react-native-get-random-values@npm:1.8.2" + checksum: 10/08f3f82efbb5b6d9acd8f7f55a2dac9f228886323ac3018a1bab46cd1b45f24809d194fd2a3fe02a9ec4196606325e5cfffde0b0057ae785208b658fdc83c821 + languageName: node + linkType: hard + "@types/react-qr-reader@npm:^2.1.7": version: 2.1.7 resolution: "@types/react-qr-reader@npm:2.1.7" @@ -15629,6 +15663,26 @@ __metadata: languageName: node linkType: hard +"@walletconnect/react-native-compat@npm:^2.18.0": + version: 2.18.0 + resolution: "@walletconnect/react-native-compat@npm:2.18.0" + dependencies: + events: "npm:3.3.0" + fast-text-encoding: "npm:1.0.6" + react-native-url-polyfill: "npm:2.0.0" + peerDependencies: + "@react-native-async-storage/async-storage": "*" + "@react-native-community/netinfo": "*" + expo-application: "*" + react-native: "*" + react-native-get-random-values: "*" + peerDependenciesMeta: + expo-application: + optional: true + checksum: 10/ef82bffb1f85f588b2f813ae30dbaf7ed87f37138548e5b3820e68df42f8a2c446d9c8a8a1f6c0fbd6d7a0c8ae89009aa02d75e208c7e58442433d2d93b97f2f + languageName: node + linkType: hard + "@walletconnect/relay-api@npm:1.0.11": version: 1.0.11 resolution: "@walletconnect/relay-api@npm:1.0.11" @@ -24536,6 +24590,13 @@ __metadata: languageName: node linkType: hard +"fast-base64-decode@npm:^1.0.0": + version: 1.0.0 + resolution: "fast-base64-decode@npm:1.0.0" + checksum: 10/4c59eb1775a7f132333f296c5082476fdcc8f58d023c42ed6d378d2e2da4c328c7a71562f271181a725dd17cdaa8f2805346cc330cdbad3b8e4b9751508bd0a3 + languageName: node + linkType: hard + "fast-copy@npm:^3.0.2": version: 3.0.2 resolution: "fast-copy@npm:3.0.2" @@ -24626,6 +24687,13 @@ __metadata: languageName: node linkType: hard +"fast-text-encoding@npm:1.0.6, fast-text-encoding@npm:^1.0.6": + version: 1.0.6 + resolution: "fast-text-encoding@npm:1.0.6" + checksum: 10/f7b9e2e7a21e4ae5f4b8d3729850be83fb45052b28c9c38c09b8366463a291d6dc5448359238bdaf87f6a9e907d5895a94319a2c5e0e9f0786859ad6312d1d06 + languageName: node + linkType: hard + "fast-uri@npm:^3.0.1": version: 3.0.1 resolution: "fast-uri@npm:3.0.1" @@ -31762,6 +31830,15 @@ __metadata: languageName: node linkType: hard +"merge-options@npm:^3.0.4": + version: 3.0.4 + resolution: "merge-options@npm:3.0.4" + dependencies: + is-plain-obj: "npm:^2.1.0" + checksum: 10/d86ddb3dd6e85d558dbf25dc944f3527b6bacb944db3fdda6e84a3f59c4e4b85231095f58b835758b9a57708342dee0f8de0dffa352974a48221487fe9f4584f + languageName: node + linkType: hard + "merge-source-map@npm:1.0.4": version: 1.0.4 resolution: "merge-source-map@npm:1.0.4" @@ -37350,6 +37427,17 @@ __metadata: languageName: node linkType: hard +"react-native-get-random-values@npm:^1.11.0": + version: 1.11.0 + resolution: "react-native-get-random-values@npm:1.11.0" + dependencies: + fast-base64-decode: "npm:^1.0.0" + peerDependencies: + react-native: ">=0.56" + checksum: 10/eb04833ce2b66309d737f1447ab01ad32aca00a8d1cc4de7b4e751c23f4d9f8059a2643bb16e0b6f3e6b074a9e57e769bb2bf2afc50a912c5661d80a6ce4de34 + languageName: node + linkType: hard + "react-native-iphone-x-helper@npm:^1.0.3": version: 1.3.1 resolution: "react-native-iphone-x-helper@npm:1.3.1" @@ -37479,6 +37567,17 @@ __metadata: languageName: node linkType: hard +"react-native-url-polyfill@npm:2.0.0": + version: 2.0.0 + resolution: "react-native-url-polyfill@npm:2.0.0" + dependencies: + whatwg-url-without-unicode: "npm:8.0.0-3" + peerDependencies: + react-native: "*" + checksum: 10/6a8d605eeb1b0ee9b0f47f1866acc2edfa2131a4a8fb1ea3839ceb507e225b894ed66f49a3bd826fc964f2c8005b3678c9d3b65d07eb0a3b979be830cb618686 + languageName: node + linkType: hard + "react-native@npm:0.76.1": version: 0.76.1 resolution: "react-native@npm:0.76.1"