Skip to content

Conversation

jjramirezn
Copy link
Contributor

Use coral through squid to get the cross-chain route for the different
flows. This enables xchain withdraw for peanut wallet

contributes to TASK-11580

Use coral through squid to get the cross-chain route for the different
flows. This enables xchain withdraw for peanut wallet
Copy link

vercel bot commented Jun 18, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
peanut-ui ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jul 1, 2025 5:35pm
peanut-wallet ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jul 1, 2025 5:35pm

Copy link
Contributor

coderabbitai bot commented Jun 18, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

This update introduces cross-chain route expiry timers, approval transaction handling, and enhanced fee and error management for both payment and withdrawal flows. It adds new UI components for route expiry, updates the swap service to handle ERC-20 approvals, and refactors hooks and views to support minimum received amounts, cross-chain awareness, and improved transaction preparation logic.

Changes

Files / Areas Changed Summary
src/app/(mobile-ui)/withdraw/crypto/page.tsx Adds wallet connection detection, cross-chain withdrawal logic, route error handling, fee display, route refresh, and reset.
src/app/[...recipient]/client.tsx Renames prop from isDirectPay to isDirectUsdPayment passed to payment views.
src/app/actions/tokens.ts Adds stablecoin detection, exports estimateTransactionCostUsd for transaction cost estimation.
src/app/actions/clients.ts Removes Next.js caching from getPublicClient, now always executes fully.
src/components/Global/PeanutActionDetailsCard/index.tsx Adds optional cross-chain timer props and renders RouteExpiryTimer when enabled.
src/components/Global/RouteExpiryTimer/index.tsx New component: countdown timer for route expiry with callbacks and progress bar.
src/components/Payment/Views/Confirm.payment.view.tsx Adds isDirectUsdPayment prop, cross-chain route expiry/timer logic, min received display, improved fee and error handling.
src/components/Withdraw/views/Confirm.withdraw.view.tsx Adds cross-chain timer props, route expiry/timer logic, min received display, error retry refresh, adjusts button states.
src/components/Withdraw/views/Initial.withdraw.view.tsx Adds TokenSelector to UI, hardcodes token symbol to "USDC".
src/hooks/usePaymentInitiator.ts Removes gas fee estimation, refactors for new swap service with approval logic, updates function signatures and state.
src/services/swap.ts Adds ERC-20 approval logic, approval cost estimation, refines route search, updates route response with approval data.
src/services/services.types.ts Makes currencyCode and currencyAmount required in TRequestChargeResponse.
src/utils/index.ts Re-exports all from token.utils.
tailwind.config.js Adds new pulse-strong keyframe animation and corresponding animation utility.
src/components/Payment/PaymentForm/index.tsx Renames prop from isDirectPay to isDirectUsdPayment throughout component and types.
src/components/Payment/Views/Initial.payment.view.tsx Updates prop passed to PaymentForm from isDirectPay to isDirectUsdPayment.

Possibly related PRs


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 19aab4e and 90d6233.

📒 Files selected for processing (5)
  • src/app/[...recipient]/client.tsx (2 hunks)
  • src/app/actions/tokens.ts (3 hunks)
  • src/components/Payment/PaymentForm/index.tsx (5 hunks)
  • src/components/Payment/Views/Confirm.payment.view.tsx (12 hunks)
  • src/components/Payment/Views/Initial.payment.view.tsx (1 hunks)
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate Unit Tests
  • Create PR with Unit Tests
  • Post Copyable Unit Tests in a Comment
  • Commit Unit Tests in branch feat/cross-chain-action-card

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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need 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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai auto-generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

Copy link

@coderabbitai coderabbitai bot added the enhancement New feature or request label Jun 18, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (2)
src/components/Global/RouteExpiryTimer/index.tsx (1)

117-125: Consider making the total duration configurable.

The progress calculation assumes a fixed 1-minute duration, but route expiry times might vary. Consider making this configurable or calculating it dynamically.

+ const totalDurationMs = expiry ? (parseInt(expiry) * 1000) - (new Date().getTime() - timeRemaining.totalMs) : 60000
- const totalDurationMs = 1 * 60 * 1000 // 1 minutes

Or add it as a prop:

interface RouteExpiryTimerProps {
    expiry?: string
+   totalDurationMs?: number // Allow customization of total duration
    // ... other props
}
src/hooks/usePaymentInitiator.ts (1)

221-225: Remove commented code or document the transition plan.

The commented-out validation code suggests this refactor is incomplete. Either remove the commented code if it's no longer needed, or document when it will be cleaned up.

-                    /*
-                    if (!txData?.unsignedTxs) {
-                        throw new Error('Failed to prepare cross-chain transaction')
-                    }
-                    */
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 49451d1 and 526c84d.

📒 Files selected for processing (11)
  • src/app/(mobile-ui)/withdraw/crypto/page.tsx (6 hunks)
  • src/app/[...recipient]/client.tsx (1 hunks)
  • src/app/actions/tokens.ts (3 hunks)
  • src/components/Global/PeanutActionDetailsCard/index.tsx (4 hunks)
  • src/components/Global/RouteExpiryTimer/index.tsx (1 hunks)
  • src/components/Payment/Views/Confirm.payment.view.tsx (11 hunks)
  • src/components/Withdraw/views/Confirm.withdraw.view.tsx (6 hunks)
  • src/components/Withdraw/views/Initial.withdraw.view.tsx (2 hunks)
  • src/hooks/usePaymentInitiator.ts (13 hunks)
  • src/services/swap.ts (8 hunks)
  • src/utils/index.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
src/components/Withdraw/views/Initial.withdraw.view.tsx (2)
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#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: peanutprotocol/peanut-ui#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.
🧬 Code Graph Analysis (1)
src/app/actions/tokens.ts (3)
src/utils/general.utils.ts (2)
  • isStableCoin (1108-1110)
  • estimateIfIsStableCoinFromPrice (748-755)
src/app/actions/clients.ts (2)
  • getPublicClient (20-35)
  • ChainId (11-11)
src/utils/token.utils.ts (1)
  • NATIVE_TOKEN_ADDRESS (27-27)
🔇 Additional comments (34)
src/utils/index.ts (1)

6-6: LGTM! Clean utility export addition.

The export follows the established pattern and extends the available utility functions from the token.utils module.

src/app/[...recipient]/client.tsx (1)

