Skip to content

Qa#1505

Open
LiorAgnin wants to merge 299 commits into
masterfrom
qa
Open

Qa#1505
LiorAgnin wants to merge 299 commits into
masterfrom
qa

Conversation

@LiorAgnin
Copy link
Copy Markdown
Contributor

@LiorAgnin LiorAgnin commented Feb 15, 2026

Note

High Risk
Updates KYC and card funding/management flows across web and native (including new third-party SDKs and iOS extension targets), which are user-verification and payments-adjacent paths with higher regression risk.

Overview
Adds multi-provider card support (Bridge vs Rain) across the app, including provider-aware formatting, deposit address selection (contracts vs funding_instructions), card status routing, and gating of actions like deposit/withdraw/freeze/PIN management based on provider and customer/KYC state.

Reworks KYC: replaces the existing Persona-based kyc flow with Didit (new kyc.native.tsx for mobile and updated web embedding), and adds a separate bridge-kyc Persona page for Bridge-only KYC; card KYC entry now redirects to the correct provider flow.

Introduces MeaWallet MPP integration and iOS Wallet Extensions (new extension entrypoints + docs), adds registry/config plumbing (.npmrc, meawallet/mea_config ignore, Expo plugins + EAS extension provisioning), and removes Fingerprint.com usage/envs and signup fingerprint collection. Also adds a hidden savings-old route for side-by-side savings calculation comparison and minor home/coin chart UX/data-fetch adjustments (spin-and-win card, CoinGecko native token charting, savings summary backend hook).

Written by Cursor Bugbot for commit 1f5b304. This will update automatically on new commits. Configure here.

@vercel
Copy link
Copy Markdown

vercel Bot commented Feb 15, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
solid-app-staging Ready Ready Preview, Comment May 26, 2026 2:31pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
solid-app Ignored Ignored Preview May 26, 2026 2:31pm

Request Review

Comment thread store/useActivityStore.ts
Comment thread components/Transaction/index.tsx
Comment thread app/(protected)/(tabs)/activity/[clientTxId].tsx
Comment thread hooks/useCardWithdrawals.ts
Comment thread hooks/useGeoCompliance.ts
Comment thread lib/api.ts
Comment thread components/Markdown.tsx Outdated
Comment thread components/Card/WithdrawCardFundsModal.tsx
Comment thread components/CustomTabBar.tsx Outdated

// Visible tabs - these are the main navigation tabs
const VISIBLE_TAB_NAMES = ['index', 'savings', 'card', 'activity'];
const VISIBLE_TAB_NAMES = ['index', 'savings', Platform.OS === 'ios' ? null : 'card', 'activity'];
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Array contains null value on iOS

Low Severity

The VISIBLE_TAB_NAMES array includes null when Platform.OS === 'ios', creating an array like ['index', 'savings', null, 'activity']. While this doesn't cause runtime errors (since route.name won't match null), it's semantically incorrect and adds unnecessary overhead. The array should either be constructed conditionally or filtered with .filter(Boolean) to remove falsy values.

Fix in Cursor Fix in Web

>
<Text className="text-base font-bold text-black">Done</Text>
</Button>
)}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Minimum withdrawal threshold traps user funds

High Severity

The withdraw button now only appears when parseFloat(availableBalance) >= 1, replacing the previous behavior where the button was always visible but disabled when balance was zero or less. Users with balances between $0 and $1 (e.g., $0.50) cannot withdraw their funds because the withdraw button is hidden and replaced with a "Done" button that only closes the modal, effectively trapping their money.

Fix in Cursor Fix in Web

claude and others added 30 commits May 17, 2026 12:15
…2DeY

Make welcome card image cover full upper section of popup
Throttled info-level captureMessage emits the raw vs filtered Arbitrum
token counts, symbols, addresses, fetch status, and whitelist size each
time tokenBalances runs. Goal: identify whether Arbitrum USDC fails to
show on native because the fetch returns empty, the whitelist filter
drops it, or something downstream. Always emits on fetch rejection;
otherwise throttled to 1/min per session.

Sentry only enables in production (lib/_layout.tsx Sentry.init), so this
needs a prod build to surface events.

TODO: revert once diagnosis is complete.
…nfo on native

React Query's default focusManager only listens to `visibilitychange`,
which never fires on React Native. Its onlineManager has no native
transport at all. Consequences with the current useBalances config:

- `refetchOnWindowFocus: true` is a no-op when the app returns from
  background, so reopening the app doesn't refresh balances — users
  wait for the next 5s `refetchInterval` tick, or longer if JS was
  paused while backgrounded.
- `refetchOnReconnect: true` is a no-op after a network drop.

Bridge both managers in the root layout: AppState → focusManager,
NetInfo → onlineManager. NetInfo is already a direct dependency.
Web behavior is unchanged.
…splay-ktdN0

Wire React Query to native app lifecycle and connectivity
…ass backend validation

The activity API's CreateActivityDto enforces /^[A-Z]{2,10}$/ on `symbol`
(after .toUpperCase()), so 'USDC.e' became 'USDC.E' and was rejected with
400. The frontend's createActivityEvent call swallows errors via console.error,
so the borrow-and-deposit-to-card, bridge-to-card, and repay-and-withdraw
flows never landed in Mongo. Card balance webhooks then fell through to the
fallback path that creates synthetic 'card_transaction' rows.

Token identity is still preserved via metadata.tokenAddress (USDC_STARGATE)
and chainId (fuse.id).

https://claude.ai/code/session_01DQgmuLpKSnWQTDRogWXHZM
…vities pass backend validation"

This reverts commit 5ab3183.
The global axios request interceptor in lib/api.ts injects the Solid
backend Bearer JWT on iOS/Android. That header was leaking into Alchemy
JSON-RPC calls (same axios import) which made Alchemy 401 only on mobile
even when the env key is identical to web. Switch lib/alchemy.ts to a
dedicated axios.create() instance so it never picks up the interceptor.
Mobile is back on the alchemy source after the axios-isolation fix in
the previous commit; the Arbitrum diagnostic Sentry.captureMessage was
only needed to attribute empty balances during the investigation.
…splay-ktdN0-qa

fix(balances): isolate Alchemy axios from global JWT interceptor and drop diagnostics
Users only receive a Rain virtual card and do not order a physical card,
so the trailing clause about a physical card being on its way was misleading.
…up-lAial

Update CardWelcomePopup message text
…T instead of CARD_TRANSACTION

The borrow handler and the SAVINGS/bridge fallthrough were both creating
generic CARD_TRANSACTION "Card Deposit" rows. The backend's card-balance
webhook (findPendingCardDepositActivity) only looks for
[BORROW_AND_DEPOSIT_TO_CARD, BRIDGE_DEPOSIT] to flip pending rows to SUCCESS,
so these rows stayed pending forever and were hidden by the 24h stuck-tx
filter in ActivityTransactions.tsx.

Writing the correct type from the form lets the existing webhook lookup
match, so the activity reaches SUCCESS and stays visible.

https://claude.ai/code/session_01DQgmuLpKSnWQTDRogWXHZM
…-display-P5EGg

Update USDC symbol references from USDC.e to USDC
…y persist

