feat(card): surface Didit duplicate-filter review reasons on /card/activate (qa) - #2091
Open
MusabShakeel576 wants to merge 291 commits into
Open
feat(card): surface Didit duplicate-filter review reasons on /card/activate (qa)#2091MusabShakeel576 wants to merge 291 commits into
MusabShakeel576 wants to merge 291 commits into
Conversation
…n-back-eXrdB Simplify navigation logic in country selection flows
Add `freezeOnBlur` to tab screen options on native platforms. Without this, inactive tab screens continue re-rendering during tab switches, causing the previous page content to briefly flash before the new tab appears. `freezeOnBlur` uses react-freeze to suspend rendering of inactive screens, keeping them visually frozen in their last state. https://claude.ai/code/session_016VaxaMHLP2fYi3vjVd5U2n
…flash-IqLoo-qa Fix native tab navigation flashing previous page
Mayank/fix/mercuryo fix
Co-authored-by: Musab Shakil <MusabShakeel576@users.noreply.github.com>
Co-authored-by: Musab Shakil <MusabShakeel576@users.noreply.github.com>
…token-sync-db12 Fix vault/principal token mismatches in deposit modal
Co-authored-by: Musab Shakil <MusabShakeel576@users.noreply.github.com>
…-qa-fff4 Restore missing checkCardAccess and LayerZero helpers in qa
Co-authored-by: Musab Shakil <MusabShakeel576@users.noreply.github.com> (cherry picked from commit a0fd135)
…idit completion Previously, completing Didit KYC would always redirect to /card/ready even when Rain KYC was not yet approved (e.g. needsInformation, needsVerification, pending). Now only redirect to /card/ready when both Didit and Rain KYC are approved. Otherwise redirect to /card/activate so the user sees the dynamic step-one button to provide additional information. https://claude.ai/code/session_01LnsDaCsxy56ZcmsFaEZKJ7
h-auto works on web (lets flex stretch apply) but not native. h-full works on native but breaks web layout. Use native:!h-full and web:!h-auto to handle both platforms correctly. https://claude.ai/code/session_01QhMD9PevR5HwX1uWbUqShv
…dge quotes The old Stargate API (stargate.finance/api/v1/quotes) returns 410 Gone, breaking all deposit-to-card operations (Wallet, Savings, Borrow). Migrated to the new LayerZero Value Transfer API (transfer.layerzero-api.com/v1/quotes) which uses POST instead of GET and different parameter/response formats. The response is transformed back to the legacy format to avoid changes in all consuming hooks. https://claude.ai/code/session_01UdFXo6FkqQhCozNm7xXm7U
…ic-IBW3s Fix KYC redirect logic to show activate page when Rain not approved
…-qa-fff4 Gate Rain card country flow to allowed test users on qa
…ull-master Use platform-specific height overrides for toast close button
…or-HS5lC Migrate Stargate API to LayerZero Value Transfer API
…ist-TJWER Add mul53 to test features whitelist for Rain card testing
The Rain card onboarding, activation, and withdraw flows were gated behind a hardcoded username whitelist (TEST_FEATURES_ALLOW_LIST). This removes the isUserAllowedToUseTestFeature check from all card flows, now relying solely on the backend accessCheck.hasAccess. https://claude.ai/code/session_0175xemWqTv9ZPJdEqReBkYU
…e API Replace the HTTP API call to the deprecated stargate.finance endpoint (and the LayerZero VT API that required auth) with a direct on-chain call to the Stargate OFT contract's quoteSend function on Fuse, mirroring the backend approach from commit 5ac004e. This eliminates external API dependencies for bridge fee quoting. https://claude.ai/code/session_01UdFXo6FkqQhCozNm7xXm7U
…ad of hardcoded Arbitrum Rain card uses Base as the funding chain, not Arbitrum (which was for the old Bridge.xyz provider). Replaced hardcoded dstEid (30110/Arbitrum) with getStargateChainId(EXPO_PUBLIC_CARD_FUNDING_CHAIN_ID) and hardcoded to_chain (42161) with the config value in all three card deposit hooks. Also fixed the default for EXPO_PUBLIC_CARD_FUNDING_CHAIN_KEY from 'arbitrum' to 'base'. https://claude.ai/code/session_01UdFXo6FkqQhCozNm7xXm7U
… abis/ Since getStargateQuote is now a direct contract call (not an API call), moved it to lib/utils/stargate.ts alongside the other Stargate utilities and extracted the quoteSend ABI to lib/abis/StargateOFT.ts. Updated all 6 consumer imports accordingly. https://claude.ai/code/session_01UdFXo6FkqQhCozNm7xXm7U
…ting-7bsXv Remove test feature flag checks from card access logic
The hook was never imported or used anywhere in the codebase. https://claude.ai/code/session_0175xemWqTv9ZPJdEqReBkYU
…ixes-to-qa fix: deposit to card fixes — direct quoteSend, Base chain, refactor
…ting-7bsXv Remove unused useCardWithdrawAllowed hook
USDC_STARGATE (0xc6Bc...) is the ERC20 token, not the Stargate pool contract. The actual pool/OFT at 0xAF54BE5B6eEc24d6BFACf1cce4eaF680A8239398 implements quoteSend and is what CardDepositManager.depositUsingStargate expects as the oft parameter. https://claude.ai/code/session_01UdFXo6FkqQhCozNm7xXm7U
When Didit KYC is rejected and Rain was never reached, the step description showed the generic "Identity verification required" message. Now uses the kycStatus field from the card status response to detect Didit rejection and shows "Your identity verification was declined. Please try again with a valid ID." with a "Retry KYC" button. https://claude.ai/code/session_01XVLDUZPDp97k9896H5Lkhj
Show appropriate messages for Didit INCOMPLETE (resubmission needed) and UNDER_REVIEW states in the card activation step, instead of falling through to the generic default message. Under review disables the button so the user waits for the review to complete. https://claude.ai/code/session_01XVLDUZPDp97k9896H5Lkhj
Adds a debug shortcut so QA can preview the welcome popup without re-activating a card. Only honored when EXPO_PUBLIC_ENVIRONMENT is not 'production'.
…2DeY Add welcome card image
…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's duplicate IP / duplicate device filters are configured to send suspicious applicants to In Review so they don't reach Rain. Backend already maps that to kycStatus=UNDER_REVIEW with the warnings preserved on cardCustomer.diditWarnings, but step 1 of /card/activate returned the generic "being reviewed, takes a few minutes" copy regardless. Render the per-warning reasons when present so the applicant knows what's being checked; keep the original copy as the empty-warnings fallback. Also adds DUPLICATED_IP / DUPLICATED_DEVICE entries (and tightens POSSIBLE_DUPLICATED_USER) in DIDIT_WARNING_DESCRIPTIONS. Cherry-pick of #2090 onto qa.
|
The latest updates on your projects. Learn more about Vercel for GitHub. 2 Skipped Deployments
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Cherry-pick of #2090 onto
qa.Didit's new duplicate IP and duplicate device filters are configured to send suspicious applicants to In Review (so they don't reach Rain). The backend already maps that to
kycStatus: UNDER_REVIEWand persists the warnings oncardCustomer.diditWarnings, but step 1 of/card/activatereturned a fixed generic copy regardless. This surfaces the actual reason.DUPLICATED_IP/DUPLICATED_DEVICEtoDIDIT_WARNING_DESCRIPTIONSand tightensPOSSIBLE_DUPLICATED_USERwording.getStepDescriptionUNDER_REVIEW branch renders the warnings list when any are present; falls back to the original "takes a few minutes" copy when warnings are empty.Button stays
"Under Review"+ disabled — applicants wait for the reviewer's decision; we don't pre-judge a duplicate as fraud.Test plan
kycStatus: UNDER_REVIEWwithDUPLICATED_IPinkycWarnings./card/activate?kycStatus=under_review; verify step 1 description renders:Generated by Claude Code