-
Notifications
You must be signed in to change notification settings - Fork 13
Make txn history private #1010
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make txn history private #1010
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
## Walkthrough
This update modifies the logic for displaying transaction history and activity details in user profile components. It introduces conditional filtering of transaction history, restricts visibility of activity summaries to profile owners, and adds a guest prompt for unauthorized access. The `useTransactionHistory` hook is extended to support mutual transaction filtering.
## Changes
| Files/Paths | Change Summary |
|------------------------------------------------|-----------------------------------------------------------------------------------------------------------------|
| src/components/Home/HomeHistory.tsx | Adds `filterMutualTxs` flag for conditional transaction filtering; enables hook only when logged in. |
| src/components/Profile/components/PublicProfile.tsx | Restricts activity summary visibility to profile owner; shows guest create-account prompt; modifies `HomeHistory` usage to non-public and logged-in only. |
| src/hooks/useTransactionHistory.ts | Adds optional `filterMutualTxs` parameter; updates hook signatures and query keys to support mutual transaction filtering. |
## Estimated code review effort
🎯 2 (Simple) | ⏱️ ~10 minutes
## Suggested reviewers
- kushagrasarathe Note ⚡️ Unit Test Generation is now available in beta!Learn more here, or try it out under "Finishing Touches" below. ✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/components/Home/HomeHistory.tsx (1)
126-126
: Minor: Fix CSS class typoThere's a typo in the CSS class
!mst-40
which should likely be!mt-40
for margin-top.- <div className="!mst-40 relative flex flex-col items-center justify-center space-y-4 rounded-sm border-2 border-black bg-white p-4"> + <div className="!mt-40 relative flex flex-col items-center justify-center space-y-4 rounded-sm border-2 border-black bg-white p-4">
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/components/Home/HomeHistory.tsx
(4 hunks)src/components/Profile/components/PublicProfile.tsx
(2 hunks)src/hooks/useTransactionHistory.ts
(4 hunks)
🧠 Learnings (4)
📓 Common learnings
Learnt from: kushagrasarathe
PR: peanutprotocol/peanut-ui#798
File: src/components/Home/HomeHistory.tsx:138-192
Timestamp: 2025-04-11T11:33:53.245Z
Learning: In the HomeHistory component, infinite scrolling is intentionally not implemented despite the presence of useInfiniteQuery and IntersectionObserver code. The component is designed to only display the first 5 entries with a "View all transactions" link for viewing the complete history.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#857
File: src/hooks/useWebSocket.ts:77-82
Timestamp: 2025-05-15T14:47:26.891Z
Learning: The useWebSocket hook in src/hooks/useWebSocket.ts is designed to provide raw history entries, while the components using it (such as HomeHistory.tsx) are responsible for implementing deduplication logic based on UUID to prevent duplicate entries when combining WebSocket data with other data sources.
src/components/Profile/components/PublicProfile.tsx (4)
Learnt from: kushagrasarathe
PR: #845
File: src/components/Request/link/views/Create.request.link.view.tsx:81-81
Timestamp: 2025-05-13T10:05:24.057Z
Learning: In the peanut-ui project, pages that handle request flows (like Create.request.link.view.tsx) are only accessible to logged-in users who will always have a username, making null checks for user?.user.username unnecessary in these contexts.
Learnt from: kushagrasarathe
PR: #798
File: src/components/Home/HomeHistory.tsx:138-192
Timestamp: 2025-04-11T11:33:53.245Z
Learning: In the HomeHistory component, infinite scrolling is intentionally not implemented despite the presence of useInfiniteQuery and IntersectionObserver code. The component is designed to only display the first 5 entries with a "View all transactions" link for viewing the complete history.
Learnt from: jjramirezn
PR: #564
File: src/components/Request/Pay/Views/Initial.view.tsx:430-430
Timestamp: 2024-12-11T10:13:22.806Z
Learning: In the React TypeScript file src/components/Request/Pay/Views/Initial.view.tsx
, when reviewing the InitialView
component, do not flag potential issues with using non-null assertion !
on the slippagePercentage
variable, as handling undefined values in this context is considered out of scope.
Learnt from: kushagrasarathe
PR: #828
File: src/app/(mobile-ui)/request/[...username]/page.tsx:17-17
Timestamp: 2025-05-02T19:14:25.010Z
Learning: In Next.js App Router, catch-all routes (like /request/[...username]
) will only match URLs with at least one parameter segment, ensuring that the page component only renders when there is at least one value in the params array.
src/components/Home/HomeHistory.tsx (14)
Learnt from: kushagrasarathe
PR: #798
File: src/components/Home/HomeHistory.tsx:138-192
Timestamp: 2025-04-11T11:33:53.245Z
Learning: In the HomeHistory component, infinite scrolling is intentionally not implemented despite the presence of useInfiniteQuery and IntersectionObserver code. The component is designed to only display the first 5 entries with a "View all transactions" link for viewing the complete history.
Learnt from: jjramirezn
PR: #857
File: src/hooks/useWebSocket.ts:77-82
Timestamp: 2025-05-15T14:47:26.891Z
Learning: The useWebSocket hook in src/hooks/useWebSocket.ts is designed to provide raw history entries, while the components using it (such as HomeHistory.tsx) are responsible for implementing deduplication logic based on UUID to prevent duplicate entries when combining WebSocket data with other data sources.
Learnt from: kushagrasarathe
PR: #845
File: src/components/Request/link/views/Create.request.link.view.tsx:81-81
Timestamp: 2025-05-13T10:05:24.057Z
Learning: In the peanut-ui project, pages that handle request flows (like Create.request.link.view.tsx) are only accessible to logged-in users who will always have a username, making null checks for user?.user.username unnecessary in these contexts.
Learnt from: jjramirezn
PR: #551
File: src/components/Request/Create/Views/Initial.view.tsx:151-156
Timestamp: 2024-12-02T17:19:18.532Z
Learning: In the InitialView
component at src/components/Request/Create/Views/Initial.view.tsx
, when setting the default chain and token in the useEffect
triggered by isPeanutWallet
, it's acceptable to omit the setters from the dependency array and not include additional error handling for invalid defaults.
Learnt from: jjramirezn
PR: #631
File: src/components/Create/Create.tsx:108-112
Timestamp: 2025-01-16T13:14:40.363Z
Learning: In the Peanut UI codebase, the resetTokenContextProvider
function from tokenSelectorContext
is a stable function reference that doesn't change, so it doesn't need to be included in useEffect dependencies.
Learnt from: jjramirezn
PR: #564
File: src/components/Request/Pay/Views/Initial.view.tsx:430-430
Timestamp: 2024-12-11T10:13:22.806Z
Learning: In the React TypeScript file src/components/Request/Pay/Views/Initial.view.tsx
, when reviewing the InitialView
component, do not flag potential issues with using non-null assertion !
on the slippagePercentage
variable, as handling undefined values in this context is considered out of scope.
Learnt from: jjramirezn
PR: #422
File: src/components/Request/Pay/Pay.consts.ts:34-34
Timestamp: 2024-10-07T15:50:29.173Z
Learning: In src/components/Request/Pay
components, the tokenPrice
property in the IPayScreenProps
interface is only relevant to these views. Other components using IPayScreenProps
do not need to handle tokenPriceData
when it's updated in these components.
Learnt from: jjramirezn
PR: #422
File: src/components/Request/Pay/Pay.consts.ts:34-34
Timestamp: 2024-10-08T20:13:42.967Z
Learning: In src/components/Request/Pay
components, the tokenPrice
property in the IPayScreenProps
interface is only relevant to these views. Other components using IPayScreenProps
do not need to handle tokenPriceData
when it's updated in these components.
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#0
File: :0-0
Timestamp: 2025-07-05T16:58:25.340Z
Learning: Hugo0 successfully refactored sessionStorage usage to React Context in the onramp flow, demonstrating preference for centralized state management over browser storage for component-shared state in React applications.
Learnt from: jjramirezn
PR: #413
File: src/context/tokenSelector.context.tsx:118-123
Timestamp: 2024-10-08T20:13:42.967Z
Learning: In the TokenContextProvider
component within src/context/tokenSelector.context.tsx
, in the TypeScript React application, when data changes and before calling fetchAndSetTokenPrice
, it is necessary to reset selectedTokenData
, selectedTokenPrice
, selectedTokenDecimals
, and inputDenomination
to discard stale data.
Learnt from: jjramirezn
PR: #469
File: src/app/request/pay/page.tsx:32-64
Timestamp: 2024-10-23T09:38:27.670Z
Learning: In src/app/request/pay/page.tsx
, if linkRes
is not OK in the generateMetadata
function, the desired behavior is to use the standard title and preview image without throwing an error.
Learnt from: kushagrasarathe
PR: #869
File: src/app/(mobile-ui)/withdraw/page.tsx:82-88
Timestamp: 2025-05-22T15:38:48.586Z
Learning: The country-specific withdrawal route exists at src/app/(mobile-ui)/withdraw/[...country]/page.tsx and renders the AddWithdrawCountriesList component with flow="withdraw".
Learnt from: kushagrasarathe
PR: #869
File: src/app/(mobile-ui)/withdraw/page.tsx:82-88
Timestamp: 2025-05-22T15:38:48.586Z
Learning: The country-specific withdrawal route exists at src/app/(mobile-ui)/withdraw/[...country]/page.tsx and renders the AddWithdrawCountriesList component with flow="withdraw".
Learnt from: jjramirezn
PR: #484
File: src/components/Cashout/Components/Initial.view.tsx:273-274
Timestamp: 2024-10-25T11:33:46.776Z
Learning: In the InitialCashoutView
component (src/components/Cashout/Components/Initial.view.tsx
), linked bank accounts should not generate error states, and the ValidatedInput
component will clear any error messages if needed. Therefore, it's unnecessary to manually clear the error state when selecting or clearing linked bank accounts.
src/hooks/useTransactionHistory.ts (2)
Learnt from: jjramirezn
PR: #857
File: src/hooks/useWebSocket.ts:77-82
Timestamp: 2025-05-15T14:47:26.891Z
Learning: The useWebSocket hook in src/hooks/useWebSocket.ts is designed to provide raw history entries, while the components using it (such as HomeHistory.tsx) are responsible for implementing deduplication logic based on UUID to prevent duplicate entries when combining WebSocket data with other data sources.
Learnt from: kushagrasarathe
PR: #798
File: src/components/Home/HomeHistory.tsx:138-192
Timestamp: 2025-04-11T11:33:53.245Z
Learning: In the HomeHistory component, infinite scrolling is intentionally not implemented despite the presence of useInfiniteQuery and IntersectionObserver code. The component is designed to only display the first 5 entries with a "View all transactions" link for viewing the complete history.
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: kushagrasarathe
PR: peanutprotocol/peanut-ui#798
File: src/components/Home/HomeHistory.tsx:138-192
Timestamp: 2025-04-11T11:33:53.245Z
Learning: In the HomeHistory component, infinite scrolling is intentionally not implemented despite the presence of useInfiniteQuery and IntersectionObserver code. The component is designed to only display the first 5 entries with a "View all transactions" link for viewing the complete history.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#857
File: src/hooks/useWebSocket.ts:77-82
Timestamp: 2025-05-15T14:47:26.891Z
Learning: The useWebSocket hook in src/hooks/useWebSocket.ts is designed to provide raw history entries, while the components using it (such as HomeHistory.tsx) are responsible for implementing deduplication logic based on UUID to prevent duplicate entries when combining WebSocket data with other data sources.
src/components/Profile/components/PublicProfile.tsx (4)
Learnt from: kushagrasarathe
PR: #845
File: src/components/Request/link/views/Create.request.link.view.tsx:81-81
Timestamp: 2025-05-13T10:05:24.057Z
Learning: In the peanut-ui project, pages that handle request flows (like Create.request.link.view.tsx) are only accessible to logged-in users who will always have a username, making null checks for user?.user.username unnecessary in these contexts.
Learnt from: kushagrasarathe
PR: #798
File: src/components/Home/HomeHistory.tsx:138-192
Timestamp: 2025-04-11T11:33:53.245Z
Learning: In the HomeHistory component, infinite scrolling is intentionally not implemented despite the presence of useInfiniteQuery and IntersectionObserver code. The component is designed to only display the first 5 entries with a "View all transactions" link for viewing the complete history.
Learnt from: jjramirezn
PR: #564
File: src/components/Request/Pay/Views/Initial.view.tsx:430-430
Timestamp: 2024-12-11T10:13:22.806Z
Learning: In the React TypeScript file src/components/Request/Pay/Views/Initial.view.tsx
, when reviewing the InitialView
component, do not flag potential issues with using non-null assertion !
on the slippagePercentage
variable, as handling undefined values in this context is considered out of scope.
Learnt from: kushagrasarathe
PR: #828
File: src/app/(mobile-ui)/request/[...username]/page.tsx:17-17
Timestamp: 2025-05-02T19:14:25.010Z
Learning: In Next.js App Router, catch-all routes (like /request/[...username]
) will only match URLs with at least one parameter segment, ensuring that the page component only renders when there is at least one value in the params array.
src/components/Home/HomeHistory.tsx (14)
Learnt from: kushagrasarathe
PR: #798
File: src/components/Home/HomeHistory.tsx:138-192
Timestamp: 2025-04-11T11:33:53.245Z
Learning: In the HomeHistory component, infinite scrolling is intentionally not implemented despite the presence of useInfiniteQuery and IntersectionObserver code. The component is designed to only display the first 5 entries with a "View all transactions" link for viewing the complete history.
Learnt from: jjramirezn
PR: #857
File: src/hooks/useWebSocket.ts:77-82
Timestamp: 2025-05-15T14:47:26.891Z
Learning: The useWebSocket hook in src/hooks/useWebSocket.ts is designed to provide raw history entries, while the components using it (such as HomeHistory.tsx) are responsible for implementing deduplication logic based on UUID to prevent duplicate entries when combining WebSocket data with other data sources.
Learnt from: kushagrasarathe
PR: #845
File: src/components/Request/link/views/Create.request.link.view.tsx:81-81
Timestamp: 2025-05-13T10:05:24.057Z
Learning: In the peanut-ui project, pages that handle request flows (like Create.request.link.view.tsx) are only accessible to logged-in users who will always have a username, making null checks for user?.user.username unnecessary in these contexts.
Learnt from: jjramirezn
PR: #551
File: src/components/Request/Create/Views/Initial.view.tsx:151-156
Timestamp: 2024-12-02T17:19:18.532Z
Learning: In the InitialView
component at src/components/Request/Create/Views/Initial.view.tsx
, when setting the default chain and token in the useEffect
triggered by isPeanutWallet
, it's acceptable to omit the setters from the dependency array and not include additional error handling for invalid defaults.
Learnt from: jjramirezn
PR: #631
File: src/components/Create/Create.tsx:108-112
Timestamp: 2025-01-16T13:14:40.363Z
Learning: In the Peanut UI codebase, the resetTokenContextProvider
function from tokenSelectorContext
is a stable function reference that doesn't change, so it doesn't need to be included in useEffect dependencies.
Learnt from: jjramirezn
PR: #564
File: src/components/Request/Pay/Views/Initial.view.tsx:430-430
Timestamp: 2024-12-11T10:13:22.806Z
Learning: In the React TypeScript file src/components/Request/Pay/Views/Initial.view.tsx
, when reviewing the InitialView
component, do not flag potential issues with using non-null assertion !
on the slippagePercentage
variable, as handling undefined values in this context is considered out of scope.
Learnt from: jjramirezn
PR: #422
File: src/components/Request/Pay/Pay.consts.ts:34-34
Timestamp: 2024-10-07T15:50:29.173Z
Learning: In src/components/Request/Pay
components, the tokenPrice
property in the IPayScreenProps
interface is only relevant to these views. Other components using IPayScreenProps
do not need to handle tokenPriceData
when it's updated in these components.
Learnt from: jjramirezn
PR: #422
File: src/components/Request/Pay/Pay.consts.ts:34-34
Timestamp: 2024-10-08T20:13:42.967Z
Learning: In src/components/Request/Pay
components, the tokenPrice
property in the IPayScreenProps
interface is only relevant to these views. Other components using IPayScreenProps
do not need to handle tokenPriceData
when it's updated in these components.
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#0
File: :0-0
Timestamp: 2025-07-05T16:58:25.340Z
Learning: Hugo0 successfully refactored sessionStorage usage to React Context in the onramp flow, demonstrating preference for centralized state management over browser storage for component-shared state in React applications.
Learnt from: jjramirezn
PR: #413
File: src/context/tokenSelector.context.tsx:118-123
Timestamp: 2024-10-08T20:13:42.967Z
Learning: In the TokenContextProvider
component within src/context/tokenSelector.context.tsx
, in the TypeScript React application, when data changes and before calling fetchAndSetTokenPrice
, it is necessary to reset selectedTokenData
, selectedTokenPrice
, selectedTokenDecimals
, and inputDenomination
to discard stale data.
Learnt from: jjramirezn
PR: #469
File: src/app/request/pay/page.tsx:32-64
Timestamp: 2024-10-23T09:38:27.670Z
Learning: In src/app/request/pay/page.tsx
, if linkRes
is not OK in the generateMetadata
function, the desired behavior is to use the standard title and preview image without throwing an error.
Learnt from: kushagrasarathe
PR: #869
File: src/app/(mobile-ui)/withdraw/page.tsx:82-88
Timestamp: 2025-05-22T15:38:48.586Z
Learning: The country-specific withdrawal route exists at src/app/(mobile-ui)/withdraw/[...country]/page.tsx and renders the AddWithdrawCountriesList component with flow="withdraw".
Learnt from: kushagrasarathe
PR: #869
File: src/app/(mobile-ui)/withdraw/page.tsx:82-88
Timestamp: 2025-05-22T15:38:48.586Z
Learning: The country-specific withdrawal route exists at src/app/(mobile-ui)/withdraw/[...country]/page.tsx and renders the AddWithdrawCountriesList component with flow="withdraw".
Learnt from: jjramirezn
PR: #484
File: src/components/Cashout/Components/Initial.view.tsx:273-274
Timestamp: 2024-10-25T11:33:46.776Z
Learning: In the InitialCashoutView
component (src/components/Cashout/Components/Initial.view.tsx
), linked bank accounts should not generate error states, and the ValidatedInput
component will clear any error messages if needed. Therefore, it's unnecessary to manually clear the error state when selecting or clearing linked bank accounts.
src/hooks/useTransactionHistory.ts (2)
Learnt from: jjramirezn
PR: #857
File: src/hooks/useWebSocket.ts:77-82
Timestamp: 2025-05-15T14:47:26.891Z
Learning: The useWebSocket hook in src/hooks/useWebSocket.ts is designed to provide raw history entries, while the components using it (such as HomeHistory.tsx) are responsible for implementing deduplication logic based on UUID to prevent duplicate entries when combining WebSocket data with other data sources.
Learnt from: kushagrasarathe
PR: #798
File: src/components/Home/HomeHistory.tsx:138-192
Timestamp: 2025-04-11T11:33:53.245Z
Learning: In the HomeHistory component, infinite scrolling is intentionally not implemented despite the presence of useInfiniteQuery and IntersectionObserver code. The component is designed to only display the first 5 entries with a "View all transactions" link for viewing the complete history.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Deploy-Preview
🔇 Additional comments (9)
src/hooks/useTransactionHistory.ts (3)
84-84
: LGTM: Clean addition of filterMutualTxs parameterThe new
filterMutualTxs
parameter is correctly added to all necessary type definitions and function signatures, maintaining consistency across the hook's interface.Also applies to: 92-92, 111-111
230-233
: Good cache key modification for proper invalidationThe query key correctly includes the username when
filterMutualTxs
is true, ensuring that cached data is properly invalidated when viewing different users' mutual transactions. The concatenation approach is simple and effective.
125-126
: Verify backend support fortargetUsername
query parameter
I performed a repo-wide search and didn’t find any references totargetUsername
in API handlers or documentation. Please confirm that the/users/{username}/history
endpoint accepts atargetUsername
parameter for filtering mutual transactions. If it isn’t yet supported, coordinate with the backend team to implement or document this query string.• File:
src/hooks/useTransactionHistory.ts
, lines 125–126src/components/Profile/components/PublicProfile.tsx (2)
109-110
: Excellent privacy enhancement: restrict activity details to ownerThe condition correctly ensures that only the account owner can view their total sent/received activity details by comparing the logged-in user's username with the profile username. This effectively implements the privacy requirement.
175-175
: Correct alignment with privacy objectivesChanging the
isPublic
prop fromtrue
tofalse
correctly aligns with the privacy requirements, ensuring that transaction history is displayed in a private context with appropriate filtering for non-owners.src/components/Home/HomeHistory.tsx (4)
20-22
: LGTM: Appropriate imports for new functionalityThe new imports for
Button
,useRouter
, andPeanutGuyGIF
are correctly added to support the guest user invitation UI.
35-40
: Good integration with updated hookThe
useTransactionHistory
call correctly includes the newfilterMutualTxs
parameter and properly restricts the hook to logged-in users withenabled: isLoggedIn
.
121-144
: Excellent guest user experience with privacy complianceThe guest user UI effectively prevents unauthorized access to transaction data while providing a clear path to account creation. The styling and messaging are appropriate for encouraging user engagement.
33-34
: filterMutualTxs logic is safe as implementedBoth usages of guarantee a defined username when the user is authenticated, so the scenario of “username undefined but user logged in” does not occur:
• src/app/(mobile-ui)/home/page.tsx:
– Passes username={username ?? undefined} but doesn’t render until isLoading is false and username is populated.
• src/components/Profile/components/PublicProfile.tsx:
– Passes username from the route (always defined) and only renders in a client context.No change required.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Zishan-7 left a suggestion
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Zishan-7 lgtm, approved, lets merge after prod release
* refactor: fetch external wallet balances from mobula (#956) * fix: update desktop navigation (#970) * fix: support page prod (#971) * fix: update desktop navigation * fix: support page * [TASK-12746] feat: beta changes (#975) * feat: beta changes - Banner that redirects to support page - Funds warning modal * refactor(banner): remove from landing and add hand thumbs up * [TASK-13082] Sprint 100 prod release (#992) * feat: abstract squid route fetching Stop using the skd and use the squid API directly, this give us more control and access to all the data that returns squid (for example, we now have access to the fees and don't have to recalculate them ourselves) * refactor: use parseunits Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * refactor: remove console.dir * feat: handle very large numbers with careful scaling * refactor: use const for squid api url * feat: add cross-chain action card Use coral through squid to get the cross-chain route for the different flows. This enables xchain withdraw for peanut wallet * refactor: use decimals from token price instead of hardcoded * style: Apply prettier formatting * feat: show min received for cross-chain payments * chore: clean unused variables * fix: tests ach_pull to ach * fix: pr comments * fix: withdrawData and pulsate animation * fix: cursor placement in token amount input * fix: delete unused code * fix: add camera perm modal * fix: enable mexico bank offramp * refactor: better comments for direct usd payments * feat: add qr scanning for xchain * fix: remove malicious code * fix: handle mxn in offramp destination details (#945) * fix: show share receipt option in direct send status view (#946) * [TASK-12678] fix: coral withdraw fixes (#949) * fix: coral withdraw fixes - Stop refreshing the page after successful payment - Better error message for unsupported token pairs * chore: add squid env vars * refactor: better copy for non rfq routes from peanut wallet Also send warning to sentry * fix: show amount in USD for withdrawals to other tokens to other tokens * fix: lock orientation to portrait mode (#947) * fix: lock orienatation to protrait mode * style(fix): add new line * style: format * fix: if condition * fix: update payment form for crosschain add money (#954) * [TASK-12682] fix: show token selector for guest flow (#955) * fix: show token selector for guest flow * docs: add comment to explain url request flow * implemented Context instead of sessionStorage in onrampData to avoid discrepancies with the Offramp logic (#953) * refactor: fetch external wallet balances from mobula (#956) (#958) * [TASK-12645] copy button for individual fields (#960) * copy button for individual fields * changed getOnrampCurrencyConfig (deprecated)to getCurrencyConfig + user now copies raw IBAN value * fix: gas estimation for external wallets (#961) We were re-rendering unnecesarily the prepare transaction, also now we catch error if any * [TASK-12603] reset send flow state when navigating to/from payment link creation (#964) * reset send flow state when navigating to/from payment link creation * linting (formatting) * [TASK-12312] ENS/eth address network error being displayed on the frontend (#963) * ENS/eth address network error being displayed on the frontend * linting * fix: centre align views on mobile (#950) * [TASK-12542] added formatIban function for correct display (#952) * added formatIban function for correct display * coderabbit suggestion Signed-off-by: facundobozzi <[email protected]> * updated formatting * added iban formatting in all pages --------- Signed-off-by: facundobozzi <[email protected]> * [TASK-12672] feat: show sponsored by peanut message (#959) * feat: show sponsored by peanut message This message is shown when we are making a transaction from the peanut wallet. If the amount is more than one cent we also show the fee that the user is saving by using peanut. * fix(fees): show correct ammounts for externalwallet * refactor: rename estimatedGasCostUsd to estimatedGasCostUsdUsd * fix: correct approval owner and base rpc (#965) Two things here: 1. We were using the peanut address for approval checking on deposits, this didn't affect because if the approval call failed we just continued with the deposit 2: The base rpc url was the sepolia one, not the mainnet. Big oversight there * feat: add alachemy as fallback rpc url (#948) * feat: add alachemy as fallback rpc url * fix: remove commented line * fix: address pr review comments * [TASK-12866] fix: small fixes around crosschain ui (#966) * fix: small fixes around crosschain ui * fix: avoid negative expiry time * removed white spaces before processing to BIC (#951) * feat: resuable slider component (#968) * fix: update desktop navigation with add/withdraw paths (#969) * [TASK-11884] request via link with comment and attachment is creating 2 txs in the history (#943) * PATCH implemented in frontend * comment input state updating correctly (onBlur) * freezing amount after updating comments/files input * debounce attachment options and update requests on file change (avoiding race conditions when attaching files!) * style: Apply prettier formatting * removed malicious code Signed-off-by: facundobozzi <[email protected]> * PATCH method using withFormData * better onBlur logic * bug fixes * blur logic fixed * nit pick comments * code rabbit suggestion * replaced useEffect setting state with derived state and debouncing * disabling amount input after request creation * linting --------- Signed-off-by: facundobozzi <[email protected]> * fix: support page staging (#972) * fix: update desktop navigation with add/withdraw paths * fix: support page * fix: ui comments (#973) * Support and beta changes to staging (#978) * refactor: fetch external wallet balances from mobula (#956) * fix: update desktop navigation (#970) * fix: support page prod (#971) * fix: update desktop navigation * fix: support page * [TASK-12746] feat: beta changes (#975) * feat: beta changes - Banner that redirects to support page - Funds warning modal * refactor(banner): remove from landing and add hand thumbs up --------- Co-authored-by: Kushagra Sarathe <[email protected]> * [TASK-12312] Bugfix/ens error withdrawing (#976) * ENS/eth address network error being displayed on the frontend * linting * fixed andre QA observations * deleting console.log * formatting * logic fixed * fixed testst --------- Signed-off-by: facundobozzi <[email protected]> * fix: coral small issues (#979) * chore: enable usdt in mainnet (#980) * fix: slider tap bug logic (#983) * fix: slider tap bug logic * fix: tap bug on slider * fix: some issues and comments (#984) * [TASK-12771] Feat/new landing page (#974) * removed legacy button and changed try now button colors * try now button color and hero description * YourMoney component * NoFees component first part * stars done * scribble in zero fees * no hidden fees section done * securityBuiltIn done * sendInSeconds progress * sendInSeconds done * updated try now button to be a link * business integration initiation * businessIntegrate done * order and marquee reusability * order fixed * background animations in Landing Page compoejnnts * changed image for text in hero section * figma details * landing page responsiveness improvements * landing page responsiveness done * coderabbit suggestion * business integration button * fixed iphone screenshots * CTA button animation * added debugging for CTA button animation * changed animation since react gave errors * arrows in hero section * NoFees new Zero * no fees responsiveness fixed * sendInSeconds details done * coderabbit suggestions * formatting * hand-token wasnt pushed? forgot to stage or sum? anyways fixed * build issues fixed * coderabbit optimization * code formatting * arrows and ZERO thickness * shade in try now button * progress in button animation * undoing button changes * small detail fixes * added asset * changed peanut business to svg * integrate peanut component done * added pay-zero-fees.svg * added new illustrations * uout money anywhere svg * securitybuiltin component SVGs * adding YourMoney new SVGs * your money anywhere component * instantly send & receive svg * arrows fixed * button and arrows done * desktop sendinseconds button done * removed arrows disappearing effect * MOBILE: hero button done * added mobile svg * yourMoney responsive component done * added mobile-zero-fees.svg * added no-hidden-fees.svg * noFees mobile svg * noFees desktop + mobile improvements * noFees done * mobile security built in SVG * securityprivacy mobile done * mobile-send-in-seconds.svg * sendInSeconds mobile done * business integrate mobile * business integrate button and final details * removed footer * formatting * removed pino-pretty * fixed button instead of sticky/floating --------- Signed-off-by: facundobozzi <[email protected]> * [TASK-13136] feat: allow uppercase in url (#986) * feat: allow uppercase in url * fix: allow uppercase in recipient * fix: inform create request type when creating from UI (#987) * fix: balance warning modal (#988) - Slider instead of button - Expiry for local storage instead of session storage - Warning icon color * chore: remove unused file (#990) * chore: re-add removed code for gas estimation --------- Signed-off-by: facundobozzi <[email protected]> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: kushagrasarathe <[email protected]> Co-authored-by: facundobozzi <[email protected]> --------- Signed-off-by: facundobozzi <[email protected]> Co-authored-by: Kushagra Sarathe <[email protected]> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: facundobozzi <[email protected]>
* feat: update add/withdraw flow to use new slider component * feat: guest receive to exchange/crypto flows * fix: coderabbit comments * fix: slider usage * feat: new server actions for guest flow * feat: update card and success view component for bank claims * feat: claim to bank flow components * fix: coderbbit comments * fix: import * feat: handle bank link claims for when sender is non-kyced (#996) * feat: handle bank link claims for when sender is non-kyced * fix: kyc status check for sender * fix: codderabbit comments * fix: update route payloads based on be changes * fix: merge conflict * feat: ui updates to bank flow * fix: rename comp name * fix: wrap fn in callback * feat: min ammount modal for send link claims
…ve not completed kyc (#999) * fix: allow user to change their email address if they have not completed kyc * fix: account incorrect field
e8e5bc3
to
9593ac7
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 7
🧹 Nitpick comments (7)
src/app/actions/users.ts (1)
115-115
: Remove debug console.log statement.This debug statement should be removed before merging to production.
- console.log('response kushhh', responseJson)
src/components/Global/PostSignupActionManager/index.tsx (1)
53-56
: Add error handling for localStorage operations.The localStorage operations should include error handling to prevent potential crashes.
onClose={() => { setShowModal(false) - localStorage.removeItem('redirect') + try { + localStorage.removeItem('redirect') + } catch (error) { + console.error('Error removing redirect from localStorage:', error) + } }}src/app/actions/external-accounts.ts (1)
9-37
: Add input validation and consider PII logging implications.The function implementation is solid with good error handling. Consider these improvements:
export async function createBridgeExternalAccountForGuest( customerId: string, accountDetails: AddBankAccountPayload ): Promise<{ id: string } | { error: string }> { + // Input validation + if (!customerId?.trim()) { + return { error: 'Customer ID is required' } + } + if (!accountDetails) { + return { error: 'Account details are required' } + } + try { const response = await fetchWithSentry(`${API_URL}/bridge/customers/${customerId}/external-accounts`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'api-key': API_KEY, }, body: JSON.stringify(accountDetails), }) const data = await response.json() if (!response.ok) { return { error: data.error || 'Failed to create external account.' } } return data } catch (error) { - console.error(`Error creating external account for ${customerId}:`, error) + console.error('Error creating external account for guest user:', error) if (error instanceof Error) { return { error: error.message } } return { error: 'An unexpected error occurred.' } } }Note: The error logging was modified to avoid logging the customer ID, which could be considered PII.
src/components/Claim/Link/views/Confirm.bank-claim.view.tsx (2)
36-42
: Add error handling for sessionStorage accessThe sessionStorage access could throw an error in environments where storage is disabled (e.g., incognito mode). Consider wrapping it in a try-catch block.
const displayedFullName = useMemo(() => { if (fullName) return fullName if (typeof window !== 'undefined') { - return sessionStorage.getItem('receiverFullName') ?? '' + try { + return sessionStorage.getItem('receiverFullName') ?? '' + } catch (error) { + console.warn('Failed to access sessionStorage:', error) + return '' + } } return '' }, [fullName])
72-73
: Clarify or remove misleading TODO commentThe TODO comment states "this name rn is of senders" but the
displayedFullName
appears to be the receiver's name based on the prop namefullName
and the sessionStorage keyreceiverFullName
. This comment should be clarified or removed if it's outdated.- {/* todo: take full name from user, this name rn is of senders */} + {/* TODO: Validate that the full name belongs to the account owner */} <PaymentInfoRow label="Full name" value={displayedFullName} />src/components/Claim/Link/Onchain/Success.view.tsx (1)
88-89
: Consider implementing dynamic bank account display.The TODO comment indicates showing actual bank account numbers is scoped for the next PR. Ensure this is tracked appropriately.
Would you like me to create an issue to track the implementation of dynamic bank account number display?
src/components/AddWithdraw/DynamicBankAccountForm.tsx (1)
242-258
: Consider improving BIC field state management.The current implementation resets showBicField and BIC value on every IBAN blur. Consider optimizing this to avoid unnecessary state changes when the IBAN hasn't actually changed.
async (field) => { if (!field.value || field.value.trim().length === 0) return + + const currentIban = field.value.trim() + const previousIban = field.previousValue?.trim() + + if (currentIban === previousIban) return try { setShowBicField(false) setValue('bic', '', { shouldValidate: false }) - const bic = await getBicFromIban(field.value.trim()) + const bic = await getBicFromIban(currentIban) if (bic) { setValue('bic', bic, { shouldValidate: true }) } else { setShowBicField(true) } } catch (error) { console.warn('Failed to fetch BIC:', error) setShowBicField(true) } }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (3)
src/assets/fonts/roboto-flex-bold.ttf
is excluded by!**/*.ttf
src/assets/illustrations/exclamations.svg
is excluded by!**/*.svg
src/assets/scribble.svg
is excluded by!**/*.svg
📒 Files selected for processing (41)
src/app/(mobile-ui)/add-money/[country]/bank/page.tsx
(1 hunks)src/app/(mobile-ui)/home/page.tsx
(6 hunks)src/app/(mobile-ui)/withdraw/crypto/page.tsx
(0 hunks)src/app/actions/exchange-rate.ts
(0 hunks)src/app/actions/external-accounts.ts
(1 hunks)src/app/actions/offramp.ts
(1 hunks)src/app/actions/tokens.ts
(1 hunks)src/app/actions/users.ts
(2 hunks)src/app/layout.tsx
(2 hunks)src/app/page.tsx
(3 hunks)src/components/AddMoney/UserDetailsForm.tsx
(0 hunks)src/components/AddWithdraw/AddWithdrawCountriesList.tsx
(3 hunks)src/components/AddWithdraw/DynamicBankAccountForm.tsx
(10 hunks)src/components/Claim/Link/Initial.view.tsx
(7 hunks)src/components/Claim/Link/Onchain/Success.view.tsx
(3 hunks)src/components/Claim/Link/views/BankFlowManager.view.tsx
(1 hunks)src/components/Claim/Link/views/ClaimCountryList.view.tsx
(1 hunks)src/components/Claim/Link/views/Confirm.bank-claim.view.tsx
(1 hunks)src/components/ExchangeRate/index.tsx
(0 hunks)src/components/Global/FAQs/index.tsx
(1 hunks)src/components/Global/Icons/Icon.tsx
(3 hunks)src/components/Global/Icons/dollar.tsx
(1 hunks)src/components/Global/PeanutActionDetailsCard/index.tsx
(9 hunks)src/components/Global/PostSignupActionManager/index.tsx
(1 hunks)src/components/Global/PostSignupActionManager/post-signup-action.consts.ts
(1 hunks)src/components/GuestActions/MethodList.tsx
(3 hunks)src/components/Home/HomeHistory.tsx
(2 hunks)src/components/LandingPage/businessIntegrate.tsx
(3 hunks)src/components/LandingPage/hero.tsx
(4 hunks)src/components/LandingPage/securityBuiltIn.tsx
(3 hunks)src/components/LandingPage/sendInSeconds.tsx
(2 hunks)src/components/LandingPage/yourMoney.tsx
(2 hunks)src/components/Profile/components/PublicProfile.tsx
(4 hunks)src/context/GuestFlowContext.tsx
(2 hunks)src/hooks/usePaymentInitiator.ts
(5 hunks)src/hooks/useTransactionHistory.ts
(4 hunks)src/interfaces/interfaces.ts
(1 hunks)src/services/charges.ts
(2 hunks)src/services/services.types.ts
(2 hunks)src/styles/globals.css
(1 hunks)tailwind.config.js
(1 hunks)
💤 Files with no reviewable changes (4)
- src/components/ExchangeRate/index.tsx
- src/app/(mobile-ui)/withdraw/crypto/page.tsx
- src/components/AddMoney/UserDetailsForm.tsx
- src/app/actions/exchange-rate.ts
✅ Files skipped from review due to trivial changes (6)
- src/app/actions/tokens.ts
- src/components/Global/FAQs/index.tsx
- src/styles/globals.css
- src/components/Global/Icons/dollar.tsx
- src/components/Global/PostSignupActionManager/post-signup-action.consts.ts
- src/components/Global/Icons/Icon.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
- src/components/Profile/components/PublicProfile.tsx
- src/components/Home/HomeHistory.tsx
🧰 Additional context used
🪛 Biome (2.1.2)
src/hooks/useTransactionHistory.ts
[error] 232-232: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.
For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level
(lint/correctness/useHookAtTopLevel)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (67)
src/services/charges.ts (1)
67-67
: LGTM! Clean API enhancement for payment tracking.The addition of the
payerAddress
parameter to track the payment source is well-implemented with consistent typing and proper inclusion in the request payload.Also applies to: 73-73, 84-84
src/hooks/usePaymentInitiator.ts (5)
86-86
: LGTM! Improved variable naming for clarity.The rename from
wagmiAddress
toexternalAccountAddress
better describes the variable's purpose and improves code readability.
498-498
: LGTM! Proper payer address tracking for Peanut Wallet payments.The addition of
payerAddress
usingpeanutWalletAddress
correctly tracks the payment source for Peanut Wallet transactions.
605-605
: LGTM! Proper payer address tracking for external wallet payments.The addition of
payerAddress
usingexternalAccountAddress
correctly tracks the payment source. The non-null assertion is safe here since external wallet connection is validated earlier in the flow.
672-672
: LGTM! Consistent variable usage after rename.The conditional check correctly uses the renamed
externalAccountAddress
variable, maintaining the same logic while improving naming consistency.
716-716
: LGTM! Correct dependency array update.The dependency array properly reflects the variable rename, ensuring the
useCallback
hook tracks the correct dependencies for proper React behavior.tailwind.config.js (1)
285-306
: LGTM! Typography enhancements look good.The new font sizes and extraBlack font weight (1000) are properly configured for prominent headings. However, these styling changes appear unrelated to the stated PR objective of making transaction history private.
Likely an incorrect or invalid review comment.
src/app/layout.tsx (2)
43-46
: Properly implemented local font addition.The robotoFlexBold font is correctly configured with appropriate CSS variable naming, following the established pattern of other local fonts in the file.
68-68
: Font variable correctly added to body className.The new font variable is properly included in the body element's className alongside existing font variables.
src/components/LandingPage/sendInSeconds.tsx (2)
9-9
: Good addition of reusable Button component import.Using a centralized Button component improves consistency and maintainability across the landing page components.
233-240
: Excellent refactoring to use reusable Button component.This change replaces custom-styled anchor elements with a consistent Button component, following DRY principles. The motion animations are properly preserved, and the updated text "TRY NOW!" adds appropriate emphasis.
src/components/LandingPage/yourMoney.tsx (2)
54-56
: Excellent replacement of image heading with accessible text.Converting from SVG image to styled text improves accessibility, SEO, and maintainability. The new typography classes are used appropriately.
71-72
: Good conversion of feature titles to styled text.Replacing SVG image titles with text elements follows the same accessibility and maintainability improvements as the main heading.
src/app/page.tsx (3)
37-37
: Consistent CTA text update.The exclamation mark addition maintains consistency with other landing page components.
53-69
: Excellent FAQ expansion with comprehensive security information.The expanded FAQ section addresses critical user concerns about security, KYC requirements, device theft protection, and fund safety. The technical details about cryptography and security measures are informative and build user trust.
179-179
: Good UX improvement with enable-select class.Adding the enable-select class improves user experience by allowing text selection where it may have been previously disabled.
src/components/LandingPage/businessIntegrate.tsx (4)
4-4
: LGTM: Clean import addition for Button component.The import is correctly added to support the button standardization changes below.
18-20
: Good refactor: SVG heading replaced with styled text.This change improves maintainability by removing dependency on SVG assets while maintaining the same visual impact through proper typography classes.
49-49
: Good addition: "ENTERPRISE" prefix enhances business messaging.The added prefix better positions the product for enterprise customers and aligns with the business integration theme.
58-63
: Excellent standardization: Button component improves consistency.The refactor from styled anchor to the reusable Button component with proper props (shadowSize, className) standardizes the UI across landing page components.
src/components/LandingPage/securityBuiltIn.tsx (5)
22-22
: Good title simplification: "BIOMETRIC AUTH" is more direct.The shortened title maintains clarity while being more concise and impactful.
24-25
: Excellent technical improvement: Enhanced biometric description.The updated description better explains the technical implementation using the phone's secure enclave, making the security benefit more concrete and understandable.
33-33
: Good simplification: Cleaner self-custodial messaging.The streamlined description focuses on the core benefit without redundant company branding, improving readability.
52-54
: Consistent refactor: SVG heading replaced with styled text.This change aligns with the broader landing page standardization effort, improving maintainability while preserving visual impact through proper typography.
74-75
: Good standardization: Text-based feature titles.The shift from SVG to text for feature titles improves consistency and reduces asset dependencies while maintaining proper styling.
src/components/LandingPage/hero.tsx (5)
8-8
: LGTM: Necessary import for Button standardization.The import addition supports the button component refactor below.
143-148
: Excellent standardization: Button component improves consistency.The refactor from custom styled anchor to the reusable Button component with proper shadow and styling props aligns with the broader landing page standardization effort.
157-157
: Good fix: Corrected viewport height unit.Changed from
min-h-[100dvh]
tomin-h-[100vh]
- thedvh
unit has limited browser support, sovh
is the safer choice for consistent rendering.
178-188
: Consistent refactor: SVG replaced with structured text heading.The replacement maintains the visual hierarchy while improving maintainability. The structured approach with separate heading and subtitle elements provides better semantic markup.
1-199
: Flag inconsistency: PR objectives don't match file changes.The PR objectives mention making transaction history private and restricting user access to transaction data, but these files contain landing page UI improvements (replacing SVG headings with text, standardizing buttons). This suggests either:
- Wrong files provided for review
- Incorrect PR objectives description
- Mixed PR with unrelated changes
Please verify that the correct files are being reviewed for the transaction history privacy changes described in the PR objectives.
Likely an incorrect or invalid review comment.
src/hooks/useTransactionHistory.ts (3)
84-84
: LGTM! Well-structured type definition.The optional
filterMutualTxs
parameter is properly added to both the base options type and the relevant function overload, maintaining backward compatibility.Also applies to: 92-92
111-111
: LGTM! Clear implementation with good documentation.The parameter is properly integrated with clear conditional logic and helpful comments explaining the mutual transaction filtering behavior.
Also applies to: 125-126
230-233
: LGTM! Proper cache key management.The conditional query key construction correctly ensures cache invalidation when switching between users during mutual transaction filtering. The explanatory comment is helpful.
src/interfaces/interfaces.ts (1)
313-313
: Approve exportedUser
interface for cross-component use – audit PII handlingThe export of
User
is required for the new guest flows and user management features, but this interface includes sensitive fields (KYC status/dates, email, full name, Bridge customer ID, etc.). Please review how it’s consumed and ensure any PII is appropriately sanitized, restricted, or omitted in guest contexts:• src/context/GuestFlowContext.tsx
• src/app/actions/users.tsVerify that neither network requests nor UI components unintentionally expose PII to unauthorized users.
src/app/(mobile-ui)/add-money/[country]/bank/page.tsx (1)
103-103
: Good simplification of the KYC flow logic.The change improves user flow consistency by always directing non-KYC verified users to collect their details, rather than making conditional decisions based on partial data. This ensures a more robust and predictable user experience.
src/app/(mobile-ui)/home/page.tsx (4)
38-38
: LGTM: Clean import additionThe PostSignupActionManager import is properly added and follows the existing import structure.
61-61
: LGTM: State variable properly initializedThe
isPostSignupActionModalVisible
state is correctly initialized and follows the naming convention of other modal states in the component.
107-113
: LGTM: Excellent modal coordination logicThe integration of the new modal state into existing conditional rendering logic properly prevents UI overlap between modals. This ensures a good user experience by showing only one modal at a time.
Also applies to: 136-137, 160-161
237-238
: LGTM: PostSignupActionManager properly integratedThe component is correctly placed and receives the visibility change handler to coordinate with other modals in the home page.
src/components/AddWithdraw/AddWithdrawCountriesList.tsx (3)
16-16
: LGTM: Improved type specificityReplacing the generic
FormData
import with the more specificIBankAccountDetails
interface improves type safety and provides clearer contracts for bank account data handling.
39-39
: LGTM: Consistent type usageThe cached bank details state properly uses the new
IBankAccountDetails
type, maintaining consistency with the updated interface.
81-84
: LGTM: Function signature aligned with new typesThe
handleFormSubmit
function signature correctly uses the newIBankAccountDetails
type for therawData
parameter, ensuring type consistency throughout the component.src/app/actions/offramp.ts (1)
73-111
: LGTM: Well-implemented guest access patternThe
createOfframpForGuest
function follows a clean pattern for providing unauthenticated access to offramp creation. Key strengths:
- Consistent error handling with the authenticated version
- Proper endpoint differentiation (
/bridge/offramp/create-for-guest
)- Maintains the same return type contract
- Removes authentication while preserving API key security
The implementation correctly mirrors the authenticated
createOfframp
function while adapting for guest usage.src/components/GuestActions/MethodList.tsx (3)
60-69
: LGTM: Enhanced component interface and state managementThe component properly accepts
claimLinkData
and integrates well with the guest flow context. The addition of error state for minimum amount validation shows good UX consideration.
71-100
: LGTM: Robust validation and flow logicThe enhanced
handleMethodClick
function includes excellent validation:
- Proper minimum amount checking ($1 USD for bank claims)
- KYC status validation with async user fetching
- Clear flow progression based on user state
- Appropriate fallback to verification modal when needed
The async logic for checking sender details and KYC status is well-implemented.
111-121
: LGTM: User-friendly error handlingThe ActionModal provides clear feedback for minimum amount requirements with appropriate styling and messaging. The modal prevents user confusion about why bank claims might not be available.
src/components/Claim/Link/views/ClaimCountryList.view.tsx (4)
19-24
: LGTM: Well-defined country support logicThe supported countries logic clearly defines SEPA countries plus US and Mexico, with proper filtering from the country data. The use of Set for efficient lookups is a good optimization.
26-34
: LGTM: Efficient search implementationThe search functionality is well-implemented with:
- Proper use of
useMemo
for performance optimization- Case-insensitive search across both country name and currency
- Clean dependency management in the memoization
82-94
: LGTM: Robust image handlingThe country flag image implementation includes proper error handling with the
onError
callback to hide failed images. Using the CDN flag service with proper alt text and responsive sizing is a good approach.
63-69
: LGTM: User-friendly empty stateThe empty state handling for search results provides clear feedback to users when no countries match their search criteria, improving the overall user experience.
src/context/GuestFlowContext.tsx (3)
1-101
: Inconsistency between PR objectives and actual changes.The PR objectives state this is about "Make txn history private" to restrict transaction history visibility, but this file is implementing guest flow context extensions for bank claim functionality. This appears to be an inconsistent AI summary.
Likely an incorrect or invalid review comment.
13-27
: LGTM: Well-structured context interface extensions.The new state variables are properly typed and logically organized for managing guest bank claim flows.
77-89
: LGTM: Proper useMemo dependency management.All new state variables are correctly included in the dependency array to ensure proper memoization.
src/components/Claim/Link/Onchain/Success.view.tsx (3)
6-141
: Inconsistency between PR objectives and actual changes.Like the previous file, this component is implementing bank claim functionality rather than transaction history privacy controls as stated in the PR objectives.
Likely an incorrect or invalid review comment.
82-100
: LGTM: Well-structured conditional card props.The dynamic card props logic properly handles the distinction between bank claims and regular claims, with appropriate formatting for amounts and recipient information.
102-122
: LGTM: Clean button rendering logic.The renderButtons function properly separates concerns and handles different user states appropriately.
src/components/AddWithdraw/DynamicBankAccountForm.tsx (3)
1-318
: Inconsistency between PR objectives and actual changes.This file implements bank account form enhancements rather than transaction history privacy controls as stated in the PR objectives.
Likely an incorrect or invalid review comment.
21-36
: LGTM: Well-structured type definition.The IBankAccountDetails type is properly extended with optional and required fields to support both claim and withdraw flows.
210-224
: LGTM: Clean conditional rendering for different flows.The form appropriately renders different input fields based on the flow type and user data availability.
src/components/Claim/Link/Initial.view.tsx (3)
55-76
: Good refactoring to use a single props objectThe change from destructured parameters to a single
IClaimScreenProps
object improves maintainability and makes it easier to pass props through to child components likeBankFlowManager
.
736-765
: Well-structured verification modal for KYC requirementsThe modal clearly communicates the verification requirements for bank claims and provides appropriate user actions.
461-465
: Verify Token Reset on Bank Flow Step EntryConfirm that resetting
selectedToken
insrc/components/Claim/Link/Initial.view.tsx
when entering bank-related flow steps doesn’t inadvertently clear the user’s choice if they navigate back and forth. Key spots:
- Line 232:
if (isPeanutWallet) resetSelectedToken()- Lines 461–465:
useEffect(() => { if (guestFlowStep?.startsWith('bank-')) { resetSelectedToken() } }, [guestFlowStep, resetSelectedToken])Ensure you only reset on the user’s first entry into those steps (or explicitly intend to clear on every revisit).
src/components/Global/PeanutActionDetailsCard/index.tsx (2)
93-99
: Clear and appropriate messaging for bank claimsThe conditional title text correctly distinguishes between pending ("You're about to receive") and completed ("You will receive") bank claims, providing clear user feedback.
198-213
: Consistent currency display for bank claimsThe logic correctly displays dollar signs for bank claims in success view, maintaining consistency with the PEANUT_WALLET_TOKEN_SYMBOL behavior.
src/services/services.types.ts (3)
276-296
: Comprehensive enhancement of off-ramp request typesThe addition of optional fields like
userId
,sendLinkPubKey
, and payment rail references provides good flexibility for various off-ramp scenarios. Thefeatures.allowAnyFromAddress
flag is particularly useful for guest flows.
305-324
: Well-structured quote object for financial transparencyThe detailed quote breakdown with fees, exchange rates, and transaction hashes provides excellent transparency for off-ramp operations.
276-324
: Verify alignment with PR objectivesThese type changes enhance off-ramp functionality for bank claims, but the PR objectives state this is about "making transaction history private." Please clarify how these changes relate to restricting transaction history visibility for guest users and limiting logged-in users to mutual transactions only.
What is the relationship between off-ramp functionality and transaction history privacy in financial applications?
Likely an incorrect or invalid review comment.
export async function getUserById(userId: string): Promise<User | null> { | ||
try { | ||
const response = await fetchWithSentry(`${PEANUT_API_URL}/users/${userId}`, { | ||
method: 'GET', | ||
headers: { | ||
'Content-Type': 'application/json', | ||
'api-key': API_KEY, | ||
}, | ||
}) | ||
|
||
if (!response.ok) { | ||
const errorData = await response.json() | ||
console.error(`Failed to fetch user ${userId}:`, errorData) | ||
return null | ||
} | ||
const responseJson = await response.json() | ||
console.log('response kushhh', responseJson) | ||
|
||
return responseJson | ||
} catch (error) { | ||
console.error(`Error fetching user ${userId}:`, error) | ||
return null | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Verify API endpoint security for unauthenticated user data access.
This function fetches user data without authentication tokens, which raises security concerns since the User
interface contains sensitive PII (KYC status, email, full name, bridge customer ID, etc.).
Ensure the API endpoint /users/${userId}
properly restricts the data returned for unauthenticated requests and doesn't expose sensitive information that could be used maliciously.
🌐 Web query:
What are the security best practices for API endpoints that return user data without authentication? Should PII data be restricted in such cases?
💡 Result:
API endpoints that return user data without authentication are a serious security risk and must never expose Personally Identifiable Information (PII) or any sensitive data; such endpoints should be heavily restricted or avoided entirely. Exposure of PII through unauthenticated APIs is a critical vulnerability that can lead to data breaches, regulatory violations, and reputational damage[2][3][5][8][10].
Security Best Practices for Unauthenticated API Endpoints
- Do not return PII or sensitive user data on unauthenticated endpoints: Best practice is to restrict PII (names, addresses, emails, phone numbers, IDs, etc.) to authenticated and authorized sessions only. If authentication is not enforced, any data returned should be explicitly reviewed to ensure no PII or confidential information is exposed[2][3][5][6][8][10].
- Minimize data exposure: The principle of least privilege dictates that you return only what is strictly necessary—often just non-sensitive, public, or aggregated data. Overexposure, such as returning entire user objects or internal fields, is a common flaw and a source of data leakage[3][5][7].
- Implement field whitelisting: Explicitly define which fields are allowed in responses from any unauthenticated endpoint, using response schemas or DTOs to avoid accidental data exposure[3][7].
- Audit and review endpoint responses: Regularly test and audit all public endpoints to verify they do not expose sensitive data. Use automated scanning tools and manual code reviews to detect overexposed fields[2][3][5][8].
- Encrypt even non-authenticated traffic: Always use HTTPS to protect data in transit and reduce risk from eavesdropping, even if data is not currently “sensitive”[1][7][9].
- Rate limit and monitor unauthenticated endpoints: To prevent abuse (e.g., enumeration, scraping), apply strict rate limiting and logging[1][7][9].
- Never embed internal or debug data in responses: Remove or mask system info, database IDs, or debugging traces, which can deepen exposure[3].
- Use randomized references, not predictable IDs: If objects must be referenced, avoid exposing predictable patterns or numeric IDs, which are easy to enumerate[6].
Should PII Data Be Restricted?
Yes—PII must be strictly restricted from unauthenticated API endpoints. Exposing PII without authentication is considered a severe security flaw and violates regulatory frameworks (e.g., GDPR, CCPA)[2][3][5][8][10]. OWASP, regulatory guidelines, and industry best practices all mandate that PII is only accessible through authenticated and authorized sessions, with object-level authorization to ensure only intended users access their own data[2][3][5][6][8][10].
Risks and Consequences
- Data breaches: Attackers can harvest all user data, leading to regulatory fines, customer loss, and lawsuits[2][8][10].
- Automated scraping and enumeration: Public endpoints can be exploited at scale, leaking large datasets rapidly[6][10].
- Regulatory non-compliance: Unauthorized PII exposure can trigger investigations and fines under privacy laws[2][3][5].
Important Caveats
- If you cannot ensure authentication, all potentially sensitive fields (including PII, user-specific metadata, and business logic) must be excluded.
- Even “non-sensitive” data may become sensitive in context or when aggregated.
- Security by obscurity (e.g., randomizing object IDs) is insufficient—proper access controls are mandatory[6].
In summary: Never return PII or sensitive user data from unauthenticated API endpoints. Strictly review, limit, and monitor data exposure, and implement robust authentication and authorization for any user-specific data and all PII[2][3][5][6][8][10].
Citations:
- 1: https://entro.security/blog/api-security-and-protection-best-practices/
- 2: https://www.trendmicro.com/vinfo/us/security/news/online-privacy/pii-leaks-and-other-risks-from-unsecure-e-commerce-apis
- 3: https://workos.com/blog/secure-api-best-practices
- 4: https://curity.io/resources/learn/api-security-best-practices/
- 5: https://cybelangel.com/api-security-data-exposure-8-principles/
- 6: https://qwiet.ai/api-security-101/
- 7: https://www.wiz.io/academy/api-security-best-practices
- 8: https://www.acunetix.com/vulnerabilities/web/api-sensitive-info-pii-accessible-without-authentication/
- 9: https://konghq.com/blog/engineering/api-security-best-practices
- 10: https://www.practical-devsecops.com/api-without-authentication/
Ensure PII Is Never Exposed by Unauthenticated /users/:userId
Calls
This helper function in src/app/actions/users.ts (getUserById) invokes ${PEANUT_API_URL}/users/${userId}
using only an API key—no user‐scoped authentication—so we must verify that no sensitive PII is returned to unauthorized clients. Exposing PII (email, full name, KYC status, etc.) on a public or API‐key‐only endpoint is a critical security risk.
Please confirm and, if needed, implement the following safeguards:
- Verify that the
/users/:userId
endpoint enforces proper authentication and object‐level authorization, returning data only for the requesting user. - Restrict or whitelist response fields so that unauthenticated or API‐key–only requests expose only non-sensitive, public data.
- Audit and sanitize the endpoint’s response schema to remove any internal IDs, debug info, or additional metadata.
- Ensure all calls use HTTPS, apply rate limiting, and monitor for enumeration or scraping attempts.
- Incorporate regular security reviews or automated scans to detect any accidental PII exposure.
🤖 Prompt for AI Agents
In src/app/actions/users.ts from lines 99 to 122, the getUserById function calls
the /users/:userId endpoint with only an API key, risking exposure of sensitive
PII. To fix this, first verify that the backend endpoint enforces user-scoped
authentication and object-level authorization so only authorized users can
access their own data. Then, restrict the response to include only non-sensitive
public fields by whitelisting allowed properties and sanitizing the response to
remove internal IDs or metadata. Ensure the fetch URL uses HTTPS, and confirm
rate limiting and monitoring are in place on the API server to prevent
enumeration or scraping. Finally, establish regular security audits or automated
scans to detect any accidental PII exposure in responses.
if (!claimLinkData.sender?.userId) return { error: 'Sender details not found' } | ||
setLoadingState('Executing transaction') | ||
setError(null) | ||
const userResponse = await getUserById(claimLinkData.sender?.userId ?? claimLinkData.senderAddress) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Verify the fallback logic for getUserById
The code falls back to claimLinkData.senderAddress
when sender.userId
is not available. Ensure that getUserById
can handle both user IDs and addresses, or this might cause unexpected behavior.
🏁 Script executed:
#!/bin/bash
# Description: Check how getUserById is implemented and if it handles addresses
# Search for the getUserById function implementation
ast-grep --pattern 'export $_ function getUserById($_) {
$$$
}'
# Also check for any async version
ast-grep --pattern 'export async function getUserById($_) {
$$$
}'
# Look for the function signature in the users.ts file
rg -A 10 "getUserById" src/app/actions/users.ts
Length of output: 549
Fix the fallback logic for getUserById
The getUserById
helper only accepts a user‐ID string. Falling back to an arbitrary senderAddress
will make the API call hit /users/<address>
and return 404s or nulls. Please update the code to either:
- Always require
sender.userId
(and surface an error if it’s missing) - Or introduce/consume a dedicated “lookup by address” function when
userId
is unavailable
Locations needing updates:
- File: src/components/Claim/Link/views/BankFlowManager.view.tsx
- Line 45
Suggested diff:
- const userResponse = await getUserById(
- claimLinkData.sender?.userId ?? claimLinkData.senderAddress
- )
+ // Use a separate address‐based lookup if userId is not provided
+ let userResponse: User | null
+ if (claimLinkData.sender?.userId) {
+ userResponse = await getUserById(claimLinkData.sender.userId)
+ } else {
+ // TODO: replace with actual address‐lookup function or error handling
+ userResponse = await getUserByAddress(claimLinkData.senderAddress)
+ }
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In src/components/Claim/Link/views/BankFlowManager.view.tsx at line 45, the
fallback logic for getUserById incorrectly uses senderAddress when userId is
missing, causing invalid API calls. Fix this by either enforcing that
sender.userId must be present and throwing an error if not, or by replacing the
fallback with a call to a proper lookup function that accepts senderAddress.
Update the code to avoid passing senderAddress to getUserById and handle missing
userId cases explicitly.
features: { | ||
allowAnyFromAddress: true, | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Verify security implications of allowAnyFromAddress
The allowAnyFromAddress
feature is set to true
, which might have security implications. Ensure this is intentional and doesn't bypass important validation checks in the offramp service.
🌐 Web query:
What does the allowAnyFromAddress feature do in Bridge API and what are its security implications?
💡 Result:
The allowAnyFromAddress feature in a Bridge API typically modifies how the API authenticates or restricts the origins of incoming requests, specifically relaxing constraints on which "from" addresses are permitted to initiate actions or transactions. However, there is no direct mention or official documentation of an allowAnyFromAddress feature in the provided search results for the publicly documented Bridge APIs[1][2][6][7][10]. Therefore, this answer is based on analysis grounded in general API security practices and the standard meaning of such a flag in API and messaging contexts.
What does allowAnyFromAddress do?
- In systems with messaging, email, or transactional APIs, an allowAnyFromAddress configuration typically means that the API will process requests from any "from" address, without whitelisting or verification.
- This enables greater flexibility during integration or testing since requests or payloads can originate from multiple sources or identities.
Security Implications
- Weakened Sender Authentication: By enabling requests or messages from any "from" address, the system disables a key verification step. Normally, only certain verified addresses are permitted to send requests (to prevent spoofing or unauthorized sending).
- Increased Risk of Spoofing and Abuse: Attackers could impersonate trusted entities by supplying forged "from" addresses, potentially tricking the system or downstream recipients into accepting malicious content or actions. This is analogous to “email spoofing” or “header spoofing” in transactional systems.
- Audit Trail Obfuscation: Tracking the origin of requests becomes unreliable. Accountability, logging, and forensics become harder if the "from" address cannot be trusted.
- Potential Bypass of Access Controls: If other access controls rely on the "from" address (for routing, permissions, or validations), this setting could allow users to bypass intended restrictions.
Best Practices and Context
- Such features should only be enabled in controlled environments such as development or testing, never in production systems[8][9].
- Security best practices dictate to restrict allowed source addresses and to implement strong authentication (such as API keys or OAuth tokens)[5][8].
- Make Bridge and other APIs stress the use of strong authentication and TLS for all communications and recommend strict control of API secrets and permission scopes[5][7][8].
Caveats
- If you are using a proprietary or less public implementation of Bridge API with an option called allowAnyFromAddress, consult the specific vendor’s documentation or support channel, as actual behaviors may vary.
Summary Table – Risks of allowAnyFromAddress
Security Aspect | With allowAnyFromAddress: Enabled | With allowAnyFromAddress: Disabled (default) |
---|---|---|
Sender Verification | Bypassed | Enforced - Only verified/approved senders allowed |
Risk of Spoofing | High | Low |
Audit Trail Integrity | Unreliable | Reliable |
Recommendations | Disabled unless under controlled testing | Default for production and most secure configs |
In summary: allowAnyFromAddress allows requests from any sender, undermining sender authentication and increasing the risk of spoofing and security breaches. This flag should generally not be used in production environments due to significant security implications, and standard security controls (authentication and origin restrictions) are strongly recommended[5][8][9].
Citations:
- 1: https://help-bridge.solocal.com/hc/en-us/articles/11272352319644-API-How-does-it-work
- 2: https://docs.bridgeapi.io/v2021.06.01/docs/basics
- 3: https://lobehub.com/mcp/inquirelab-mcp-bridge-api
- 4: https://docs.oracle.com/javase/9/access/jaapi.htm
- 5: https://support.rapidinsight.eab.com/hc/en-us/articles/5594943662743-Bridge-Security-and-Privacy
- 6: https://www.bridgeinteractive.com/mls/bridge-api/
- 7: https://www.postman.com/bridgeapi/bridge-api/documentation/l2ihsuk/bridge-api?entity=folder-8318256-29ea9712-d687-4e21-94db-4597f6042aee
- 8: https://developers.make.com/bridge-documentation/get-started/integrate-make-bridge/make-bridge-api-method-preferred
- 9: https://www.youtube.com/watch?v=6WZ6S-qmtqY
- 10: https://community.bridgeapp.com/hc/en-us/articles/360054637574-How-to-use-the-Bridge-API
Review security implications of allowAnyFromAddress
The allowAnyFromAddress: true
setting in BankFlowManager.view.tsx effectively disables sender‐address validation, which can lead to:
- Weakened sender authentication
- Increased risk of spoofed or malicious transactions
- Unreliable audit trails and potential access-control bypass
This flag should only be enabled in tightly controlled (e.g., dev or testing) environments. Before merging, please:
• Confirm that relaxing the “from” address restriction is intentional and documented.
• Restrict or disable allowAnyFromAddress
in production builds.
• If genuine flexibility is needed, consider adding explicit allowlists or stronger authentication checks upstream.
File: src/components/Claim/Link/views/BankFlowManager.view.tsx
Lines: 124–126
- features: {
- allowAnyFromAddress: true,
- },
+ // ⚠️ Review/remove for production:
+ features: {
+ allowAnyFromAddress: true,
+ },
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
features: { | |
allowAnyFromAddress: true, | |
}, | |
// ⚠️ Review/remove for production: | |
features: { | |
allowAnyFromAddress: true, | |
}, |
🤖 Prompt for AI Agents
In src/components/Claim/Link/views/BankFlowManager.view.tsx around lines 124 to
126, the allowAnyFromAddress flag is set to true, disabling sender-address
validation and posing security risks. To fix this, ensure this flag is only
enabled in non-production environments by adding environment checks to
conditionally set allowAnyFromAddress to true for dev or testing and false for
production. Additionally, document this behavior clearly and consider
implementing allowlists or stronger authentication upstream if flexibility is
required.
const accountType = useMemo(() => { | ||
if (bankDetails.iban) return AccountType.IBAN | ||
if (bankDetails.clabe) return AccountType.CLABE | ||
if (bankDetails.accountNumber && bankDetails.routingNumber) return AccountType.US | ||
return AccountType.IBAN // Default or handle error | ||
}, [bankDetails]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Consider explicit error handling for unknown account types
The default return of AccountType.IBAN
when no conditions match could lead to incorrect account type classification. Consider throwing an error or returning a specific "UNKNOWN" type instead.
const accountType = useMemo(() => {
if (bankDetails.iban) return AccountType.IBAN
if (bankDetails.clabe) return AccountType.CLABE
if (bankDetails.accountNumber && bankDetails.routingNumber) return AccountType.US
- return AccountType.IBAN // Default or handle error
+ // This should not happen with valid bank details
+ console.error('Unable to determine account type from bank details:', bankDetails)
+ return AccountType.IBAN // Fallback to IBAN, but log the issue
}, [bankDetails])
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const accountType = useMemo(() => { | |
if (bankDetails.iban) return AccountType.IBAN | |
if (bankDetails.clabe) return AccountType.CLABE | |
if (bankDetails.accountNumber && bankDetails.routingNumber) return AccountType.US | |
return AccountType.IBAN // Default or handle error | |
}, [bankDetails]) | |
const accountType = useMemo(() => { | |
if (bankDetails.iban) return AccountType.IBAN | |
if (bankDetails.clabe) return AccountType.CLABE | |
if (bankDetails.accountNumber && bankDetails.routingNumber) return AccountType.US | |
// This should not happen with valid bank details | |
console.error('Unable to determine account type from bank details:', bankDetails) | |
return AccountType.IBAN // Fallback to IBAN, but log the issue | |
}, [bankDetails]) |
🤖 Prompt for AI Agents
In src/components/Claim/Link/views/Confirm.bank-claim.view.tsx around lines 44
to 49, the useMemo hook defaults to returning AccountType.IBAN when no
bankDetails conditions match, which may misclassify unknown account types.
Modify the code to either throw an explicit error or return a distinct "UNKNOWN"
account type value instead of defaulting to IBAN, ensuring clearer handling of
unexpected or missing bank details.
{bankDetails.iban && <PaymentInfoRow label="IBAN" value={bankDetails.iban} />} | ||
{bankDetails.bic && <PaymentInfoRow label="BIC" value={bankDetails.bic} />} | ||
<ExchangeRate accountType={accountType} /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add support for displaying other account types
The component only displays IBAN and BIC fields but doesn't show CLABE or US account details (account number and routing number) even though these account types are supported in the accountType
logic.
{bankDetails.iban && <PaymentInfoRow label="IBAN" value={bankDetails.iban} />}
{bankDetails.bic && <PaymentInfoRow label="BIC" value={bankDetails.bic} />}
+ {bankDetails.clabe && <PaymentInfoRow label="CLABE" value={bankDetails.clabe} />}
+ {bankDetails.accountNumber && <PaymentInfoRow label="Account Number" value={bankDetails.accountNumber} />}
+ {bankDetails.routingNumber && <PaymentInfoRow label="Routing Number" value={bankDetails.routingNumber} />}
<ExchangeRate accountType={accountType} />
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
{bankDetails.iban && <PaymentInfoRow label="IBAN" value={bankDetails.iban} />} | |
{bankDetails.bic && <PaymentInfoRow label="BIC" value={bankDetails.bic} />} | |
<ExchangeRate accountType={accountType} /> | |
{bankDetails.iban && <PaymentInfoRow label="IBAN" value={bankDetails.iban} />} | |
{bankDetails.bic && <PaymentInfoRow label="BIC" value={bankDetails.bic} />} | |
{bankDetails.clabe && <PaymentInfoRow label="CLABE" value={bankDetails.clabe} />} | |
{bankDetails.accountNumber && <PaymentInfoRow label="Account Number" value={bankDetails.accountNumber} />} | |
{bankDetails.routingNumber && <PaymentInfoRow label="Routing Number" value={bankDetails.routingNumber} />} | |
<ExchangeRate accountType={accountType} /> |
🤖 Prompt for AI Agents
In src/components/Claim/Link/views/Confirm.bank-claim.view.tsx around lines 74
to 76, the component only renders IBAN and BIC fields but does not handle other
supported account types like CLABE or US accounts. Update the JSX to
conditionally render additional PaymentInfoRow components for CLABE, and for US
accounts, display account number and routing number based on the accountType and
available bankDetails properties.
useEffect(() => { | ||
const redirectUrl = getFromLocalStorage('redirect') | ||
if (redirectUrl) { | ||
const matchedAction = POST_SIGNUP_ACTIONS.find((action) => action.pathPattern.test(redirectUrl)) | ||
|
||
if (matchedAction) { | ||
setActionConfig({ | ||
...matchedAction.config, | ||
action: () => { | ||
router.push(redirectUrl) | ||
localStorage.removeItem('redirect') | ||
setShowModal(false) | ||
}, | ||
}) | ||
setShowModal(true) | ||
} | ||
} | ||
}, []) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add URL validation and error handling for security.
The component should validate redirect URLs before navigation to prevent potential security issues like open redirects.
useEffect(() => {
- const redirectUrl = getFromLocalStorage('redirect')
- if (redirectUrl) {
+ try {
+ const redirectUrl = getFromLocalStorage('redirect')
+ if (redirectUrl) {
+ // Validate that the redirect URL is safe (internal to the app)
+ const url = new URL(redirectUrl, window.location.origin)
+ if (url.origin !== window.location.origin) {
+ console.warn('Invalid redirect URL detected:', redirectUrl)
+ localStorage.removeItem('redirect')
+ return
+ }
+
const matchedAction = POST_SIGNUP_ACTIONS.find((action) => action.pathPattern.test(redirectUrl))
if (matchedAction) {
setActionConfig({
...matchedAction.config,
action: () => {
router.push(redirectUrl)
localStorage.removeItem('redirect')
setShowModal(false)
},
})
setShowModal(true)
}
- }
+ }
+ } catch (error) {
+ console.error('Error processing redirect URL:', error)
+ localStorage.removeItem('redirect')
+ }
}, [])
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
useEffect(() => { | |
const redirectUrl = getFromLocalStorage('redirect') | |
if (redirectUrl) { | |
const matchedAction = POST_SIGNUP_ACTIONS.find((action) => action.pathPattern.test(redirectUrl)) | |
if (matchedAction) { | |
setActionConfig({ | |
...matchedAction.config, | |
action: () => { | |
router.push(redirectUrl) | |
localStorage.removeItem('redirect') | |
setShowModal(false) | |
}, | |
}) | |
setShowModal(true) | |
} | |
} | |
}, []) | |
useEffect(() => { | |
try { | |
const redirectUrl = getFromLocalStorage('redirect') | |
if (redirectUrl) { | |
// Validate that the redirect URL is safe (internal to the app) | |
const url = new URL(redirectUrl, window.location.origin) | |
if (url.origin !== window.location.origin) { | |
console.warn('Invalid redirect URL detected:', redirectUrl) | |
localStorage.removeItem('redirect') | |
return | |
} | |
const matchedAction = POST_SIGNUP_ACTIONS.find((action) => | |
action.pathPattern.test(redirectUrl) | |
) | |
if (matchedAction) { | |
setActionConfig({ | |
...matchedAction.config, | |
action: () => { | |
router.push(redirectUrl) | |
localStorage.removeItem('redirect') | |
setShowModal(false) | |
}, | |
}) | |
setShowModal(true) | |
} | |
} | |
} catch (error) { | |
console.error('Error processing redirect URL:', error) | |
localStorage.removeItem('redirect') | |
} | |
}, []) |
🤖 Prompt for AI Agents
In src/components/Global/PostSignupActionManager/index.tsx around lines 25 to
42, the redirectUrl from localStorage is used directly without validation, which
can lead to open redirect vulnerabilities. Add validation to ensure redirectUrl
is a safe and allowed URL before using it for navigation. If the URL is invalid,
avoid setting the action or redirecting, and optionally handle the error
gracefully to prevent security risks.
if (mode === 'latest') { | ||
// if filterMutualTxs is true, we need to add the username to the query key to invalidate the query when the username changes | ||
const queryKeyTxn = TRANSACTIONS + (filterMutualTxs ? username : '') | ||
return useQuery({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Verify the static analysis hook ordering concern.
The static analyzer flags this as conditional hook calling, but this appears to be a false positive since the function overloads should ensure the mode is statically determined. Let me verify the hook usage patterns.
🏁 Script executed:
#!/bin/bash
# Description: Check how useTransactionHistory is called to verify if mode can change dynamically
# Expected: Mode should be statically determined, making this a false positive
echo "=== Searching for useTransactionHistory usage patterns ==="
rg -A 3 -B 1 "useTransactionHistory\(" --type ts --type tsx
echo -e "\n=== Checking for dynamic mode usage ==="
rg "mode.*=.*\?" --type ts --type tsx | head -10
Length of output: 390
🏁 Script executed:
#!/bin/bash
# Locate the hook file
echo "=== Locating useTransactionHistory.ts ==="
HOOK_FILE=$(fd -t f useTransactionHistory.ts)
echo "Found: $HOOK_FILE"
echo -e "\n=== Inspecting overloads in $HOOK_FILE ==="
sed -n '1,200p' "$HOOK_FILE" | grep -E '^export function useTransactionHistory' -n -B1 -A3 || true
echo -e "\n=== Searching for hook usage across the codebase ==="
rg "useTransactionHistory\(" -n -g "*.ts" -g "*.tsx" || true
echo -e "\n=== Checking for dynamic mode usage patterns ==="
rg "useTransactionHistory.*mode\s*=\s*[^,'\"]" -n -g "*.ts" -g "*.tsx" | head -10 || true
Length of output: 1861
Refactor hook calls in useTransactionHistory to satisfy the Rule of Hooks
The mode
value can be passed dynamically (e.g. in HomeHistory.tsx you’re passing a mode
variable), so the static analyzer is correctly warning that you’re conditionally calling useQuery
/useInfiniteQuery
. To fix this, invoke all three hooks in the same order on every render and gate them with enabled
flags, then return the appropriate result:
Locations to update:
- src/hooks/useTransactionHistory.ts (around lines 230–240)
Proposed diff:
- if (mode === 'latest') {
- return useQuery({
- queryKey: ['transactions', 'latest', address],
- queryFn: fetchLatestTransactions,
- enabled,
- })
- }
-
- if (mode === 'public') {
- return useQuery({
- queryKey: ['transactions', 'public', address],
- queryFn: fetchPublicTransactions,
- enabled,
- })
- }
-
- return useInfiniteQuery({
- queryKey: ['transactions', 'infinite', address],
- queryFn: fetchPagedTransactions,
- getNextPageParam: ({ nextCursor }) => nextCursor,
- enabled,
- })
+ const latestQuery = useQuery({
+ queryKey: ['transactions', 'latest', address],
+ queryFn: fetchLatestTransactions,
+ enabled: mode === 'latest' && enabled,
+ })
+ const publicQuery = useQuery({
+ queryKey: ['transactions', 'public', address],
+ queryFn: fetchPublicTransactions,
+ enabled: mode === 'public' && enabled,
+ })
+ const infiniteQuery = useInfiniteQuery({
+ queryKey: ['transactions', 'infinite', address],
+ queryFn: fetchPagedTransactions,
+ getNextPageParam: ({ nextCursor }) => nextCursor,
+ enabled: mode === 'infinite' && enabled,
+ })
+
+ if (mode === 'latest') return latestQuery
+ if (mode === 'public') return publicQuery
+ return infiniteQuery
This ensures hooks are always called in the same order, with only their results gated by mode
.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
return useQuery({ | |
const latestQuery = useQuery({ | |
queryKey: ['transactions', 'latest', address], | |
queryFn: fetchLatestTransactions, | |
enabled: mode === 'latest' && enabled, | |
}) | |
const publicQuery = useQuery({ | |
queryKey: ['transactions', 'public', address], | |
queryFn: fetchPublicTransactions, | |
enabled: mode === 'public' && enabled, | |
}) | |
const infiniteQuery = useInfiniteQuery({ | |
queryKey: ['transactions', 'infinite', address], | |
queryFn: fetchPagedTransactions, | |
getNextPageParam: ({ nextCursor }) => nextCursor, | |
enabled: mode === 'infinite' && enabled, | |
}) | |
if (mode === 'latest') return latestQuery | |
if (mode === 'public') return publicQuery | |
return infiniteQuery |
🧰 Tools
🪛 Biome (2.1.2)
[error] 232-232: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.
For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level
(lint/correctness/useHookAtTopLevel)
🤖 Prompt for AI Agents
In src/hooks/useTransactionHistory.ts around lines 230 to 240, the useQuery and
useInfiniteQuery hooks are being called conditionally based on the dynamic mode
value, violating the Rule of Hooks. To fix this, call all three hooks
unconditionally in the same order on every render, but use the enabled option to
gate their execution based on the mode. Then return the result corresponding to
the current mode. This ensures hooks are always called consistently while only
their results are conditionally used.
Closed in favour of #1017 |
CHANGES
Contributes to TASK-13200
NOTE: MERGE ONLY AFTER the backend PR for this task is merged