updateActivityEvent was sending `txHash` (not a backend DTO field — silently
dropped by mongoose's strict schema) and omitting `url` entirely. The
backend's UpdateActivityDto declares `hash` and `url`; the schema persists
both. So neither field ever made it into the DB, even though local Zustand
held the values.

Symptom: after a hard refresh / cache clear, the activity-detail page lost
its LayerZero explorer-row link, because the backend's GET /activity
returned an activity with no `hash` or `url` and the page no longer had
the local fallback.

Side effect: useCardDepositPoller, which keys off activity.hash, can now
actually pick up pending card-deposit rows as a fallback when the webhook
is delayed (separate but related fix to broaden its activity types).

https://claude.ai/code/session_01DQgmuLpKSnWQTDRogWXHZM
…fields

fix(activity): send hash and url to backend on update so they actuall…
PageLayout was unmounting the entire savings page whenever isBalanceLoading
or isTransactionsLoading flipped true — which now fires on every vault tab
switch since both queries are keyed by the current vault. On Android this
remounts the reanimated vault cards and analytics chart and feels stuck.

Only show the full-page loader on the very first load (tracked via a ref).
Subsequent vault switches keep the page mounted and render skeletons in
the Total Value / Interest Earned slots while the new vault's data loads.
Also surface a loading state on the Vault Breakdown tab so it stops
flashing "No vault breakdown data available" during the switch.
…loader-oX5Fh-qa

fix(savings): keep page mounted on vault switch, show inline skeletons
…ysical card shipping with Rain's actual displayName rule

Rain's only character restriction is on configuration.displayName for
physical cards (alphanumeric, spaces, periods, hyphens), and is ignored
for virtual cards entirely. The Rain KYC form was rejecting valid
applicants with non-Latin names (Cyrillic, Arabic, CJK) for both virtual
and physical cards.

- RainKyc schema: removed Latin-only regex on firstName/lastName.
- OrderPhysicalCardModal: relaxed the shipping name regex to match Rain's
  documented rule (also allow digits and periods) since these names are
  embossed as the physical card's displayName.
…tion-rain-AeJe0

Refactor name validation for Rain KYC and physical card forms
Fetch and display the safe's native ETH balance on Arbitrum alongside
Ethereum, Fuse, and Base. Users who sent ETH to their Arbitrum safe
address can now see and transfer those funds from the Send flow.
Add Arbitrum network support to balance fetching
@didit-protocol/sdk-react-native's Expo plugin injects the Podfile entry
pointing at .../sdk-ios/main/DiditSDK.podspec. On 2026-05-25 main was
bumped to 4.0.0, which no longer satisfies the SdkReactNative.podspec
constraint of `DiditSDK ~> 3.2`, so pod install fails on every iOS EAS
build with a CocoaPods version conflict.

Patch the plugin to use the 3.2.13 tagged podspec — the latest 3.2.x
release that still ships the flat DiditSDK.xcframework + OpenSSL.xcframework
the react-native-quick-crypto patch relies on for OpenSSL.
…ments

#2093 pinned the DiditSDK pod to 3.2.13, which gets pod install past the
version constraint but introduces a new fault: VerificationError gained a
.retryBlocked case starting in 3.2.10, and @didit-protocol/sdk-react-native@3.2.8's
DiditSdkBridge.swift mapErrorType() switch only handles
.sessionExpired / .networkError / .cameraAccessDenied / .unknown. Xcode
errors out with "switch must be exhaustive" during the Fastlane step.

3.2.9 is the latest DiditSDK iOS release before the enum was extended, so
the wrapper's 4-case switch is still exhaustive against it. Verified by
diffing the swiftinterface across 3.2.8 / 3.2.9 / 3.2.10 / 3.2.13 — the
.retryBlocked case lands in 3.2.10. The wrapper's other switches
(VerificationStatus, VerificationResult) are unchanged across 3.2.x.
fix(ios): pin DiditSDK pod to 3.2.13 instead of tracking main
The send form pulled balance from wagmi's useBalance, which has a 5-minute
default staleTime in the app's QueryClient and isn't invalidated by the
safe-account send flow (useSend doesn't go through useTransactionAwait).
After a previous send, the token picker — fed by useWalletTokens (5s
polling + SSE-invalidated) — showed the fresh balance, but selecting a
token brought the user back to a SendForm displaying wagmi's stale cache.

Drop wagmi's useBalance and source the balance from useWalletTokens
instead, looking up the live token by contractAddress + chainId. The
picker and the send screen now read from the same query.

Max button also lost precision: it did `balanceAmount.toString()` where
balanceAmount was Number(formatUnits(wei, decimals)). For balances whose
low-order wei round up when squeezed into a float64, parseUnits later
produced a BigInt above the actual on-chain balance and the transfer
reverted — while Send stayed enabled because the Zod check was a JS-Number
compare. Build the max string from the wei BigInt via formatUnits so it
round-trips through parseUnits exactly, and validate amount <= balance in
wei so the button can't enable for amounts that exceed the balance after
rounding.
…vZYP

Replace wagmi useBalance with useWalletTokens for fresher balance data
The form uses react-hook-form's onChange mode, which only re-runs the
Zod schema when the Controller's TextInput fires onChange. handleMaxPress
just calls setValue('amount', maxAmount), which writes the value but
doesn't run validation, so isValid stays at its prior value (false if
the user hadn't typed first) and the Review button remains disabled.

Call trigger('amount') after setValue — matches the pattern already
used in CardRepayForm and RegularWithdrawForm for the same problem.
…DOC-qa

fix(send): trigger validation on Max so Review enables immediately
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants