* tests(mobile): add e2e coverage for WalletConnectGate flows
Adds Maestro tests for the two non-signing gate states on the
review-and-execute screen:
- wc-gate-reconnect.yml: expired session renders "Reconnect wallet to
continue"; tapping restores the session and reveals Execute transaction.
- wc-gate-switch-network.yml: wrong-network state renders "Switch network
to continue"; tapping clears the flag and reveals Execute transaction.
Wires up the e2e control surface:
- WalletConnectContext.e2e.tsx: mock reconnect() and switchNetworkIfNeeded()
now flip walletConnectE2eState so the gate transitions correctly.
- TestCtrls: e2eWcGateReconnect and e2eWcGateWrongNetwork buttons.
- connectSignerSetup: setupWcGateReconnect / setupWcGateWrongNetwork seed
a pending-tx safe with a WC signer in the desired gate state.
Pin isows@1.0.7 in package.json resolutions.
Part of WA-1858.
* tests(mobile): extract shared review-and-execute nav for wc-gate tests
Both wc-gate YAML tests duplicated ~30 lines navigating from app start to
the Review-and-Execute screen of the first pending tx. Move that navigation
into apps/mobile/e2e/utils/setup/open-review-and-execute.yml, parameterised
by SETUP_BUTTON_ID, and have both gate tests `runFlow` it. The seeding
button id is now the only piece of per-test configuration.
* tests(mobile): assert wc-gate dismissal by id, not by neighbouring text
The gate-dismissed assertion used a regex matching either "Execute
transaction" or "Insufficient funds". Those are distinct semantic states
(funded vs unfunded signer); coupling them in one assertion lets a
funds-error regression silently pass the gate test.
Replace the text regex with `extendedWaitUntil: notVisible` on the gate
button id. That waits for re-render and asserts the gate is gone in one
step, decoupling the test from the underlying execute-button copy.
* tests(mobile): drop unread fields from WC e2e state overrides
WalletConnectGate and useWalletConnectStatus only read `address`,
`isWrongNetwork`, and `isWalletConnectSigner`. The setup helpers and the
`reconnect` mock were also setting `hasProvider` and `walletInfo` —
unobservable from any production code path, so they only added noise.
- setupWcGateReconnect: drop the override entirely; post-reset defaults
already model an expired session.
- setupWcGateWrongNetwork: drop hasProvider and walletInfo.
- WalletConnectContext.e2e.tsx reconnect mock: drop hasProvider.
* tests(mobile): add `wc-gate` tag to connect-signer suite
The two child flows (wc-gate-reconnect.yml, wc-gate-switch-network.yml)
declare a `wc-gate` tag, but the parent __suite__.yml didn't surface it.
Tag-based runs (`maestro test --include-tags wc-gate`) now also pick up
the aggregated suite, matching repo convention.
* tests(mobile): annotate wcSigner literal with explicit Signer type
The literal relied on inference plus `as const` on `type`. With an explicit
Signer annotation, future widening or narrowing of the discriminated union
in signersSlice will surface here at compile time instead of failing
silently in the e2e flow. The `as const` workaround is no longer needed.
* tests(mobile): reuse setupPendingTxSafe from WC gate setup
setupWcGateBase duplicated the pending-tx safe scaffolding already in
setupHelpers.ts (base config, signer registration, active safe/signer).
The only delta was the signer's `type: 'walletconnect'` and the extra
setExecutionMethod dispatch.
Extend setupPendingTxSafe with an optional `options.signer` override.
Existing five private-key callers are unchanged. setupWcGateBase now
constructs the WC Signer literal and delegates everything else to the
shared helper.
* docs(mobile): document `e2e<PascalCase>` exception for TestCtrls triggers
The repo-wide testID convention is kebab-case, but every TestCtrls
scenario-trigger button uses `e2eConnectSignerOwner`-style camelCase.
That divergence was undocumented, so new contributors would either
churn the convention or get pushed to match it without context.
Codify the exception: product testIDs stay kebab-case; the hidden
e2e-build-only TestCtrls triggers use `e2e<PascalCase>`.
* docs: document `isows@1.0.7` resolution and add resolutions log
The root package.json `resolutions` block had 12 entries with zero
recorded rationale, so each new reviewer has to investigate why a pin
exists. Add `docs/resolutions.md` as the canonical home for that
rationale and seed it with the `isows@1.0.7` entry — a benign dedup
(no CVE) added to align the transitive version under viem.
Future contributors are asked to update the log alongside any new
resolutions entry.
* chore(mobile): upgrade Tamagui from v1 to v2
Upgrade all @tamagui/* packages from v1 (^1.126.3) to v2 (2.0.0-rc.26).
Replace deprecated @tamagui/animations-moti with animations-reanimated.
Rewrite SafeButton to use v2 compound component pattern (Button.Text)
with correct font weight, disabled state, and icon coloring.
Patch @tamagui/image for style override bug (upstream fix merged but
not yet on npm: https://github.com/tamagui/tamagui/pull/3966).
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
* fix(mobile): resolve Tamagui tokens in Loader before passing to SVG
The Loader component passes color directly to react-native-progress
(CircleSnail), which uses react-native-svg internally. SVG doesn't
understand Tamagui theme tokens like "$color", causing repeated
"not a valid color or brush" console warnings.
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
* fix(mobile): center nav bar title in scrollable headers
Remove flex: 1 from headerTitle Animated.View so the native stack
header centers the title element itself. Add headerTitleAlign: 'center'
and match right spacer width (40px) to the back button circle.
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
* fix(mobile): fix Tamagui v2 component API breakages
- SafeButton: rewrite with Button.Text compound pattern, add textColor
prop for forced light-mode overrides, restore fontWeight 700 default
- SafeInput: replace removed `editable` prop with `readOnly`, use
GetProps<StyledInput> to fix type conflicts, cast theme tokens
- SafeCard: use `src` instead of `source`, `objectFit` instead of
`resizeMode` for Tamagui v2 Image
- ParametersButton: migrate from raw Button to SafeButton
- Badge: fix dark mode background token (backgroundMain → borderLight)
- Raw Buttons: move fontWeight to Button.Text in ImportSigner/Ledger
- Onboarding: migrate color prop to textColor for dark mode fix
- Assets errors: use secondary variant + textColor instead of inline bg
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
* fix(mobile): preserve element children and text-button accent color in SafeButton
- Only wrap string/number children in Button.Text; render element
children (ActivityIndicator, Loader) directly to avoid invalid
text-child nesting on native.
- Use theme.primary for the text variant so text-style buttons
retain their accent color instead of blending with body text.
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
* fix(mobile): replace raw Tamagui Button with SafeButton in ImportSuccess
The Copy button on the signer import success screen was broken after the
Tamagui v2 upgrade because it used a raw Tamagui Button. Replace it with
SafeButton (secondary, $sm) for consistent styling and v2 compatibility.
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
* fix(mobile): fix Jest transform config for Tamagui v2 and update snapshots
Add tamagui and @tamagui/* to transformIgnorePatterns so Jest can parse
the ESM exports in Tamagui v2. Update 22 snapshots reflecting the new
style output and remove stale fontFamily assertion in DataRow test.
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
---------
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
* fix(mobile): upgrade react-native-quick-crypto for Android 16KB page size support
Upgrade react-native-quick-crypto from 0.7.x to 1.0.17 to support
Android 16KB page size requirement. Add react-native-nitro-modules and
react-native-quick-base64 as new peer dependencies. Update
react-native-device-crypto patch to remove deprecated jcenter()
repository references for Gradle 9.0 compatibility.
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
* chore(mobile): remove unused config/ethers.ts
Dead code — crypto-shims.ts in platform/ is the active version
imported by the root layout.
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
* fix(mobile): deduplicate react-native-quick-base64 via resolution
Add root resolution to force a single copy of react-native-quick-base64
(2.2.2), avoiding version skew between the direct dependency and the
transitive one from @craftzdog/react-native-buffer.
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
* fix(mobile): upgrade react-native-mmkv to v4 and pin MMKV pod
- Upgrade react-native-mmkv from 3.x to 4.2.0 (Nitro-based rewrite)
- Migrate API: new MMKV() -> createMMKV(), .delete() -> .remove()
- Pin MMKV pod to ~> 2.3.0 in notification extension plugin instead
of master branch, fixing sharedApplication build error in App
Extensions
- Update expo plugin config.ts (source of truth for Podfile template)
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
* docs: add solution doc for Expo native file editing workflow
Document that generated native files (ios/Podfile etc.) must be
modified through Expo config plugins, not directly. Also unignore
docs/solutions/ from .gitignore.
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
* fix(mobile): add jest mocks for react-native-nitro-modules and mmkv v4
MMKV v4 uses NitroModules under the hood, which requires mocking in
the test environment. Add mocks for both react-native-nitro-modules
and the new react-native-mmkv createMMKV API.
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
---------
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
* refactor(swap): migrate to v3 feature architecture
- Create contract.ts defining public API surface with typed exports
- Create feature.ts with flat structure for lazy-loaded components
- Create index.ts with feature handle and direct hook exports
- Move SwapWidget from index.tsx to components/SwapWidget/
- Extract getSwapTitle to helpers/utils.ts
- Add FallbackSwapWidget to contract and feature
Update all consumers (~20 files) to use the v3 pattern:
- Components accessed via useLoadFeature(SwapFeature)
- Hooks imported directly from @/features/swap
- Utilities/constants imported directly from @/features/swap
All consumers now use proper public API imports instead of
internal paths like @/features/swap/components/* or
@/features/swap/hooks/*
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
* fix(swap): convert internal imports to relative paths
Convert absolute @/features/swap/* imports to relative paths within
the swap feature to satisfy ESLint import restrictions.
Internal components and hooks now use relative imports:
- components/SwapOrder/index.tsx: ../OrderId, ../StatusLabel, etc.
- components/SwapOrderConfirmationView/*: ../OrderId, ../SwapTokens, etc.
- hooks/__tests__/*: ../useIsExpiredSwap, ../useIsTWAPFallbackHandler
Also fix external consumers:
- SignMessage: import selectSwapParams from @/features/swap
- store/slices.ts: import from @/features/swap barrel
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
* docs(web): eslint gotcha on feature refactoriing
* refactor(web): move swapTx to transactions
* fix(web): don’t directly import feature files
* refactor(web): use swap title directly
* fix(web): import swap
* refactor(web): remove unused hook
* fix(web): export store from store folder
* fix(web): duplicate import
* fix: import swap errors
* fix(web): add pr feedback
---------
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
* Update docs (#53)
* docs: move contributing to code-style
The contributing doc is actually a code-style doc. Once we move
everything to monorepo we will adopt the safe-wallet-web
CONTRIBUTING.md file.
* docs: add release procedure docs
(cherry picked from commit 01345f008492e9a5d33fc5e198966e6be4d5452c)
* Feat: Add create/get private key hook (#59)
* feat: add necessary libraries
* feat: create useSign hook
* feat: cover sign hook with unit tests
* Update apps/mobile/src/hooks/useSign/useSign.ts
Co-authored-by: katspaugh <381895+katspaugh@users.noreply.github.com>
* fix: adjust type
Co-authored-by: katspaugh <381895+katspaugh@users.noreply.github.com>
* feat: add react-native-quick-crypto back
* fix: lint uintGenericArray problem
* fix: adjust export style
* fix: remove duplicated lines from gitignore
* chore: add reference link
* fix: typo on useSign unit tests
* chore: store iv in the keychain
* Update apps/mobile/src/hooks/useSign/useSign.ts
Co-authored-by: Usame Algan <5880855+usame-algan@users.noreply.github.com>
* fix: typo in unit tests
---------
Co-authored-by: katspaugh <381895+katspaugh@users.noreply.github.com>
Co-authored-by: Usame Algan <5880855+usame-algan@users.noreply.github.com>
(cherry picked from commit 45e82f7ee28fd349669e70e5a3e259e88675743f)
* feat: create account management functionality (#60)
* feat: create useSign hook
* feat: add react-native-quick-crypto back
* feat: create chainsDisplay component to show the grouped chains images
* chore: move redux provider to the top of the react three to make the bottomSheet provider able to read values from redux selectors
* feat: create badge variant for using the badge component in the chainsDisplay component according to figma
* feat: add testIDs in the chainsDisplay component
* feat: allow user to provider a footer to the dropdown component
* chore: make the logo size dynamically
* feat: create AccountCard component
* feat: create AccountItem component to handle the dropdown events and specific layout
* feat: replace the image component by the chainsDisplay component in the Balances component
* feat: change the color of the active chain in the chain selection dropdown
* feat: create a footer for MyAccounts dropdown
* feat: remove unnecessary tests
* feat: add accounts management feature inside the navbar dropdown
* feat: create useInfiniteScroll hook to handle infinite scroll functionality
* feat: use activeChain information into the tokens container
* feat: make the Identicon component to be more extensible
* feat: add mocked constants inside the store folder
* feat: create safes slice to store all safes added into the app
* feat: add possibility to get all supported chains ids and get them also by id
* chore: auto generated types
* chore: remove unused types
* feat: create MyAccounts container
* feat: use isFetching instead isLoading to avoid cached result while query is being revalidated
* chore: memoize the chains manipulation in the chainsDisplay component
* chore: create an useMyAccountsService hook to handle pos-fetch logic outside the container
(cherry picked from commit be1a137b30984b8fcc866fd6767824f5f67ec659)
* chore: update yarn.lock
* chore: link code style file with CONTRIBUTING.md
---------
Co-authored-by: Daniel Dimitrov <daniel@compojoom.com>