Skip to content

Qa - #1505

Closed
LiorAgnin wants to merge 0 commit into
masterfrom
qa
Closed

Qa#1505
LiorAgnin wants to merge 0 commit into
masterfrom
qa

Conversation

@LiorAgnin

@LiorAgnin LiorAgnin commented Feb 15, 2026

Copy link
Copy Markdown
Contributor

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

vercel Bot commented Feb 15, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
solid-app-staging Ready Ready Preview, Comment Jun 23, 2026 8:51am
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
solid-app Ignored Ignored Preview Jun 23, 2026 8:51am

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

Comment thread app.config.ts
Comment thread app/(protected)/coins/[id].tsx
Comment thread app.config.ts Outdated
onSuccess?: () => void;
};

export default function BridgeKyc({ onSuccess }: BridgeKycParams = {}) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Route component accepts props that are never passed

Low Severity

BridgeKyc is an Expo Router page component but declares an onSuccess prop via BridgeKycParams. Expo Router renders route components without custom props, so onSuccess will always be undefined (from the default = {}). The onSuccess?.() call on completion will never execute, and onSuccess is incorrectly listed in the useEffect dependency array, which could cause unnecessary re-runs if the reference were ever non-stable.

Fix in Cursor Fix in Web

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

<View className="flex-shrink-0 flex-row items-center gap-2 md:gap-10">
<Text className={`text-right font-bold text-white`}>
{formatCardAmountWithCurrency(item.amount, item.currency)}
{formatCardAmountWithCurrency(item.amount, item.currency, provider)}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Rain card amounts shown as cents while provider loads

Medium Severity

formatCardAmountWithCurrency and formatCardAmount receive provider from useCardProvider, which can be null while loading. When provider is null, normalizeCardAmount skips the Rain cents-to-dollars division, causing Rain card transactions to display raw cent values as dollar amounts (e.g., $1234.00 instead of $12.34) until the provider resolves.

Additional Locations (1)
Fix in Cursor Fix in Web

@cursor

cursor Bot commented Mar 12, 2026

Copy link
Copy Markdown

You have run out of free Bugbot PR reviews for this billing cycle. This will reset on March 24.

To receive reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

6 similar comments
@cursor

cursor Bot commented Mar 12, 2026

Copy link
Copy Markdown

You have run out of free Bugbot PR reviews for this billing cycle. This will reset on March 24.

To receive reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

@cursor

cursor Bot commented Mar 12, 2026

Copy link
Copy Markdown

You have run out of free Bugbot PR reviews for this billing cycle. This will reset on March 24.

To receive reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

@cursor

cursor Bot commented Mar 12, 2026

Copy link
Copy Markdown

You have run out of free Bugbot PR reviews for this billing cycle. This will reset on March 24.

To receive reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

@cursor

cursor Bot commented Mar 12, 2026

Copy link
Copy Markdown

You have run out of free Bugbot PR reviews for this billing cycle. This will reset on March 24.

To receive reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

@cursor

cursor Bot commented Mar 12, 2026

Copy link
Copy Markdown

You have run out of free Bugbot PR reviews for this billing cycle. This will reset on March 24.

To receive reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

@cursor

cursor Bot commented Mar 12, 2026

Copy link
Copy Markdown

You have run out of free Bugbot PR reviews for this billing cycle. This will reset on March 24.

To receive reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

@LiorAgnin

Copy link
Copy Markdown
Contributor Author

@claude Review this

@claude

claude Bot commented Mar 18, 2026

Copy link
Copy Markdown

Claude finished @LiorAgnin's task in 4m 1s —— View job


PR Review — qa → master

This is a large, high-risk PR (6736 additions / 1406 deletions across 100 files) introducing multi-provider card support (Bridge vs Rain), a new KYC provider (Didit), MeaWallet MPP Apple/Google Wallet integration, and iOS wallet extensions. Below is a prioritized review.


Critical Bugs

1. Bridge card users permanently redirected to onboarding [app/(protected)/(tabs)/card/index.tsx:10]

hasCard() was changed to return false for Bridge users (cardStatus.provider !== CardProvider.BRIDGE), and hasCardStatusWithRainApplication() checks for rainApplicationStatus which Bridge users don't have. Bridge users with active cards will always be redirected to /card-onboard instead of /card/details.

Same issue in rewards/index.tsx:83 — Bridge users see a "Get Card" banner despite already having one.

Fix this →


2. Race condition redirects Bridge users to wrong KYC [app/(protected)/(tabs)/user-kyc-info.tsx:40-45]

const { provider: cardProvider } = useCardProvider();
// ...
useEffect(() => {
  if ((kycMode as KycMode) === KycMode.CARD && cardProvider !== CardProvider.BRIDGE) {
    router.replace(path.KYC as any); // fires when cardProvider is null (still loading)
  }
}, [kycMode, cardProvider, router]);

useCardProvider returns { provider: null, isLoading: true } initially. null !== CardProvider.BRIDGE is true, so this redirect fires before the provider is known, incorrectly redirecting Bridge users to the Rain KYC page. Need to guard with isLoading.

Fix this →


3. Wallet extension ships placeholder auth token [app/extensions/App.IssuerUIExtension.tsx:29-38]

// TODO: Replace with real auth – call backend or reuse main app auth.
const session = { email, token: 'placeholder' };
GroupPreference.set('session', JSON.stringify(session));

The password state is collected from the user but never used. IssuerNonUIExtension reads this session and calls getExtensionCards(token) with the invalid 'placeholder' token — the entire Apple Wallet add-card flow will fail at the API call. This is a non-functional feature being shipped. The login callback also has [email] in its deps array, omitting password.


4. Spin wheel stuck in "Spinning..." state [components/SpinAndWin/SpinWinModalProvider.tsx:435-443]

const result = await spin();
if (result) {
  setResultPoints(result.pointsEarned);
}
// catch only resets isSpinning — if result is undefined (expired session), isSpinning stays true forever

If spin() returns undefined (e.g., expired auth), the if (result) guard skips setting resultPoints, but isSpinning is never reset to false because only the catch branch resets it. The carousel never completes, leaving a permanent "Spinning..." disabled button with no recovery path.

Fix this →


5. Access-granted users redirected to waitlist [app/(protected)/(tabs)/card/activate/country_selection.tsx:214-215]

if (accessCheck.hasAccess) {
  const ipCountry = await getCountryFromIp();
  if (ipCountry && ipCountry.countryCode === selectedCountry.code) {
    router.replace(path.CARD_ACTIVATE);
  } else {
    router.replace(path.CARD_COUNTRY_SELECTION); // BUG: sends to waitlist/onboarding
  }

When a user has access but their IP country doesn't match their selection, they're sent to path.CARD_COUNTRY_SELECTION (the onboarding/waitlist page). This should be path.CARD_ACTIVATE_COUNTRY_SELECTION or similar.


High Severity

6. STATUS_PRIORITY collision — DETECTED can overwrite PROCESSING [store/useActivityStore.ts]

[TransactionStatus.DETECTED]: 1,
[TransactionStatus.PROCESSING]: 1,

Both have the same priority. A late-arriving DETECTED SSE event won't be blocked by isStatusDowngrade() (which only rejects when incoming priority is strictly less), causing a PROCESSING → DETECTED regression in displayed status.

Fix this →


7. Rain card amounts displayed as cents while provider loads [components/Card/CardDetailsReveal.tsx, app/(protected)/(tabs)/card/details/transactions.tsx]

normalizeCardAmount in cardHelpers.ts:54 divides by 100 only when provider === CardProvider.RAIN. When provider is null (loading), Rain amounts are shown as raw cents (e.g., $1234.00 instead of $12.34).


Medium Severity

8. DETECTED status missing from spinner and description [components/Transaction/index.tsx:218-226, 275]

// Line 275: spinner only shows for pending/processing, NOT detected
{(isPending || isProcessing) && <ActivityIndicator color="gray" size={14} />}

// getDescription() at line 218: no case for isDetected
const getDescription = () => {
  if (isPending) return 'Pending';
  if (isProcessing) return 'Processing';
  // isDetected missing — falls through to category text

This is inconsistent with isPendingOrProcessing at line 115 which correctly includes isDetected.

Fix this →


9. Bridge deposit countdown always starts from 5:00 [app/(protected)/(tabs)/activity/[clientTxId].tsx:364-369]

useEffect(() => {
  if (!finalActivity || !isDeposit || !createdAt) return; // only isDeposit, not isBridgeDeposit
  const elapsedSeconds = Math.floor((Date.now() - createdAt.getTime()) / 1000);
  setCurrentTime(Math.max(0, estimatedDurationSeconds - elapsedSeconds));
}, [finalActivity, isDeposit, createdAt, estimatedDurationSeconds]);

The estimated time row is displayed for isDeposit || isBridgeDeposit (line 516), but this useEffect only initializes the elapsed time for isDeposit. Bridge deposits always start at minutesToSeconds(5).


10. Sub-$1 funds trapped — withdraw button hidden [components/Card/WithdrawCardFundsModal.tsx:153]

{parseFloat(availableBalance) >= 1 ? (
  <Button onPress={handleWithdrawPress}>Withdraw</Button>
) : (
  <Button onPress={() => onOpenChange(false)}>Done</Button>  // only closes modal
)}

Users with balances between $0.01 and $0.99 see only a "Done" button that closes the modal, with no way to withdraw their funds.

Fix this →


11. Withdrawals "pending" detection includes undefined status [components/Card/WithdrawCardFundsModal.tsx:36]

const pendingWithdrawal = React.useMemo(() => {
  return withdrawalsData?.data?.find(w => w.status !== 'completed' && w.status !== 'failed');
}, [withdrawalsData]);

status is optional on CardWithdrawalResponse. When undefined, this condition is true, permanently flagging the modal as "pending" and blocking new withdrawals.


12. isBuyCryptoAvailable hardcoded to false on iOS [hooks/useGeoCompliance.ts:31]

isBuyCryptoAvailable: false, // ignores countryInfo and isCountryRestricted

This unconditionally disables buy-crypto on iOS regardless of country. If this is intentional (App Store policy compliance), it should be clearly documented; as written it appears to be a bug.


13. Android edgeToEdgeEnabled dropped during JS→TS migration [app.config.ts:70-95]

The android block in app.config.ts is missing edgeToEdgeEnabled: true which was in the old app.config.js. This will cause a visual regression on Android.

Fix this →


Low Severity / Code Quality

14. Memoized MPP availability never re-evaluates after async import [components/Card/AddToWalletRain.tsx:64-79]

appleMppAvailable and googleMppAvailable use useMemo with [] deps but read module-level variables set by a top-level import().then(). If the component renders before the import resolves, both are permanently false, showing "Available in the app" toasts even on native.

15. Debug console.warn left in production [app/(protected)/(tabs)/user-kyc-info.tsx:98]

console.warn('redirectUrl', redirectUrl);

16. savings-old QA comparison page accessible via URL [app/(protected)/(tabs)/savings-old.tsx]

The route is hidden from the tab bar (href: null) but remains URL-accessible in production. Per the PR description this was intentional for side-by-side comparison, but it adds dead code surface area and debugging components (SavingCountUpOld, SavingVaultOld) to production builds.

17. BridgeKyc route component declares onSuccess prop it never receives [app/(protected)/(tabs)/bridge-kyc.tsx:20]

Expo Router never passes custom props to route components; onSuccess will always be undefined. The onSuccess?.() call after completion is a no-op, and it's incorrectly listed in the useEffect deps.


Summary

The most critical items to address before merging:

Several Cursor Bugbot comments from earlier in the review appear to have already been addressed in later commits (fingerprint references removed, QA build flags cleaned up).

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.

2 participants