From c2556bbdf800ba99d5054f6c696a5ddd77b08a90 Mon Sep 17 00:00:00 2001
From: kushagrasarathe <76868364+kushagrasarathe@users.noreply.github.com>
Date: Wed, 12 Nov 2025 12:19:03 -0300
Subject: [PATCH 1/4] feat: enable crosschain payments using token selector
---
src/components/Payment/PaymentForm/index.tsx | 90 +++++++++++++-------
1 file changed, 61 insertions(+), 29 deletions(-)
diff --git a/src/components/Payment/PaymentForm/index.tsx b/src/components/Payment/PaymentForm/index.tsx
index c9f3c7180..eb09cc5f1 100644
--- a/src/components/Payment/PaymentForm/index.tsx
+++ b/src/components/Payment/PaymentForm/index.tsx
@@ -10,8 +10,9 @@ import FileUploadInput from '@/components/Global/FileUploadInput'
import { type IconName } from '@/components/Global/Icons/Icon'
import NavHeader from '@/components/Global/NavHeader'
import TokenAmountInput from '@/components/Global/TokenAmountInput'
+import TokenSelector from '@/components/Global/TokenSelector/TokenSelector'
import UserCard from '@/components/User/UserCard'
-import { PEANUT_WALLET_TOKEN, PEANUT_WALLET_TOKEN_DECIMALS } from '@/constants'
+import { PEANUT_WALLET_TOKEN, PEANUT_WALLET_TOKEN_DECIMALS, PEANUT_WALLET_CHAIN } from '@/constants'
import { tokenSelectorContext } from '@/context'
import { useAuth } from '@/context/authContext'
import { useRequestFulfillmentFlow } from '@/context/RequestFulfillmentFlowContext'
@@ -182,6 +183,9 @@ export const PaymentForm = ({
setInputTokenAmount(amount)
}
+ // for ADDRESS/ENS recipients, initialize token/chain from URL or defaults
+ const isExternalRecipient = recipient?.recipientType === 'ADDRESS' || recipient?.recipientType === 'ENS'
+
if (chain) {
setSelectedChainID((chain.chainId || requestDetails?.chainId) ?? '')
if (!token && !requestDetails?.tokenAddress) {
@@ -191,15 +195,37 @@ export const PaymentForm = ({
// Note: decimals automatically derived by useTokenPrice hook
}
}
+ } else if (isExternalRecipient && !selectedChainID) {
+ // default to arbitrum for external recipients if no chain specified
+ setSelectedChainID(PEANUT_WALLET_CHAIN.id.toString())
}
if (token) {
setSelectedTokenAddress((token.address || requestDetails?.tokenAddress) ?? '')
// Note: decimals automatically derived by useTokenPrice hook
+ } else if (isExternalRecipient && !selectedTokenAddress && selectedChainID) {
+ // default to USDC for external recipients if no token specified
+ const chainData = supportedSquidChainsAndTokens[selectedChainID]
+ const defaultToken = chainData?.tokens.find((t) => t.symbol.toLowerCase() === 'usdc')
+ if (defaultToken) {
+ setSelectedTokenAddress(defaultToken.address)
+ }
}
setInitialSetupDone(true)
- }, [chain, token, amount, initialSetupDone, requestDetails, showRequestPotInitialView, isRequestPotLink])
+ }, [
+ chain,
+ token,
+ amount,
+ initialSetupDone,
+ requestDetails,
+ showRequestPotInitialView,
+ isRequestPotLink,
+ recipient?.recipientType,
+ selectedChainID,
+ selectedTokenAddress,
+ supportedSquidChainsAndTokens,
+ ])
// reset error when component mounts or recipient changes
useEffect(() => {
@@ -244,12 +270,14 @@ export const PaymentForm = ({
}
} else {
// regular send/pay
+ const isExternalRecipient = recipient?.recipientType === 'ADDRESS' || recipient?.recipientType === 'ENS'
+
if (
!showRequestPotInitialView && // don't apply balance check on request pot payment initial view
isActivePeanutWallet &&
- areEvmAddressesEqual(selectedTokenAddress, PEANUT_WALLET_TOKEN)
+ (areEvmAddressesEqual(selectedTokenAddress, PEANUT_WALLET_TOKEN) || !isExternalRecipient)
) {
- // peanut wallet payment
+ // peanut wallet payment (for USERNAME or default token)
const walletNumeric = parseFloat(String(peanutWalletBalance).replace(/,/g, ''))
if (walletNumeric < parsedInputAmount) {
dispatch(paymentActions.setError('Insufficient balance'))
@@ -274,6 +302,9 @@ export const PaymentForm = ({
} else {
dispatch(paymentActions.setError(null))
}
+ } else if (isExternalRecipient && isActivePeanutWallet) {
+ // for external recipients with peanut wallet, balance will be checked via cross-chain route
+ dispatch(paymentActions.setError(null))
} else {
dispatch(paymentActions.setError(null))
}
@@ -304,6 +335,7 @@ export const PaymentForm = ({
currentView,
isProcessing,
hasPendingTransactions,
+ recipient?.recipientType,
])
// Calculate USD value when requested token price is available
@@ -339,7 +371,12 @@ export const PaymentForm = ({
(!!inputTokenAmount && parseFloat(inputTokenAmount) > 0) || (!!usdValue && parseFloat(usdValue) > 0)
}
- const tokenSelected = !!selectedTokenAddress && !!selectedChainID
+ const isExternalRecipient = recipient?.recipientType === 'ADDRESS' || recipient?.recipientType === 'ENS'
+ // for external recipients, token selection is required
+ // for USERNAME recipients, token is always PEANUT_WALLET_TOKEN
+ const tokenSelected = isExternalRecipient
+ ? !!selectedTokenAddress && !!selectedChainID
+ : !!selectedTokenAddress && !!selectedChainID
const recipientExists = !!recipient
const walletConnected = isConnected
@@ -809,30 +846,25 @@ export const PaymentForm = ({
defaultSliderSuggestedAmount={defaultSliderValue.suggestedAmount}
/>
- {/*
- Url request flow (peanut.me/
)
- If we are paying from peanut wallet we only need to
- select a token if it's not included in the url
- From other wallets we always need to select a token
- */}
- {/* we dont need this as daimo will handle token selection */}
- {/* {!(chain && isPeanutWalletConnected) && isConnected && !isAddMoneyFlow && (
-
- {!isPeanutWalletUSDC && !selectedTokenAddress && !selectedChainID && (
-
Select token and chain to receive
- )}
-
- {!isPeanutWalletUSDC && selectedTokenAddress && selectedChainID && (
-
- Use USDC on Arbitrum for free transactions!
-
- )}
-
- )} */}
-
- {/* {isExternalWalletConnected && isAddMoneyFlow && (
-
- )} */}
+ {/* Token selector for external ADDRESS/ENS recipients */}
+ {!isExternalWalletFlow &&
+ !showRequestPotInitialView &&
+ (recipient?.recipientType === 'ADDRESS' || recipient?.recipientType === 'ENS') &&
+ isConnected && (
+
+
+ {selectedTokenAddress &&
+ selectedChainID &&
+ !(
+ areEvmAddressesEqual(selectedTokenAddress, PEANUT_WALLET_TOKEN) &&
+ selectedChainID === PEANUT_WALLET_CHAIN.id.toString()
+ ) && (
+
+ Use USDC on Arbitrum for free transactions!
+
+ )}
+
+ )}
{isDirectUsdPayment && (
Date: Wed, 12 Nov 2025 13:26:16 -0300
Subject: [PATCH 2/4] fix: use daimo for external wallet payments
---
src/app/[...recipient]/client.tsx | 7 --
src/components/Common/ActionList.tsx | 21 ++++--
.../Common/ActionListDaimoPayButton.tsx | 6 ++
src/components/Payment/PaymentForm/index.tsx | 16 +----
.../views/ExternalWalletFulfilManager.tsx | 67 -------------------
.../views/ExternalWalletFulfilMethods.tsx | 45 -------------
src/context/RequestFulfillmentFlowContext.tsx | 18 -----
7 files changed, 24 insertions(+), 156 deletions(-)
delete mode 100644 src/components/Request/views/ExternalWalletFulfilManager.tsx
delete mode 100644 src/components/Request/views/ExternalWalletFulfilMethods.tsx
diff --git a/src/app/[...recipient]/client.tsx b/src/app/[...recipient]/client.tsx
index 007190da8..bbb5fd15c 100644
--- a/src/app/[...recipient]/client.tsx
+++ b/src/app/[...recipient]/client.tsx
@@ -26,7 +26,6 @@ import { useEffect, useMemo, useRef, useState } from 'react'
import { twMerge } from 'tailwind-merge'
import { fetchTokenPrice } from '@/app/actions/tokens'
import { RequestFulfillmentBankFlowStep, useRequestFulfillmentFlow } from '@/context/RequestFulfillmentFlowContext'
-import ExternalWalletFulfilManager from '@/components/Request/views/ExternalWalletFulfilManager'
import ActionList from '@/components/Common/ActionList'
import NavHeader from '@/components/Global/NavHeader'
import { ReqFulfillBankFlowManager } from '@/components/Request/views/ReqFulfillBankFlowManager'
@@ -67,7 +66,6 @@ export default function PaymentPage({ recipient, flow = 'request_pay' }: Props)
const { isDrawerOpen, selectedTransaction, openTransactionDetails } = useTransactionDetailsDrawer()
const [isLinkCancelling, setisLinkCancelling] = useState(false)
const {
- showExternalWalletFulfillMethods,
showRequestFulfilmentBankFlowManager,
setShowRequestFulfilmentBankFlowManager,
setFlowStep: setRequestFulfilmentBankFlowStep,
@@ -524,11 +522,6 @@ export default function PaymentPage({ recipient, flow = 'request_pay' }: Props)
)
}
- // render external wallet fulfilment methods
- if (showExternalWalletFulfillMethods) {
- return
- }
-
// render request fulfilment bank flow manager
if (showRequestFulfilmentBankFlowManager) {
return
diff --git a/src/components/Common/ActionList.tsx b/src/components/Common/ActionList.tsx
index 657e439ee..1aecc768e 100644
--- a/src/components/Common/ActionList.tsx
+++ b/src/components/Common/ActionList.tsx
@@ -5,7 +5,7 @@ import IconStack from '../Global/IconStack'
import { ClaimBankFlowStep, useClaimBankFlow } from '@/context/ClaimBankFlowContext'
import { type ClaimLinkData } from '@/services/sendLinks'
import { formatUnits } from 'viem'
-import { useContext, useMemo, useState } from 'react'
+import { useContext, useMemo, useState, useRef } from 'react'
import ActionModal from '@/components/Global/ActionModal'
import Divider from '../0_Bruddle/Divider'
import { Button } from '../0_Bruddle'
@@ -86,7 +86,6 @@ export default function ActionList({
const { addParamStep } = useClaimLink()
const {
setShowRequestFulfilmentBankFlowManager,
- setShowExternalWalletFulfillMethods,
setFlowStep: setRequestFulfilmentBankFlowStep,
setFulfillUsingManteca,
setRegionalMethodType: setRequestFulfillmentRegionalMethodType,
@@ -109,6 +108,8 @@ export default function ActionList({
const { initiatePayment, loadingStep } = usePaymentInitiator()
const { isUserMantecaKycApproved } = useKycStatus()
const isPaymentInProgress = loadingStep !== 'Idle' && loadingStep !== 'Error' && loadingStep !== 'Success'
+ // ref to store daimo button click handler for triggering from balance modal
+ const daimoButtonClickRef = useRef<(() => void) | null>(null)
const dispatch = useAppDispatch()
@@ -255,9 +256,7 @@ export default function ActionList({
setRequestFulfillmentRegionalMethodType(method.id)
setFulfillUsingManteca(true)
break
- case 'exchange-or-wallet':
- setShowExternalWalletFulfillMethods(true)
- break
+ // 'exchange-or-wallet' case removed - handled by ActionListDaimoPayButton
}
}
}
@@ -329,6 +328,7 @@ export default function ActionList({
return true // Proceed with Daimo
}}
isDisabled={!isAmountEntered}
+ clickHandlerRef={daimoButtonClickRef}
/>
)
@@ -427,7 +427,16 @@ export default function ActionList({
setIsUsePeanutBalanceModalShown(true)
// Proceed with the method the user originally selected
if (selectedPaymentMethod) {
- handleMethodClick(selectedPaymentMethod, true) // true = bypass modal check
+ // for exchange-or-wallet, trigger daimo button after state updates
+ if (selectedPaymentMethod.id === 'exchange-or-wallet' && daimoButtonClickRef.current) {
+ // use setTimeout to ensure state updates are processed before triggering daimo
+ setTimeout(() => {
+ daimoButtonClickRef.current?.()
+ }, 0)
+ } else {
+ // for other methods, use handleMethodClick
+ handleMethodClick(selectedPaymentMethod, true) // true = bypass modal check
+ }
}
setSelectedPaymentMethod(null)
},
diff --git a/src/components/Common/ActionListDaimoPayButton.tsx b/src/components/Common/ActionListDaimoPayButton.tsx
index a2683aeea..2c96d3142 100644
--- a/src/components/Common/ActionListDaimoPayButton.tsx
+++ b/src/components/Common/ActionListDaimoPayButton.tsx
@@ -17,6 +17,7 @@ interface ActionListDaimoPayButtonProps {
showConfirmModal: boolean
onBeforeShow?: () => boolean | Promise
isDisabled?: boolean
+ clickHandlerRef?: React.MutableRefObject<(() => void) | null>
}
const ActionListDaimoPayButton = ({
@@ -24,6 +25,7 @@ const ActionListDaimoPayButton = ({
showConfirmModal,
onBeforeShow,
isDisabled,
+ clickHandlerRef,
}: ActionListDaimoPayButtonProps) => {
const dispatch = useAppDispatch()
const searchParams = useSearchParams()
@@ -178,6 +180,10 @@ const ActionListDaimoPayButton = ({
{({ onClick, loading }) => {
// Store the onClick function so we can trigger it from elsewhere
daimoPayButtonClickRef.current = onClick
+ // also store in parent ref if provided (for balance modal in ActionList)
+ if (clickHandlerRef) {
+ clickHandlerRef.current = onClick
+ }
return (
{
- if (isExternalWalletFlow) {
- setShowExternalWalletFulfillMethods(true)
- setExternalWalletFulfillMethod(null)
- return
- } else if (window.history.length > 1) {
+ if (window.history.length > 1) {
router.back()
} else {
router.push('/')
diff --git a/src/components/Request/views/ExternalWalletFulfilManager.tsx b/src/components/Request/views/ExternalWalletFulfilManager.tsx
deleted file mode 100644
index 389ed9005..000000000
--- a/src/components/Request/views/ExternalWalletFulfilManager.tsx
+++ /dev/null
@@ -1,67 +0,0 @@
-import { useRequestFulfillmentFlow } from '@/context/RequestFulfillmentFlowContext'
-import ExternalWalletFulfilMethods from './ExternalWalletFulfilMethods'
-import AddMoneyCryptoPage from '@/app/(mobile-ui)/add-money/crypto/page'
-import { type ParsedURL } from '@/lib/url-parser/types/payment'
-import { usePaymentStore } from '@/redux/hooks'
-import ConfirmPaymentView from '@/components/Payment/Views/Confirm.payment.view'
-import DirectSuccessView from '@/components/Payment/Views/Status.payment.view'
-import { PaymentForm } from '@/components/Payment/PaymentForm'
-
-export default function ExternalWalletFulfilManager({ parsedPaymentData }: { parsedPaymentData: ParsedURL }) {
- const {
- showExternalWalletFulfillMethods,
- externalWalletFulfillMethod,
- setExternalWalletFulfillMethod,
- setShowExternalWalletFulfillMethods,
- } = useRequestFulfillmentFlow()
- const { currentView } = usePaymentStore()
-
- if (externalWalletFulfillMethod === 'wallet') {
- switch (currentView) {
- case 'INITIAL':
- return (
-
- )
- case 'CONFIRM':
- return
- case 'STATUS':
- return (
-
- )
- default:
- break
- }
- }
-
- if (externalWalletFulfillMethod === 'exchange') {
- return (
- {
- setExternalWalletFulfillMethod(null)
- setShowExternalWalletFulfillMethods(true)
- }}
- />
- )
- }
-
- if (showExternalWalletFulfillMethods) {
- return setShowExternalWalletFulfillMethods(false)} />
- }
-
- return null
-}
diff --git a/src/components/Request/views/ExternalWalletFulfilMethods.tsx b/src/components/Request/views/ExternalWalletFulfilMethods.tsx
deleted file mode 100644
index 94acb7fd8..000000000
--- a/src/components/Request/views/ExternalWalletFulfilMethods.tsx
+++ /dev/null
@@ -1,45 +0,0 @@
-import { BINANCE_LOGO, LEMON_LOGO, RIPIO_LOGO } from '@/assets'
-import { METAMASK_LOGO, RAINBOW_LOGO, TRUST_WALLET_SMALL_LOGO } from '@/assets/wallets'
-import { MethodCard } from '@/components/Common/ActionList'
-import NavHeader from '@/components/Global/NavHeader'
-import { type PaymentMethod } from '@/constants/actionlist.consts'
-import { type ExternalWalletFulfilMethod, useRequestFulfillmentFlow } from '@/context/RequestFulfillmentFlowContext'
-
-const methods: PaymentMethod[] = [
- {
- id: 'exchange',
- title: 'Exchange',
- description: 'Lemon, Binance, Ripio and more',
- icons: [RIPIO_LOGO, BINANCE_LOGO, LEMON_LOGO],
- soon: false,
- },
- {
- id: 'wallet',
- title: 'Crypto Wallet',
- description: 'Metamask, Trustwallet and more',
- icons: [RAINBOW_LOGO, TRUST_WALLET_SMALL_LOGO, METAMASK_LOGO],
- soon: false,
- },
-]
-
-export default function ExternalWalletFulfilMethods({ onBack }: { onBack: () => void }) {
- const { setExternalWalletFulfillMethod } = useRequestFulfillmentFlow()
-
- return (
-
-
-
-
Where will you send from?
- {methods.map((method) => (
-
{
- setExternalWalletFulfillMethod(method.id as ExternalWalletFulfilMethod)
- }}
- />
- ))}
-
-
- )
-}
diff --git a/src/context/RequestFulfillmentFlowContext.tsx b/src/context/RequestFulfillmentFlowContext.tsx
index 82ee98a12..d9400aa24 100644
--- a/src/context/RequestFulfillmentFlowContext.tsx
+++ b/src/context/RequestFulfillmentFlowContext.tsx
@@ -5,8 +5,6 @@ import { type CountryData } from '@/components/AddMoney/consts'
import { type IOnrampData } from './OnrampFlowContext'
import { type User } from '@/interfaces'
-export type ExternalWalletFulfilMethod = 'exchange' | 'wallet'
-
export enum RequestFulfillmentBankFlowStep {
BankCountryList = 'bank-country-list',
DepositBankDetails = 'deposit-bank-details',
@@ -16,12 +14,8 @@ export enum RequestFulfillmentBankFlowStep {
interface RequestFulfillmentFlowContextType {
resetFlow: () => void
- showExternalWalletFulfillMethods: boolean
- setShowExternalWalletFulfillMethods: (showExternalWalletFulfillMethods: boolean) => void
showRequestFulfilmentBankFlowManager: boolean
setShowRequestFulfilmentBankFlowManager: (showRequestFulfilmentBankFlowManager: boolean) => void
- externalWalletFulfillMethod: ExternalWalletFulfilMethod | null
- setExternalWalletFulfillMethod: (externalWalletFulfillMethod: ExternalWalletFulfilMethod | null) => void
flowStep: RequestFulfillmentBankFlowStep | null
setFlowStep: (step: RequestFulfillmentBankFlowStep | null) => void
selectedCountry: CountryData | null
@@ -43,10 +37,6 @@ interface RequestFulfillmentFlowContextType {
const RequestFulfillmentFlowContext = createContext(undefined)
export const RequestFulfilmentFlowContextProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
- const [showExternalWalletFulfillMethods, setShowExternalWalletFulfillMethods] = useState(false)
- const [externalWalletFulfillMethod, setExternalWalletFulfillMethod] = useState(
- null
- )
const [showRequestFulfilmentBankFlowManager, setShowRequestFulfilmentBankFlowManager] = useState(false)
const [flowStep, setFlowStep] = useState(null)
const [selectedCountry, setSelectedCountry] = useState(null)
@@ -58,8 +48,6 @@ export const RequestFulfilmentFlowContextProvider: React.FC<{ children: ReactNod
const [triggerPayWithPeanut, setTriggerPayWithPeanut] = useState(false) // To trigger the pay with peanut from Action List
const resetFlow = useCallback(() => {
- setExternalWalletFulfillMethod(null)
- setShowExternalWalletFulfillMethods(false)
setFlowStep(null)
setShowRequestFulfilmentBankFlowManager(false)
setSelectedCountry(null)
@@ -73,10 +61,6 @@ export const RequestFulfilmentFlowContextProvider: React.FC<{ children: ReactNod
const value = useMemo(
() => ({
resetFlow,
- externalWalletFulfillMethod,
- setExternalWalletFulfillMethod,
- showExternalWalletFulfillMethods,
- setShowExternalWalletFulfillMethods,
flowStep,
setFlowStep,
showRequestFulfilmentBankFlowManager,
@@ -98,8 +82,6 @@ export const RequestFulfilmentFlowContextProvider: React.FC<{ children: ReactNod
}),
[
resetFlow,
- externalWalletFulfillMethod,
- showExternalWalletFulfillMethods,
flowStep,
showRequestFulfilmentBankFlowManager,
selectedCountry,
From 710a7e608906d5746bddbed7f878691af9c5f45b Mon Sep 17 00:00:00 2001
From: kushagrasarathe <76868364+kushagrasarathe@users.noreply.github.com>
Date: Wed, 12 Nov 2025 13:27:04 -0300
Subject: [PATCH 3/4] fix: daimo cross chain payments destination chain
---
src/components/Common/ActionListDaimoPayButton.tsx | 7 ++++++-
src/components/Global/DaimoPayButton/index.tsx | 10 ++++++++--
2 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/src/components/Common/ActionListDaimoPayButton.tsx b/src/components/Common/ActionListDaimoPayButton.tsx
index 2c96d3142..95551cbed 100644
--- a/src/components/Common/ActionListDaimoPayButton.tsx
+++ b/src/components/Common/ActionListDaimoPayButton.tsx
@@ -117,7 +117,10 @@ const ActionListDaimoPayButton = ({
const result = await completeDaimoPayment({
chargeDetails: chargeDetails,
txHash: daimoPaymentResponse.txHash as string,
- destinationchainId: daimoPaymentResponse.payment.destination.chainId,
+ // use destination chain from chargeDetails (not from daimo response)
+ // chargeDetails has the correct chain from URL/explicit overrides
+ destinationchainId:
+ Number(chargeDetails.chainId) ?? Number(daimoPaymentResponse.payment.destination.chainId),
payerAddress: peanutWalletAddress ?? daimoPaymentResponse.payment.source.payerAddress,
sourceChainId: daimoPaymentResponse.payment.source.chainId,
sourceTokenAddress: daimoPaymentResponse.payment.source.tokenAddress,
@@ -150,6 +153,8 @@ const ActionListDaimoPayButton = ({
{
// First check if parent wants to intercept (e.g. show balance modal)
diff --git a/src/components/Global/DaimoPayButton/index.tsx b/src/components/Global/DaimoPayButton/index.tsx
index 2702efa0c..cdb6b6732 100644
--- a/src/components/Global/DaimoPayButton/index.tsx
+++ b/src/components/Global/DaimoPayButton/index.tsx
@@ -13,6 +13,10 @@ export interface DaimoPayButtonProps {
amount: string
/** The recipient address */
toAddress: string
+ /** Target chain ID (defaults to Arbitrum if not specified) */
+ toChainId?: number
+ /** Target token address (defaults to USDC on Arbitrum if not specified) */
+ toTokenAddress?: string
/**
* Render function that receives click handler and other props
* OR React node for backwards compatibility
@@ -51,6 +55,8 @@ export interface DaimoPayButtonProps {
export const DaimoPayButton = ({
amount,
toAddress,
+ toChainId,
+ toTokenAddress,
children,
variant = 'purple',
icon,
@@ -139,10 +145,10 @@ export const DaimoPayButton = ({
resetOnSuccess // resets the daimo payment state after payment is successfully completed
appId={daimoAppId}
intent="Deposit"
- toChain={arbitrum.id}
+ toChain={toChainId ?? arbitrum.id} // use provided chain or default to arbitrum
toUnits={amount.replace(/,/g, '')}
toAddress={getAddress(toAddress)}
- toToken={getAddress(PEANUT_WALLET_TOKEN)} // USDC on arbitrum
+ toToken={getAddress(toTokenAddress ?? PEANUT_WALLET_TOKEN)} // use provided token or default to usdc on arbitrum
onPaymentCompleted={onPaymentCompleted}
closeOnSuccess
onClose={onClose}
From 6f4e0cc2c9f29ad354fd50c4bb75380aca473426 Mon Sep 17 00:00:00 2001
From: kushagrasarathe <76868364+kushagrasarathe@users.noreply.github.com>
Date: Wed, 12 Nov 2025 15:39:18 -0300
Subject: [PATCH 4/4] fix: cr comments
---
src/components/Common/ActionListDaimoPayButton.tsx | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/src/components/Common/ActionListDaimoPayButton.tsx b/src/components/Common/ActionListDaimoPayButton.tsx
index 95551cbed..609978550 100644
--- a/src/components/Common/ActionListDaimoPayButton.tsx
+++ b/src/components/Common/ActionListDaimoPayButton.tsx
@@ -114,13 +114,18 @@ const ActionListDaimoPayButton = ({
if (chargeDetails) {
dispatch(paymentActions.setIsDaimoPaymentProcessing(true))
try {
+ // validate and parse destination chain id with proper fallback
+ // use chargeDetails chainId if it's a valid non-negative integer, otherwise use daimo response
+ const parsedChainId = Number(chargeDetails.chainId)
+ const destinationChainId =
+ Number.isInteger(parsedChainId) && parsedChainId >= 0
+ ? parsedChainId
+ : Number(daimoPaymentResponse.payment.destination.chainId)
+
const result = await completeDaimoPayment({
chargeDetails: chargeDetails,
txHash: daimoPaymentResponse.txHash as string,
- // use destination chain from chargeDetails (not from daimo response)
- // chargeDetails has the correct chain from URL/explicit overrides
- destinationchainId:
- Number(chargeDetails.chainId) ?? Number(daimoPaymentResponse.payment.destination.chainId),
+ destinationchainId: destinationChainId,
payerAddress: peanutWalletAddress ?? daimoPaymentResponse.payment.source.payerAddress,
sourceChainId: daimoPaymentResponse.payment.source.chainId,
sourceTokenAddress: daimoPaymentResponse.payment.source.tokenAddress,