396-396: LGTM! Consistent flow-based prop passing.

The isDirectPay prop correctly derives from the flow comparison and maintains consistency with the component's flow-handling pattern.

src/components/Withdraw/views/Initial.withdraw.view.tsx (1)

16-16: LGTM! TokenSelector properly integrated.

The TokenSelector import and usage are correctly implemented, allowing users to select their preferred token for withdrawal.

Also applies to: 90-90

src/app/actions/tokens.ts (2)

7-9: LGTM! Necessary imports for enhanced functionality.

The new imports support the enhanced stablecoin detection and transaction cost estimation features.


90-90: LGTM! Enhanced stablecoin detection.

Adding symbol-based stablecoin detection alongside price-based detection provides more robust stablecoin identification.

src/components/Global/RouteExpiryTimer/index.tsx (4)

35-58: LGTM! Robust time calculation with proper validation.

The calculateTimeRemaining function properly handles edge cases:

  • Validates expiry input
  • Handles invalid timestamps
  • Correctly converts Unix timestamp to milliseconds
  • Returns null for invalid inputs

60-109: LGTM! Proper cleanup and state management.

The useEffect properly:

  • Cleans up intervals to prevent memory leaks
  • Resets state when conditions change
  • Handles callback triggers with proper guards
  • Updates timer at appropriate intervals

140-144: LGTM! Smart pulse logic for user feedback.

The pulse animation appropriately triggers during loading and near expiry states, providing good visual feedback to users.


155-187: LGTM! Well-structured render with proper styling.

The component renders with:

  • Clear status text with appropriate colors
  • Animated progress bar with color coding
  • Proper conditional styling using twMerge
  • Good accessibility through color and text indicators
src/components/Global/PeanutActionDetailsCard/index.tsx (2)

24-31: Well-structured timer props interface.

The timer-related props are clearly defined with appropriate types and optional flags. The naming convention is consistent and the props cover all necessary timer functionality.


135-144: Clean timer integration.

The conditional rendering of RouteExpiryTimer is well-implemented, passing through all necessary props while maintaining the existing card layout.

src/app/(mobile-ui)/withdraw/crypto/page.tsx (4)

217-233: Solid cross-chain detection logic.

The cross-chain detection correctly compares source and destination chain IDs, with proper handling of Peanut Wallet context. The logging provides good debugging information.


236-245: Appropriate route type restrictions.

The route type error checking correctly restricts "swap" routes for Peanut Wallet users, providing a clear error message. This aligns with the business logic requirements.


202-207: Clean route refresh implementation.

The route refresh handler properly calls prepareTransactionDetails with current charge details and amount. The logging helps with debugging route expiry scenarios.


252-257: Robust network fee calculation.

The network fee calculation provides appropriate fallbacks and formatting, handling both cross-chain routes and default scenarios properly.

src/components/Payment/Views/Confirm.payment.view.tsx (3)

75-83: Improved network fee calculation.

The network fee memo handles multiple scenarios properly: Peanut Wallet sponsorship, fee estimation errors, and small amounts with appropriate formatting.


298-307: Consistent route type restrictions.

The route type error logic matches the withdrawal flow implementation, maintaining consistency across payment and withdrawal experiences.


334-342: Effective timer integration.

The timer props are properly passed to PeanutActionDetailsCard, enabling cross-chain route expiry handling in the payment flow.

src/components/Withdraw/views/Confirm.withdraw.view.tsx (3)

68-76: Well-integrated timer functionality.

The timer props are properly integrated, providing expiry handling and loading states for cross-chain withdrawals.


128-137: Improved error handling logic.

The enhanced error handling correctly differentiates between route type errors (triggering refresh) and other errors (triggering retry), providing better user experience.


67-67: Let’s broaden the search to include both .ts and .tsx files without relying on ripgrep types:

#!/bin/bash
# Search for hardcoded USDC tokenSymbol across TS and TSX files
rg 'tokenSymbol\s*=\s*"USDC"' -A3 -B3 --glob '*.ts' --glob '*.tsx'
src/services/swap.ts (6)

177-193: Secure allowance checking implementation.

The checkTokenAllowance function properly uses the ERC-20 standard interface and handles the blockchain interaction correctly.


198-214: Clean approval transaction creation.

The createApproveTransaction function correctly encodes the ERC-20 approve function call with proper parameter handling.


274-277: Excellent performance optimization.

The concurrent fetching of token prices using Promise.all significantly improves performance by avoiding sequential API calls.


290-306: Thoughtful tolerance adjustments.

The dynamic tolerance ranges based on USD amounts show careful consideration of slippage effects across different transaction sizes, with more granular control for smaller amounts.


482-524: Robust approval handling logic.

The approval logic correctly:

  • Checks current allowance before creating approval transactions
  • Only adds approval when insufficient allowance exists
  • Includes approval costs in total fee calculation
  • Handles errors gracefully without breaking the flow

This is a solid implementation of ERC-20 approval handling.


527-537: Well-structured transaction array.

The transaction preparation properly sequences approval (if needed) followed by the main swap transaction, with consistent fee options for both transaction types.

src/hooks/usePaymentInitiator.ts (7)

26-35: LGTM: Import updates align with new cross-chain functionality.

The new imports properly support the architectural shift to using the swap service for cross-chain routing and fee estimation.


95-95: LGTM: Added state for cross-chain route data.

The new xChainRoute state variable properly stores the comprehensive route information from the swap service.


172-173: LGTM: Function signature improvements for withdrawal flow.

The parameter changes from isAddMoneyFlowContext to isWithdrawFlow and the addition of usdAmount provide better clarity and support for USD-based routing.


254-263: LGTM: Improved fee estimation for same-chain transactions.

The integration with estimateTransactionCostUsd provides more accurate fee estimation compared to the previous approach.


207-219: LGTM: Comprehensive cross-chain route integration.

The new getRoute integration properly handles both USD-based and token amount-based routing, providing a more flexible and powerful cross-chain solution.


746-746: LGTM: Return object updated with cross-chain route data.

Adding xChainRoute to the return object enables components to access route expiry timers and other cross-chain metadata as mentioned in the PR objectives.


447-504: Verify hardcoded chain/token values match transaction preparation.

The function now uses hardcoded PEANUT_WALLET_CHAIN and PEANUT_WALLET_TOKEN values when creating payment records, but the actual transactions might use different chains/tokens based on the cross-chain route. This could cause inconsistencies in payment tracking.

#!/bin/bash
# Description: Check if PEANUT_WALLET_CHAIN and PEANUT_WALLET_TOKEN are consistently used across transaction preparation and payment creation

# Search for usage of these constants in cross-chain transaction preparation
rg -A 5 -B 5 "PEANUT_WALLET_CHAIN|PEANUT_WALLET_TOKEN" --type ts

Copy link
Contributor

@Hugo0 Hugo0 left a comment

Choose a reason for hiding this comment

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

squid 99.5 WIP

Comment on lines +252 to +257
const networkFee = useCallback(() => {
if (xChainRoute?.feeCostsUsd) {
return xChainRoute.feeCostsUsd < 0.01 ? '$ <0.01' : `$ ${xChainRoute.feeCostsUsd.toFixed(2)}`
}
return '$ 0.00'
}, [xChainRoute])
Copy link
Contributor

Choose a reason for hiding this comment

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

issue, non-blocking: I dislike this. We have a lot of money flows

withdraw, add, pay a request, send money etc

In all of them we have fees. We should handle that in a centralized place (probably 2: one for calculation, the other for formatting). Having it like this increases code complexity and surface for bugs

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For xChain the calculation is centralized (we use the one informed by squid), formatting I actually prefer it to be near of where we show the value. We have two confirm pages right now. The withdraw one and the payment one that is used in all other flows

Copy link
Contributor

Choose a reason for hiding this comment

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

i disagree. We've had so much back and forth on fees - tons of discussions and edge case bugs and so on. I really think centralizing would save us a lot of time longterm. Happy to disagree and commit on this one, but lets revisit it next time we have a bug on fees

currency,
currencyAmount,
isAddMoneyFlow,
isDirectPay = false,
Copy link
Contributor

Choose a reason for hiding this comment

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

Readability: directPay var is not clear. Why does it matter? Would a dev reading this for the first time be able to understand why the variables are needed and what they represent without having to deeply understand prepareTransaction and other fns?

Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: for functions, always add a quick docstring. IMO almost always it helps readability. It is extremely rare that we are too verbose.

Copy link
Contributor

Choose a reason for hiding this comment

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

@jjramirezn this isnt resolved

Comment on lines +219 to +237
async function estimateApprovalCostUsd(
tokenAddress: Address,
spenderAddress: Address,
amount: bigint,
fromAddress: Address,
chainId: string
): Promise<number> {
const estimateCost = await estimateTransactionCostUsd(
fromAddress,
tokenAddress,
encodeFunctionData({
abi: erc20Abi,
functionName: 'approve',
args: [spenderAddress, amount],
}),
chainId
)
return estimateCost
}
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: this seems like an unnecessary fn. A generic estimateTxnCostUsd is better and always usable imo

Copy link
Contributor Author

Choose a reason for hiding this comment

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

my brother in christ, this function uses the generic estimateTxCostUsd

Copy link
Contributor

Choose a reason for hiding this comment

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

yes exactly! estimateApprovalCostUsd seems superfluous!

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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

♻️ Duplicate comments (3)
src/app/actions/tokens.ts (1)

148-210: Review the gas estimation assumptions and error handling.

The function implementation looks solid but has some areas for improvement:

  1. Gas decimals assumption: Line 201 uses nativeTokenPrice.decimals but this may not represent the native token's actual decimals. Native tokens often have different decimal configurations than what's returned from price APIs.

  2. Scientific notation handling: Based on the PR objectives, there's a known issue with scientific notation in parseUnits that could affect this code path.

  3. Conservative fallback: The 0.01 USD fallback might be too low for high-gas networks like Ethereum mainnet.

Consider these improvements:

// Get native token decimals dynamically  
-        const estimatedCostUsd = nativeTokenPrice ? Number(formatUnits(gasCostWei, nativeTokenPrice.decimals)) * nativeTokenPrice.price : 0.01
+        const nativeTokenDetails = await fetchTokenDetails(NATIVE_TOKEN_ADDRESS, chainId)
+        const decimals = nativeTokenDetails?.decimals ?? 18
+        const estimatedCostUsd = nativeTokenPrice ? Number(formatUnits(gasCostWei, decimals)) * nativeTokenPrice.price : 0.01

Also consider making the fallback amount configurable based on the chain:

-        return 0.01
+        // Higher fallback for mainnet, lower for testnets/L2s
+        const fallbackAmount = Number(chainId) === 1 ? 0.05 : 0.01
+        return fallbackAmount
src/components/Payment/Views/Confirm.payment.view.tsx (1)

323-326: Add error handling for deep property access.

The minimum received calculation accesses deeply nested properties (xChainRoute.rawResponse.route.estimate.toAmountMin) without null checks, which could throw runtime errors if the API response structure changes.

Add defensive programming:

     const minReceived = useMemo<string | null>(() => {
-        if (!xChainRoute || !chargeDetails?.tokenDecimals) return null
-        return formatUnits(BigInt(xChainRoute.rawResponse.route.estimate.toAmountMin), chargeDetails.tokenDecimals)
+        if (!xChainRoute || !chargeDetails?.tokenDecimals) return null
+        
+        try {
+            const toAmountMin = xChainRoute.rawResponse?.route?.estimate?.toAmountMin
+            if (!toAmountMin) return null
+            return formatUnits(BigInt(toAmountMin), chargeDetails.tokenDecimals)
+        } catch (error) {
+            console.warn('Failed to calculate minimum received amount:', error)
+            return null
+        }
     }, [xChainRoute, chargeDetails?.tokenDecimals])
src/hooks/usePaymentInitiator.ts (1)

238-238: Fix potentially incorrect slippage calculation.

The slippage calculation appears to be comparing amounts rather than prices, which would not give a meaningful slippage percentage. Slippage should typically be calculated based on price impact or expected vs actual exchange rates.

Verify this calculation is correct, or consider:

-                    const slippagePercentage = Number(xChainRoute.fromAmount) / Number(chargeDetails.tokenAmount) - 1
+                    // Calculate slippage based on route's price impact if available
+                    const slippagePercentage = xChainRoute.slippage ?? 0
🧹 Nitpick comments (1)
src/hooks/usePaymentInitiator.ts (1)

232-236: Remove commented-out code.

This commented code block should be removed to maintain code cleanliness.

-                    /*
-                    if (!txData?.unsignedTxs) {
-                        throw new Error('Failed to prepare cross-chain transaction')
-                    }
-                    */
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 186d490 and 83a5ac8.

📒 Files selected for processing (5)
  • src/app/(mobile-ui)/withdraw/crypto/page.tsx (11 hunks)
  • src/app/actions/tokens.ts (3 hunks)
  • src/components/Payment/Views/Confirm.payment.view.tsx (11 hunks)
  • src/hooks/usePaymentInitiator.ts (13 hunks)
  • src/services/swap.ts (10 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/app/(mobile-ui)/withdraw/crypto/page.tsx
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#919
File: src/components/Withdraw/views/Initial.withdraw.view.tsx:87-87
Timestamp: 2025-06-18T19:56:55.443Z
Learning: In withdraw flows for Peanut Wallet, the PeanutActionDetailsCard should always display "USDC" as the token symbol because it shows the amount being withdrawn from the Peanut Wallet (which holds USDC), regardless of the destination token/chain selected by the user. The TokenSelector is used for choosing the withdrawal destination, not the source display.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#535
File: src/components/Claim/Claim.tsx:142-146
Timestamp: 2024-11-18T21:36:11.486Z
Learning: In `src/components/Claim/Claim.tsx`, external calls like token price fetching and cross-chain details retrieval are already encapsulated within existing `try...catch` blocks, so additional error handling may be unnecessary.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#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: Hugo0
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Pay.tsx:103-111
Timestamp: 2024-10-08T20:13:42.967Z
Learning: When the token price cannot be fetched in `src/components/Request/Pay/Pay.tsx` within the `PayRequestLink` component, set `tokenPriceData.price` to 0 to ensure the UI remains functional. Since Squid uses their own price engine for x-chain fulfillment transactions, this approach will not affect the transaction computation.
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Pay.tsx:103-111
Timestamp: 2024-10-07T13:42:00.443Z
Learning: When the token price cannot be fetched in `src/components/Request/Pay/Pay.tsx` within the `PayRequestLink` component, set `tokenPriceData.price` to 0 to ensure the UI remains functional. Since Squid uses their own price engine for x-chain fulfillment transactions, this approach will not affect the transaction computation.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Views/Initial.view.tsx:76-78
Timestamp: 2024-10-07T15:28:25.280Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, both `txFee` and `utils.formatTokenAmount(estimatedGasCost, 3)` return strings, ensuring consistent return types for `calculatedFee`.
src/app/actions/tokens.ts (16)
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Views/Initial.view.tsx:76-78
Timestamp: 2024-10-07T15:28:25.280Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, both `txFee` and `utils.formatTokenAmount(estimatedGasCost, 3)` return strings, ensuring consistent return types for `calculatedFee`.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Views/Initial.view.tsx:76-78
Timestamp: 2024-10-07T15:25:45.170Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, both `txFee` and `utils.formatTokenAmount(...)` return strings, ensuring that `calculatedFee` consistently returns a string without the need for additional type conversion.
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Pay.tsx:103-111
Timestamp: 2024-10-08T20:13:42.967Z
Learning: When the token price cannot be fetched in `src/components/Request/Pay/Pay.tsx` within the `PayRequestLink` component, set `tokenPriceData.price` to 0 to ensure the UI remains functional. Since Squid uses their own price engine for x-chain fulfillment transactions, this approach will not affect the transaction computation.
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Pay.tsx:103-111
Timestamp: 2024-10-07T13:42:00.443Z
Learning: When the token price cannot be fetched in `src/components/Request/Pay/Pay.tsx` within the `PayRequestLink` component, set `tokenPriceData.price` to 0 to ensure the UI remains functional. Since Squid uses their own price engine for x-chain fulfillment transactions, this approach will not affect the transaction computation.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#535
File: src/components/Claim/Claim.tsx:142-146
Timestamp: 2024-11-18T21:36:11.486Z
Learning: In `src/components/Claim/Claim.tsx`, external calls like token price fetching and cross-chain details retrieval are already encapsulated within existing `try...catch` blocks, so additional error handling may be unnecessary.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#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: peanutprotocol/peanut-ui#847
File: src/app/actions/clients.ts:48-68
Timestamp: 2025-05-13T16:26:58.336Z
Learning: In viem v2.21.48, the `stateOverride` parameter for `estimateGas` and related functions expects an array-based format: `[{ address: tokenAddress, stateDiff: [{ slot: calculatedSlot, value: hexValue }] }]` rather than an object-based format.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#868
File: src/components/Payment/PaymentForm/index.tsx:284-293
Timestamp: 2025-05-19T19:40:43.138Z
Learning: When converting between USD and token amounts, always check if the token price (divisor) is valid and non-zero before performing the division to prevent Infinity, NaN, or errors. Implementing validation like `if (!tokenPrice || isNaN(tokenPrice) || tokenPrice === 0)` before division operations is crucial for handling cases where price data might be unavailable.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#551
File: src/context/walletContext/walletContext.tsx:87-88
Timestamp: 2024-12-02T17:21:45.515Z
Learning: When converting `totalBalance` (in USD) to a `BigInt` balance in `src/context/walletContext/walletContext.tsx`, multiplying by `1e6` is intentional to maintain compatibility with USDC's 6 decimal places. The application displays only 2 decimal places, so this level of precision is sufficient.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#404
File: src/context/tokenSelector.context.tsx:121-121
Timestamp: 2024-10-03T09:57:43.885Z
Learning: In `TokenContextProvider` within `tokenSelector.context.tsx`, when token data is loaded from preferences, it's acceptable to set `isTokenPriceFetchingComplete` to `true` because the token data is already available.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#495
File: src/components/Cashout/Components/Initial.view.tsx:194-198
Timestamp: 2024-10-29T14:44:08.745Z
Learning: Using a fixed 6 decimal places for `floorFixed` is acceptable for token amounts in this codebase, even if tokens have varying decimal places.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#424
File: src/components/Global/TokenSelector/TokenSelector.tsx:197-211
Timestamp: 2024-10-11T01:14:15.489Z
Learning: In `src/components/Global/TokenSelector/TokenSelector.tsx`, when the calculation within functions like `byChainAndText` is not computationally expensive, it's acceptable to avoid using `useCallback` for memoization.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#443
File: src/components/Request/Pay/Views/Initial.view.tsx:293-297
Timestamp: 2024-10-16T11:37:07.647Z
Learning: Routes obtained from `createXChainUnsignedTx` are only valid for 20 seconds, so caching them for reuse is not effective.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#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: jjramirezn
PR: peanutprotocol/peanut-ui#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: peanutprotocol/peanut-ui#478
File: src/components/Dashboard/useDashboard.tsx:134-134
Timestamp: 2024-10-24T12:36:40.508Z
Learning: In the file `src/components/Dashboard/useDashboard.tsx`, memoization of the `getTokenSymbol` function is not necessary because it is lightweight and does not involve complex computations or network calls.
src/components/Payment/Views/Confirm.payment.view.tsx (26)
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#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: jjramirezn
PR: peanutprotocol/peanut-ui#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: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Views/Initial.view.tsx:76-78
Timestamp: 2024-10-07T15:28:25.280Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, both `txFee` and `utils.formatTokenAmount(estimatedGasCost, 3)` return strings, ensuring consistent return types for `calculatedFee`.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Views/Initial.view.tsx:76-78
Timestamp: 2024-10-07T15:25:45.170Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, both `txFee` and `utils.formatTokenAmount(...)` return strings, ensuring that `calculatedFee` consistently returns a string without the need for additional type conversion.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#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: Hugo0
PR: peanutprotocol/peanut-ui#413
File: src/components/Request/Pay/Views/Initial.view.tsx:71-72
Timestamp: 2024-10-04T13:10:49.199Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, it's acceptable to use the `!` operator in TypeScript to assert that `selectedTokenData` is not `null` or `undefined`, and potential runtime errors from accessing its properties without checks can be disregarded.
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#413
File: src/components/Request/Pay/Views/Initial.view.tsx:71-72
Timestamp: 2024-10-08T20:13:42.967Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, it's acceptable to use the `!` operator in TypeScript to assert that `selectedTokenData` is not `null` or `undefined`, and potential runtime errors from accessing its properties without checks can be disregarded.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#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: Hugo0
PR: peanutprotocol/peanut-ui#458
File: src/components/Offramp/Confirm.view.tsx:141-141
Timestamp: 2024-10-18T01:51:35.247Z
Learning: The `handleConfirm` function in `src/components/Create/Link/Confirm.view.tsx` is separate from the one in `src/components/Offramp/Confirm.view.tsx` and does not need to be renamed when refactoring `handleConfirm` in `src/components/Offramp/Confirm.view.tsx`.
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#458
File: src/components/Offramp/Confirm.view.tsx:96-96
Timestamp: 2024-10-18T08:54:22.142Z
Learning: In the `src/components/Offramp/Confirm.view.tsx` file, it's acceptable to include crass or informal language in code comments.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#469
File: src/app/request/pay/page.tsx:32-64
Timestamp: 2024-10-23T09:38:04.446Z
Learning: Within `src/app/request/pay/page.tsx`, extracting the `getBaseUrl` function does not add significant readability, and the host URL construction code is expected to change soon.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#535
File: src/components/Claim/Claim.tsx:142-146
Timestamp: 2024-11-18T21:36:11.486Z
Learning: In `src/components/Claim/Claim.tsx`, external calls like token price fetching and cross-chain details retrieval are already encapsulated within existing `try...catch` blocks, so additional error handling may be unnecessary.
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Pay.tsx:103-111
Timestamp: 2024-10-07T13:42:00.443Z
Learning: When the token price cannot be fetched in `src/components/Request/Pay/Pay.tsx` within the `PayRequestLink` component, set `tokenPriceData.price` to 0 to ensure the UI remains functional. Since Squid uses their own price engine for x-chain fulfillment transactions, this approach will not affect the transaction computation.
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Pay.tsx:103-111
Timestamp: 2024-10-08T20:13:42.967Z
Learning: When the token price cannot be fetched in `src/components/Request/Pay/Pay.tsx` within the `PayRequestLink` component, set `tokenPriceData.price` to 0 to ensure the UI remains functional. Since Squid uses their own price engine for x-chain fulfillment transactions, this approach will not affect the transaction computation.
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Pay.tsx:113-123
Timestamp: 2024-10-08T20:13:42.967Z
Learning: In the `PayRequestLink` component (`src/components/Request/Pay/Pay.tsx`), when resolving ENS names, handle errors by displaying an appropriate error message to the user if the ENS cannot be resolved.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#469
File: src/app/request/pay/page.tsx:25-25
Timestamp: 2024-10-22T18:10:56.955Z
Learning: In the `src/app/request/pay/page.tsx` file, the `PreviewType` enum values are strings, so when adding `previewType` to `URLSearchParams`, there's no need to convert them to strings.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#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: jjramirezn
PR: peanutprotocol/peanut-ui#469
File: src/app/request/pay/page.tsx:32-49
Timestamp: 2024-10-22T18:11:36.864Z
Learning: In `src/app/request/pay/page.tsx`, the `id` parameter is accessed via `searchParams.id` in the `generateMetadata` function.
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Pay.tsx:113-123
Timestamp: 2024-10-07T13:42:07.299Z
Learning: In the `PayRequestLink` component (`src/components/Request/Pay/Pay.tsx`), when resolving ENS names, handle errors by displaying an appropriate error message to the user if the ENS cannot be resolved.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#404
File: src/context/tokenSelector.context.tsx:121-121
Timestamp: 2024-10-03T09:57:43.885Z
Learning: In `TokenContextProvider` within `tokenSelector.context.tsx`, when token data is loaded from preferences, it's acceptable to set `isTokenPriceFetchingComplete` to `true` because the token data is already available.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#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: peanutprotocol/peanut-ui#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: peanutprotocol/peanut-ui#424
File: src/components/Global/TokenSelector/TokenSelector.tsx:197-211
Timestamp: 2024-10-11T01:14:15.489Z
Learning: In `src/components/Global/TokenSelector/TokenSelector.tsx`, when the calculation within functions like `byChainAndText` is not computationally expensive, it's acceptable to avoid using `useCallback` for memoization.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#478
File: src/components/Request/Create/Views/Initial.view.tsx:48-128
Timestamp: 2024-10-24T12:40:15.006Z
Learning: When `handleOnNext` is deliberately refactored to avoid dependencies that change, it's acceptable to have an empty dependency array in `useCallback`.
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#420
File: src/components/Offramp/Offramp.consts.ts:27-28
Timestamp: 2024-10-08T20:13:42.967Z
Learning: In `src/components/Offramp/Offramp.consts.ts`, the `MIN_CASHOUT_LIMIT` is set to $10 because smaller amounts are impractical due to approximately $1 fee per cashout.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#919
File: src/components/Withdraw/views/Initial.withdraw.view.tsx:87-87
Timestamp: 2025-06-18T19:56:55.443Z
Learning: In withdraw flows for Peanut Wallet, the PeanutActionDetailsCard should always display "USDC" as the token symbol because it shows the amount being withdrawn from the Peanut Wallet (which holds USDC), regardless of the destination token/chain selected by the user. The TokenSelector is used for choosing the withdrawal destination, not the source display.
src/services/swap.ts (17)
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#535
File: src/components/Claim/Claim.tsx:142-146
Timestamp: 2024-11-18T21:36:11.486Z
Learning: In `src/components/Claim/Claim.tsx`, external calls like token price fetching and cross-chain details retrieval are already encapsulated within existing `try...catch` blocks, so additional error handling may be unnecessary.
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Pay.tsx:103-111
Timestamp: 2024-10-08T20:13:42.967Z
Learning: When the token price cannot be fetched in `src/components/Request/Pay/Pay.tsx` within the `PayRequestLink` component, set `tokenPriceData.price` to 0 to ensure the UI remains functional. Since Squid uses their own price engine for x-chain fulfillment transactions, this approach will not affect the transaction computation.
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Pay.tsx:103-111
Timestamp: 2024-10-07T13:42:00.443Z
Learning: When the token price cannot be fetched in `src/components/Request/Pay/Pay.tsx` within the `PayRequestLink` component, set `tokenPriceData.price` to 0 to ensure the UI remains functional. Since Squid uses their own price engine for x-chain fulfillment transactions, this approach will not affect the transaction computation.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Views/Initial.view.tsx:76-78
Timestamp: 2024-10-07T15:28:25.280Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, both `txFee` and `utils.formatTokenAmount(estimatedGasCost, 3)` return strings, ensuring consistent return types for `calculatedFee`.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Views/Initial.view.tsx:76-78
Timestamp: 2024-10-07T15:25:45.170Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, both `txFee` and `utils.formatTokenAmount(...)` return strings, ensuring that `calculatedFee` consistently returns a string without the need for additional type conversion.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#847
File: src/app/actions/clients.ts:48-68
Timestamp: 2025-05-13T16:26:58.336Z
Learning: In viem v2.21.48, the `stateOverride` parameter for `estimateGas` and related functions expects an array-based format: `[{ address: tokenAddress, stateDiff: [{ slot: calculatedSlot, value: hexValue }] }]` rather than an object-based format.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#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: peanutprotocol/peanut-ui#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: peanutprotocol/peanut-ui#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: jjramirezn
PR: peanutprotocol/peanut-ui#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: peanutprotocol/peanut-ui#431
File: src/components/Create/Link/Success.view.tsx:89-89
Timestamp: 2024-10-08T20:28:39.527Z
Learning: The remaining uses of `shortenAddressLong` are for transaction hashes and do not need to be replaced.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#551
File: src/context/walletContext/walletContext.tsx:87-88
Timestamp: 2024-12-02T17:21:45.515Z
Learning: When converting `totalBalance` (in USD) to a `BigInt` balance in `src/context/walletContext/walletContext.tsx`, multiplying by `1e6` is intentional to maintain compatibility with USDC's 6 decimal places. The application displays only 2 decimal places, so this level of precision is sufficient.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#404
File: src/context/tokenSelector.context.tsx:121-121
Timestamp: 2024-10-03T09:57:43.885Z
Learning: In `TokenContextProvider` within `tokenSelector.context.tsx`, when token data is loaded from preferences, it's acceptable to set `isTokenPriceFetchingComplete` to `true` because the token data is already available.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#424
File: src/components/Global/TokenSelector/TokenSelector.tsx:197-211
Timestamp: 2024-10-11T01:14:15.489Z
Learning: In `src/components/Global/TokenSelector/TokenSelector.tsx`, when the calculation within functions like `byChainAndText` is not computationally expensive, it's acceptable to avoid using `useCallback` for memoization.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#478
File: src/components/Request/Create/Views/Initial.view.tsx:81-89
Timestamp: 2024-10-24T12:38:32.793Z
Learning: In `src/components/Request/Create/Views/Initial.view.tsx`, the function `getTokenDetails` is a simple function that does not fetch from the network or perform asynchronous operations.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#868
File: src/components/Payment/PaymentForm/index.tsx:284-293
Timestamp: 2025-05-19T19:40:43.138Z
Learning: When converting between USD and token amounts, always check if the token price (divisor) is valid and non-zero before performing the division to prevent Infinity, NaN, or errors. Implementing validation like `if (!tokenPrice || isNaN(tokenPrice) || tokenPrice === 0)` before division operations is crucial for handling cases where price data might be unavailable.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#443
File: src/components/Request/Pay/Views/Initial.view.tsx:293-297
Timestamp: 2024-10-16T11:37:07.647Z
Learning: Routes obtained from `createXChainUnsignedTx` are only valid for 20 seconds, so caching them for reuse is not effective.
src/hooks/usePaymentInitiator.ts (29)
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Views/Initial.view.tsx:76-78
Timestamp: 2024-10-07T15:28:25.280Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, both `txFee` and `utils.formatTokenAmount(estimatedGasCost, 3)` return strings, ensuring consistent return types for `calculatedFee`.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Views/Initial.view.tsx:76-78
Timestamp: 2024-10-07T15:25:45.170Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, both `txFee` and `utils.formatTokenAmount(...)` return strings, ensuring that `calculatedFee` consistently returns a string without the need for additional type conversion.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#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: peanutprotocol/peanut-ui#495
File: src/components/Create/useCreateLink.tsx:647-657
Timestamp: 2024-10-29T16:06:38.812Z
Learning: In the React code for `useCreateLink` in `src/components/Create/useCreateLink.tsx`, the `switchNetwork` function used within `useCallback` hooks is stable and does not need to be included in the dependency arrays.
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Pay.tsx:103-111
Timestamp: 2024-10-08T20:13:42.967Z
Learning: When the token price cannot be fetched in `src/components/Request/Pay/Pay.tsx` within the `PayRequestLink` component, set `tokenPriceData.price` to 0 to ensure the UI remains functional. Since Squid uses their own price engine for x-chain fulfillment transactions, this approach will not affect the transaction computation.
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Pay.tsx:103-111
Timestamp: 2024-10-07T13:42:00.443Z
Learning: When the token price cannot be fetched in `src/components/Request/Pay/Pay.tsx` within the `PayRequestLink` component, set `tokenPriceData.price` to 0 to ensure the UI remains functional. Since Squid uses their own price engine for x-chain fulfillment transactions, this approach will not affect the transaction computation.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#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: peanutprotocol/peanut-ui#535
File: src/components/Claim/Claim.tsx:142-146
Timestamp: 2024-11-18T21:36:11.486Z
Learning: In `src/components/Claim/Claim.tsx`, external calls like token price fetching and cross-chain details retrieval are already encapsulated within existing `try...catch` blocks, so additional error handling may be unnecessary.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#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: jjramirezn
PR: peanutprotocol/peanut-ui#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: Hugo0
PR: peanutprotocol/peanut-ui#413
File: src/components/Request/Pay/Views/Initial.view.tsx:71-72
Timestamp: 2024-10-04T13:10:49.199Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, it's acceptable to use the `!` operator in TypeScript to assert that `selectedTokenData` is not `null` or `undefined`, and potential runtime errors from accessing its properties without checks can be disregarded.
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#413
File: src/components/Request/Pay/Views/Initial.view.tsx:71-72
Timestamp: 2024-10-08T20:13:42.967Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, it's acceptable to use the `!` operator in TypeScript to assert that `selectedTokenData` is not `null` or `undefined`, and potential runtime errors from accessing its properties without checks can be disregarded.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#868
File: src/components/Payment/PaymentForm/index.tsx:284-293
Timestamp: 2025-05-19T19:40:43.138Z
Learning: When converting between USD and token amounts, always check if the token price (divisor) is valid and non-zero before performing the division to prevent Infinity, NaN, or errors. Implementing validation like `if (!tokenPrice || isNaN(tokenPrice) || tokenPrice === 0)` before division operations is crucial for handling cases where price data might be unavailable.
Learnt from: kushagrasarathe
PR: peanutprotocol/peanut-ui#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: peanutprotocol/peanut-ui#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: peanutprotocol/peanut-ui#919
File: src/components/Withdraw/views/Initial.withdraw.view.tsx:87-87
Timestamp: 2025-06-18T19:56:55.443Z
Learning: In withdraw flows for Peanut Wallet, the PeanutActionDetailsCard should always display "USDC" as the token symbol because it shows the amount being withdrawn from the Peanut Wallet (which holds USDC), regardless of the destination token/chain selected by the user. The TokenSelector is used for choosing the withdrawal destination, not the source display.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#431
File: src/components/Create/Link/Success.view.tsx:89-89
Timestamp: 2024-10-08T20:28:39.527Z
Learning: The remaining uses of `shortenAddressLong` are for transaction hashes and do not need to be replaced.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#478
File: src/components/Request/Create/Views/Initial.view.tsx:93-94
Timestamp: 2024-10-24T12:39:09.318Z
Learning: In `src/components/Request/Create/Views/Initial.view.tsx`, the `inputValue` variable passed to `peanut.createRequestLink` is expected to be a string.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#827
File: src/components/Claim/Link/Initial.view.tsx:120-126
Timestamp: 2025-04-30T21:31:27.790Z
Learning: The `sendLinksApi.claim` function in the Peanut Protocol UI accepts both username and wallet address as the first parameter.
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#420
File: src/components/Offramp/Offramp.consts.ts:27-28
Timestamp: 2024-10-08T20:13:42.967Z
Learning: In `src/components/Offramp/Offramp.consts.ts`, the `MIN_CASHOUT_LIMIT` is set to $10 because smaller amounts are impractical due to approximately $1 fee per cashout.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#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: peanutprotocol/peanut-ui#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: peanutprotocol/peanut-ui#404
File: src/context/tokenSelector.context.tsx:121-121
Timestamp: 2024-10-03T09:57:43.885Z
Learning: In `TokenContextProvider` within `tokenSelector.context.tsx`, when token data is loaded from preferences, it's acceptable to set `isTokenPriceFetchingComplete` to `true` because the token data is already available.
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Pay.tsx:113-123
Timestamp: 2024-10-07T13:42:07.299Z
Learning: In the `PayRequestLink` component (`src/components/Request/Pay/Pay.tsx`), when resolving ENS names, handle errors by displaying an appropriate error message to the user if the ENS cannot be resolved.
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Pay.tsx:113-123
Timestamp: 2024-10-08T20:13:42.967Z
Learning: In the `PayRequestLink` component (`src/components/Request/Pay/Pay.tsx`), when resolving ENS names, handle errors by displaying an appropriate error message to the user if the ENS cannot be resolved.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#424
File: src/components/Global/TokenSelector/TokenSelector.tsx:197-211
Timestamp: 2024-10-11T01:14:15.489Z
Learning: In `src/components/Global/TokenSelector/TokenSelector.tsx`, when the calculation within functions like `byChainAndText` is not computationally expensive, it's acceptable to avoid using `useCallback` for memoization.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#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.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#443
File: src/components/Request/Pay/Views/Initial.view.tsx:293-297
Timestamp: 2024-10-16T11:37:07.647Z
Learning: Routes obtained from `createXChainUnsignedTx` are only valid for 20 seconds, so caching them for reuse is not effective.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#830
File: src/components/Global/ListItemView/index.tsx:186-191
Timestamp: 2025-05-05T20:43:40.198Z
Learning: In the Peanut UI codebase, chainId is stored as a numeric or hex ID in the HistoryEntry object, not as a human-readable name string. When using it with explorer links, it should be passed directly to getExplorerUrl() as a number, rather than comparing it against chain.name in the supportedPeanutChains array.
🧬 Code Graph Analysis (1)
src/app/actions/tokens.ts (4)
src/utils/general.utils.ts (2)
  • isStableCoin (1108-1110)
  • estimateIfIsStableCoinFromPrice (748-755)
src/utils/__mocks__/next-cache.ts (1)
  • unstable_cache (1-1)
src/app/actions/clients.ts (2)
  • getPublicClient (20-29)
  • ChainId (11-11)
src/utils/token.utils.ts (1)
  • NATIVE_TOKEN_ADDRESS (27-27)
🔇 Additional comments (27)
src/app/actions/tokens.ts (2)

7-9: LGTM!

The new imports are correctly structured and will support the enhanced token price checking and gas estimation functionality.


90-90: Enhanced stablecoin detection is a good improvement.

The dual approach using both symbol-based checking and price-based estimation provides better coverage for stablecoin identification.

src/components/Payment/Views/Confirm.payment.view.tsx (7)

41-41: LGTM!

The new isDirectPay prop correctly supports conditional transaction preparation for direct USD payments.


75-83: Well-implemented fee display logic.

The networkFee memo correctly handles different wallet types, error states, and formatting edge cases for small amounts.


140-146: Good conditional transaction preparation logic.

The direct pay flow correctly passes the currency amount when paying in USD, which aligns with the intended functionality.


159-163: Excellent route refresh handling.

The callback properly refreshes transaction details on route expiry, ensuring users get updated routing information.


312-321: Strong route type validation for Peanut Wallet.

The logic correctly prevents unsupported swap routes for Peanut Wallet users, enforcing the RFQ-only requirement.


353-362: Excellent route expiry timer integration.

The timer implementation with callbacks for near expiry and expiry events provides a great user experience for time-sensitive cross-chain routes.


366-372: Good addition of minimum received information.

The conditional display of minimum received amount helps users understand potential slippage in cross-chain transactions.

src/services/swap.ts (10)

3-8: LGTM!

The new imports properly support ERC-20 approval handling and enhanced transaction cost estimation.


177-193: Well-implemented allowance checking.

The function correctly uses the ERC-20 standard allowance function and provides a clean interface for checking current approvals.


198-214: Good approval transaction creation.

The function properly encodes the ERC-20 approve function call with correct parameters and return structure.


219-237: Solid approval cost estimation.

The function leverages the existing transaction cost estimation infrastructure to provide accurate gas cost estimates for approval transactions.


274-283: Excellent concurrent price fetching optimization.

The parallel fetching of token prices significantly improves performance compared to sequential API calls.


290-309: Enhanced granularity for small amounts is well-designed.

The refined tolerances and range multipliers for small USD amounts (< 0.3 and < 1) provide better handling of micro-transactions and testing scenarios.


412-413: Verify number formatting to prevent scientific notation issues.

Based on the PR objectives, there's a known issue with scientific notation numbers not being accepted by parseUnits. The division here could produce scientific notation for very small amounts.

Add validation to ensure the number is in proper decimal format:

-        const tokenAmount = Number(amount.fromUsd) / fromTokenPrice.price
-        fromAmount = parseUnits(tokenAmount.toFixed(fromTokenPrice.decimals), fromTokenPrice.decimals).toString()
+        const tokenAmount = Number(amount.fromUsd) / fromTokenPrice.price
+        const tokenAmountString = tokenAmount.toFixed(fromTokenPrice.decimals)
+        // Ensure no scientific notation
+        if (tokenAmountString.includes('e') || tokenAmountString.includes('E')) {
+            throw new Error(`Token amount calculation resulted in scientific notation: ${tokenAmountString}`)
+        }
+        fromAmount = parseUnits(tokenAmountString, fromTokenPrice.decimals).toString()

482-524: Comprehensive approval handling implementation.

The approval logic is well-structured with proper error handling:

  1. Smart allowance checking: Only creates approval transactions when needed
  2. Graceful error handling: Continues with swap if allowance check fails
  3. Cost integration: Properly adds approval costs to total fees
  4. Transaction ordering: Correctly places approval before the main swap

This implementation significantly enhances the cross-chain swap experience.


527-537: Good transaction structure standardization.

The consistent transaction format with fee options provides a clean interface for transaction execution across different transaction types.


548-550: Helpful debugging information.

The detailed logging provides valuable insights for troubleshooting route creation and expiry handling.

src/hooks/usePaymentInitiator.ts (8)

26-36: LGTM! Import updates align with the refactoring.

The import changes properly support the transition from internal fee calculation to the external routing service approach.


95-95: LGTM! State addition supports new routing approach.

Adding xChainRoute state properly supports the new cross-chain routing functionality.


172-180: LGTM! Function signature enhancement with good defaults.

The optional parameters with sensible defaults maintain backward compatibility while enabling more flexible usage.


207-231: LGTM! Cross-chain preparation refactoring is well-structured.

The refactoring to use getRoute service properly centralizes cross-chain logic and handles both USD amount and token amount scenarios appropriately.


265-274: LGTM! Gas estimation refactoring is appropriate.

The transition to using estimateTransactionCostUsd centralizes gas estimation logic and properly handles the async calculation.


458-515: LGTM! Peanut Wallet payment handling properly updated.

The removal of the payload parameter and use of prepared transactions from state aligns well with the new transaction preparation approach. The hardcoded constants for Peanut Wallet are appropriate for this specific payment flow.


690-690: LGTM! Function call updated correctly.

The removal of the payload parameter aligns with the updated function signature.


749-757: LGTM! Return object properly reflects state changes.

The replacement of feeCalculations with estimatedGasCost and addition of xChainRoute correctly exposes the new state structure to consumers.

Comment on lines 190 to 209
// Run all API calls in parallel since they're independent
const [gasEstimate, gasPrice, nativeTokenPrice] = await Promise.all([
getCachedGasEstimate(fromAddress, contractAddress, data, chainId),
getCachedGasPrice(chainId),
fetchTokenPrice(NATIVE_TOKEN_ADDRESS, chainId),
])

// Calculate gas cost in native token
const gasCostWei = gasEstimate * gasPrice

const estimatedCostUsd = nativeTokenPrice
? Number(formatUnits(gasCostWei, nativeTokenPrice.decimals)) * nativeTokenPrice.price
: 0.01

return estimatedCostUsd
} catch (error) {
console.error('Error estimating transaction cost:', error)
// Return a conservative estimate if we can't calculate exact cost
return 0.01
}
Copy link
Contributor

Choose a reason for hiding this comment

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

yay

also, its insane to me that 1 cents is a conservative cost estimate. thats insane. we've come so far in crypto

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants