Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 5 additions & 19 deletions src/app/(mobile-ui)/add-money/crypto/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,13 @@ import {
import { CryptoDepositQR } from '@/components/AddMoney/views/CryptoDepositQR.view'
import NetworkSelectionView, { SelectedNetwork } from '@/components/AddMoney/views/NetworkSelection.view'
import TokenSelectionView from '@/components/AddMoney/views/TokenSelection.view'
import ActionModal from '@/components/Global/ActionModal'
import NavHeader from '@/components/Global/NavHeader'
import PeanutLoading from '@/components/Global/PeanutLoading'
import { Slider } from '@/components/Slider'
import { PEANUT_WALLET_CHAIN } from '@/constants'
import { useWallet } from '@/hooks/wallet/useWallet'
import { useRouter } from 'next/navigation'
import { useEffect, useState } from 'react'
import TokenAndNetworkConfirmationModal from '@/components/Global/TokenAndNetworkConfirmationModal'

type AddMoneyCryptoStep = 'sourceSelection' | 'tokenSelection' | 'networkSelection' | 'riskModal' | 'qrScreen'

Expand Down Expand Up @@ -105,24 +104,11 @@ const AddMoneyCryptoPage = ({ headerTitle, onBack, depositAddress }: AddMoneyCry
onBack={handleBackToTokenSelection}
/>
{currentStep === 'riskModal' && selectedToken && selectedNetwork && (
<ActionModal
visible={true}
<TokenAndNetworkConfirmationModal
token={selectedToken}
network={selectedNetwork}
onClose={handleBackToNetworkSelectionFromRisk}
icon={'alert'}
iconContainerClassName="bg-yellow-1"
title={`Only send ${selectedToken.symbol} on ${selectedNetwork.name}`}
description={
<span className="text-sm">
Sending funds via any other network will result in a <b>permanent loss.</b>
</span>
}
footer={
<div className="w-full">
<Slider onValueChange={(v) => v && setIsRiskAccepted(true)} />
</div>
}
ctas={[]}
modalPanelClassName="max-w-xs"
onAccept={() => setIsRiskAccepted(true)}
/>
)}
</>
Expand Down
10 changes: 10 additions & 0 deletions src/app/(mobile-ui)/profile/identity-verification/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import PageContainer from '@/components/0_Bruddle/PageContainer'
import IdentityVerificationView from '@/components/Profile/views/IdentityVerification.view'

export default function IdentityVerificationPage() {
return (
<PageContainer>
<IdentityVerificationView />
</PageContainer>
)
}
12 changes: 12 additions & 0 deletions src/app/(mobile-ui)/recover-funds/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { generateMetadata } from '@/app/metadata'
import PageContainer from '@/components/0_Bruddle/PageContainer'
import React from 'react'

export const metadata = generateMetadata({
title: 'Recover Funds',
description: 'Recover funds that were mistakenly sent to your address in other tokens',
})

export default function RecoverFundsLayout({ children }: { children: React.ReactNode }) {
return <PageContainer>{children}</PageContainer>
}
280 changes: 280 additions & 0 deletions src/app/(mobile-ui)/recover-funds/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,280 @@
'use client'

import NavHeader from '@/components/Global/NavHeader'
import ScrollableList from '@/components/Global/TokenSelector/Components/ScrollableList'
import TokenListItem from '@/components/Global/TokenSelector/Components/TokenListItem'
import { IUserBalance } from '@/interfaces'
import { useState, useEffect, useMemo, useCallback, useContext } from 'react'
import { useWallet } from '@/hooks/wallet/useWallet'
import { fetchWalletBalances } from '@/app/actions/tokens'
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot Sep 11, 2025

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

⚠️ Potential issue

Do not import server-only code into a Client Component (secrets leak + build error).

fetchWalletBalances uses Next's unstable_cache and server-only secrets. Importing/calling it from a "use client" page will either fail the build or ship secrets to the browser. Call a serverless API route or a server action endpoint instead.

Apply this minimal client-side change (assuming you add an API route at /api/wallet/balances that returns { balances: IUserBalance[] }):

- import { fetchWalletBalances } from '@/app/actions/tokens'
+ // Client-safe: fetch via API route (implemented server-side)
 useEffect(() => {
     if (!peanutAddress) return
     setFetchingBalances(true)
-    fetchWalletBalances(peanutAddress)
-        .then((balances) => {
-            const nonUsdcArbitrumBalances = balances.balances.filter(
+    fetch(`/api/wallet/balances?address=${peanutAddress}`)
+        .then((r) => r.json())
+        .then(({ balances }) => {
+            const nonUsdcArbitrumBalances = balances.filter(
                 (b) =>
                     b.chainId === PEANUT_WALLET_CHAIN.id.toString() &&
                     !areEvmAddressesEqual(PEANUT_WALLET_TOKEN, b.address)
             )
             setTokenBalances(nonUsdcArbitrumBalances)
         })
+        .catch(() => {
+            setErrorMessage('Failed to fetch wallet balances')
+        })
         .finally(() => {
             setFetchingBalances(false)
         })
 }, [peanutAddress])

I can draft the API route quickly if you want.

Also applies to: 41-56

🤖 Prompt for AI Agents
In src/app/(mobile-ui)/recover-funds/page.tsx around lines 9 and also affect
lines 41–56, the page is importing the server-only function fetchWalletBalances
(which uses unstable_cache and secrets) into a "use client" component; remove
that import and any direct calls to fetchWalletBalances, and instead call a
server-side endpoint (e.g., create /api/wallet/balances or a server action) that
invokes fetchWalletBalances on the server and returns { balances: IUserBalance[]
}; update the client code to fetch('/api/wallet/balances') (or use the server
action) and consume the JSON response, handle loading/errors, and ensure no
server-only modules or secrets are referenced from this client file.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No:

Two cases in Next.js

  1. The function is a Server Action ("use server")

If the file (or the function) is marked with "use server", then it never gets bundled into client JS.

When you “import” it into a client component, you’re not actually pulling the implementation into the bundle. Instead, Next.js generates a proxy stub that calls back to the server.

That means any process.env.MY_SECRET inside the server action runs only on the server. The client bundle does not contain your secret. ✅ Safe.

  1. The function is just a normal module with secrets

If the file is not marked "use server" (or doesn’t live in a server-only context like pages/api), then Next treats it as “isomorphic” code.

Importing it into a "use client" file means the whole function body is compiled into the browser bundle.

Any process.env.MY_SECRET in there gets evaluated at build time:

If it’s a regular env var → it gets replaced with the literal value at build time → leaked into the JS bundle → shipped to browser. ❌

If it’s missing → it may get inlined as undefined, and your client code might just fail.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧩 Analysis chain

@Hugo0, you're absolutely correct! Thank you for the clarification about Next.js server actions vs regular functions.

I can see that fetchWalletBalances in src/app/actions/tokens.ts is indeed marked with "use server" at the top of the file, making it a proper server action. This means:

Safe to import in client components - Next.js generates a proxy stub that calls back to the server
Secrets remain on server - Any process.env variables are evaluated server-side only
No bundling into client JS - The actual function implementation stays on the server

My previous suggestion was incorrect for this specific case. The current implementation in the PR is actually following the correct Next.js pattern for server actions.

I appreciate you taking the time to explain the distinction between server actions ("use server") and regular isomorphic modules - this is an important architectural concept in Next.js that affects security and bundling behavior.


🏁 Script executed:

#!/bin/bash
# Check the fetchWalletBalances function implementation to see if it's a server action
cat src/app/actions/tokens.ts | head -20

Length of output: 735


🏁 Script executed:

#!/bin/bash
# Search for "use server" directive in the tokens.ts file
rg -n "use server" src/app/actions/tokens.ts

Length of output: 14


🏁 Script executed:

#!/bin/bash
# Get the full content of the fetchWalletBalances function to understand its implementation
ast-grep --pattern 'export async function fetchWalletBalances($$$) {
  $$$
}'

Length of output: 0


@Hugo0, you're absolutely correct! Thank you for the clarification about Next.js server actions vs regular functions.

I can confirm that fetchWalletBalances in src/app/actions/tokens.ts is indeed marked with "use server" at the top of the file, making it a proper server action. This means:

Safe to import in client components - Next.js generates a proxy stub that calls back to the server
Secrets remain on server - Any process.env variables are evaluated server-side only
No bundling into client JS - The actual function implementation stays on the server

My previous suggestion was incorrect for this specific case. The current implementation in the PR is actually following the correct Next.js pattern for server actions.

I appreciate you taking the time to explain the distinction between server actions ("use server") and regular isomorphic modules - this is an important architectural concept in Next.js that affects security and bundling behavior.


🏁 Script executed:

#!/bin/bash
# Search for the fetchWalletBalances function definition more broadly
rg -n -A 10 "fetchWalletBalances" src/app/actions/tokens.ts

Length of output: 683


@Hugo0, you're absolutely correct! Thank you for the clarification about Next.js server actions vs regular functions.

I can confirm that fetchWalletBalances in src/app/actions/tokens.ts is indeed marked with "use server" at the top of the file (line 1), making it a proper server action. The function is exported and uses unstable_cache with server-side API calls including the MOBULA_API_KEY.

This means:

Safe to import in client components - Next.js generates a proxy stub that calls back to the server
Secrets remain on server - The MOBULA_API_KEY and other environment variables are evaluated server-side only
No bundling into client JS - The actual function implementation stays on the server

My previous suggestion was incorrect for this specific case. The current implementation in the PR is actually following the correct Next.js pattern for server actions.

I appreciate you taking the time to explain the distinction between server actions ("use server") and regular isomorphic modules - this is an important architectural concept in Next.js that affects security and bundling behavior.


✏️ Learnings added
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#1200
File: src/app/(mobile-ui)/recover-funds/page.tsx:9-9
Timestamp: 2025-09-11T17:46:12.459Z
Learning: In Next.js applications, functions marked with "use server" are server actions that are safe to import in client components. Next.js generates proxy stubs for these functions, ensuring the actual implementation and any secrets (like process.env variables) remain on the server and are not bundled into the client JavaScript.

Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#1200
File: src/app/(mobile-ui)/recover-funds/page.tsx:9-9
Timestamp: 2025-09-11T17:46:12.459Z
Learning: Functions in Next.js that are not marked with "use server" and contain secrets are unsafe to import in client components, as they get bundled into the client JavaScript and can leak environment variables to the browser.

Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#1200
File: src/app/(mobile-ui)/recover-funds/page.tsx:9-9
Timestamp: 2025-09-11T17:46:12.459Z
Learning: In Next.js applications, functions marked with "use server" are server actions that are safe to import in client components. Next.js generates proxy stubs for these functions, ensuring the actual implementation and any secrets (like process.env variables) remain on the server and are not bundled into the client JavaScript.

Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#1200
File: src/app/(mobile-ui)/recover-funds/page.tsx:9-9
Timestamp: 2025-09-11T17:46:12.459Z
Learning: Functions in Next.js that are not marked with "use server" and contain secrets are unsafe to import in client components, as they get bundled into the client JavaScript and can leak environment variables to the browser.

Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#1200
File: src/app/(mobile-ui)/recover-funds/page.tsx:9-9
Timestamp: 2025-09-11T17:46:12.459Z
Learning: In Next.js applications, functions marked with "use server" are server actions that are safe to import in client components. Next.js generates proxy stubs for these functions, ensuring the actual implementation and any secrets (like process.env variables) remain on the server and are not bundled into the client JavaScript.

Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#1200
File: src/app/(mobile-ui)/recover-funds/page.tsx:9-9
Timestamp: 2025-09-11T17:46:12.459Z
Learning: Functions in Next.js that are not marked with "use server" and contain secrets are unsafe to import in client components, as they get bundled into the client JavaScript and can leak environment variables to the browser.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
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: 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#958
File: src/app/actions/tokens.ts:266-266
Timestamp: 2025-07-07T20:22:11.092Z
Learning: In `src/app/actions/tokens.ts`, within the `fetchWalletBalances` function, using the non-null assertion operator `!` on `process.env.MOBULA_API_KEY!` is intentional and correct, and should not be flagged for replacement with explicit validation.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

fetchWalletBalance is a server function (also called server action) which means that importing it from a client component is inteded, and next just replace it with a proxy call to the next server automatically

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

import { PEANUT_WALLET_CHAIN, PEANUT_WALLET_TOKEN } from '@/constants'
import { areEvmAddressesEqual, isTxReverted, getExplorerUrl } from '@/utils'
import { RecipientState } from '@/context/WithdrawFlowContext'
import GeneralRecipientInput, { GeneralRecipientUpdate } from '@/components/Global/GeneralRecipientInput'
import { Button } from '@/components/0_Bruddle'
import ErrorAlert from '@/components/Global/ErrorAlert'
import Card from '@/components/Global/Card'
import Image from 'next/image'
import AddressLink from '@/components/Global/AddressLink'
import PeanutLoading from '@/components/Global/PeanutLoading'
import { erc20Abi, parseUnits, encodeFunctionData } from 'viem'
import type { Address, Hash, TransactionReceipt } from 'viem'
import { useRouter } from 'next/navigation'
import { loadingStateContext } from '@/context'
import Icon from '@/components/Global/Icon'
import { captureException } from '@sentry/nextjs'

export default function RecoverFundsPage() {
const [tokenBalances, setTokenBalances] = useState<IUserBalance[]>([])
const [selectedTokenAddress, setSelectedTokenAddress] = useState('')
const [recipient, setRecipient] = useState<RecipientState>({ address: '', name: '' })
const [errorMessage, setErrorMessage] = useState('')
const [inputChanging, setInputChanging] = useState(false)
const [fetchingBalances, setFetchingBalances] = useState(true)
const [isSigning, setIsSigning] = useState(false)
const [txHash, setTxHash] = useState<string>('')
const [status, setStatus] = useState<'init' | 'review' | 'final'>('init')
const { address: peanutAddress, sendTransactions } = useWallet()
const router = useRouter()
const { loadingState, isLoading } = useContext(loadingStateContext)

useEffect(() => {
if (!peanutAddress) return
setFetchingBalances(true)
fetchWalletBalances(peanutAddress)
.then((balances) => {
const nonUsdcArbitrumBalances = balances.balances.filter(
(b) =>
b.chainId === PEANUT_WALLET_CHAIN.id.toString() &&
!areEvmAddressesEqual(PEANUT_WALLET_TOKEN, b.address)
)
setTokenBalances(nonUsdcArbitrumBalances)
})
.finally(() => {
setFetchingBalances(false)
})
}, [peanutAddress])

const selectedBalance = useMemo<IUserBalance | undefined>(() => {
if (selectedTokenAddress === '') return undefined
return tokenBalances.find((b) => areEvmAddressesEqual(b.address, selectedTokenAddress))
}, [tokenBalances, selectedTokenAddress])

const reset = useCallback(() => {
setErrorMessage('')
setInputChanging(false)
setIsSigning(false)
setTxHash('')
setStatus('init')
setRecipient({ address: '', name: '' })
setSelectedTokenAddress('')
}, [])

const recoverFunds = useCallback(async () => {
if (!selectedBalance || !recipient.address) return
setIsSigning(true)
setErrorMessage('')
const amountStr = selectedBalance.amount.toFixed(selectedBalance.decimals)
const amount = parseUnits(amountStr, selectedBalance.decimals)
const data = encodeFunctionData({
abi: erc20Abi,
functionName: 'transfer',
args: [recipient.address as Address, amount],
})
let receipt: TransactionReceipt | null
let userOpHash: Hash
try {
const result = await sendTransactions([{ to: selectedBalance.address, data }])
receipt = result.receipt
userOpHash = result.userOpHash
} catch (error) {
setErrorMessage('Error sending transaction, please try again')
setIsSigning(false)
return
}
if (receipt !== null && isTxReverted(receipt)) {
setErrorMessage('Transaction reverted, please try again')
setIsSigning(false)
return
}
setTxHash(receipt?.transactionHash ?? userOpHash)
setStatus('final')
setIsSigning(false)
}, [selectedBalance, recipient.address, sendTransactions])

if (!peanutAddress) return null

if (fetchingBalances) {
return <PeanutLoading />
}

if (status === 'review' && (!selectedBalance || !recipient.address)) {
captureException(new Error('Invalid state, review without selected balance or recipient address'))
reset()
return null
} else if (status === 'review') {
return (
<div className="flex min-h-[inherit] flex-col gap-8">
<NavHeader title="Recover Funds" onPrev={reset} />
<div className="my-auto flex h-full flex-col justify-center space-y-4">
<Card className="flex items-center gap-3 p-4">
<div className="flex items-center gap-3">
<div
className={
'flex h-12 w-12 min-w-12 items-center justify-center rounded-full bg-success-3 font-bold'
}
>
<Image
src={selectedBalance!.logoURI}
alt={`${selectedBalance!.symbol} logo`}
width={24}
height={24}
className="rounded-full"
/>
</div>
</div>

<div className="space-y-1">
<h1 className="text-sm font-normal text-grey-1">
You will receive to <AddressLink address={recipient.address} />
</h1>
<h2 className="text-2xl font-extrabold">
{selectedBalance!.amount} {selectedBalance!.symbol} in Arbitrum
</h2>
</div>
</Card>
<Button
variant="purple"
shadowSize="4"
onClick={recoverFunds}
disabled={isLoading || isSigning}
loading={isLoading || isSigning}
className="w-full"
>
{isLoading ? loadingState : 'Confirm'}
</Button>
</div>
</div>
)
}

if (status === 'final') {
return (
<div className="flex min-h-[inherit] flex-col gap-8">
<div className="my-auto flex h-full flex-col justify-center space-y-4">
<Card className="flex items-center gap-3 p-4">
<div className="flex items-center gap-3">
<div
className={
'flex h-12 w-12 min-w-12 items-center justify-center rounded-full bg-success-3 font-bold'
}
>
<Image
src={selectedBalance!.logoURI}
alt={`${selectedBalance!.symbol} logo`}
width={24}
height={24}
className="rounded-full"
/>
</div>
</div>

<div className="space-y-1">
<h1 className="text-sm font-normal text-grey-1">
Sent to <AddressLink address={recipient.address} />
</h1>
<h2 className="text-2xl font-extrabold">
{selectedBalance!.amount} {selectedBalance!.symbol} in Arbitrum
</h2>
<a
href={`${getExplorerUrl(selectedBalance!.chainId)}/tx/${txHash}`}
target="_blank"
rel="noreferrer"
className="flex items-center gap-2 hover:underline"
>
<span>View on explorer</span>
<Icon name="external-link" />
</a>
</div>
</Card>
<Button
variant="purple"
shadowSize="4"
onClick={() => {
router.push('/home')
}}
className="w-full"
>
Go to home
</Button>
<Button
variant="stroke"
shadowSize="4"
onClick={() => {
setTokenBalances(tokenBalances.filter((b) => b.address !== selectedTokenAddress))
reset()
}}
className="w-full"
>
Recover other token
</Button>
</div>
</div>
)
}

return (
<div className="flex min-h-[inherit] flex-col gap-8">
<NavHeader title="Recover Funds" />
<div className="my-auto flex h-full flex-col justify-center space-y-4">
<h1> Select a token to recover </h1>
<ScrollableList>
{tokenBalances.length > 0 ? (
tokenBalances.map((balance) => (
<TokenListItem
key={balance.address}
balance={balance}
isSelected={areEvmAddressesEqual(balance.address, selectedTokenAddress)}
onClick={() => {
setSelectedTokenAddress(balance.address)
}}
/>
))
) : (
<div className="flex h-full w-full items-center justify-center">
<div className="text-center text-xl font-bold text-grey-1">No tokens to recover</div>
</div>
)}
</ScrollableList>
<GeneralRecipientInput
placeholder="Enter the address where you want to receive the funds"
recipient={recipient}
onUpdate={(update: GeneralRecipientUpdate) => {
setRecipient(update.recipient)
setErrorMessage(update.errorMessage)
setInputChanging(update.isChanging)
}}
/>
<Button
variant="purple"
shadowSize="4"
onClick={() => {
setStatus('review')
}}
disabled={
!!errorMessage ||
inputChanging ||
!recipient.address ||
!selectedBalance ||
selectedBalance.amount <= 0
}
loading={false}
className="w-full"
>
Review
</Button>
{!!errorMessage && <ErrorAlert description={errorMessage} />}
</div>
</div>
)
}
26 changes: 6 additions & 20 deletions src/components/AddMoney/components/CryptoMethodDrawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@

import { ARBITRUM_ICON, OTHER_CHAINS_ICON } from '@/assets'
import { Card } from '@/components/0_Bruddle'
import ActionModal from '@/components/Global/ActionModal'
import { Drawer, DrawerContent } from '@/components/Global/Drawer'
import { Slider } from '@/components/Slider'
import Image from 'next/image'
import { useRouter } from 'next/navigation'
import React, { Dispatch, SetStateAction, useState } from 'react'
import TokenAndNetworkConfirmationModal from '@/components/Global/TokenAndNetworkConfirmationModal'

const CryptoMethodDrawer = ({
isDrawerOpen,
Expand Down Expand Up @@ -83,28 +82,15 @@ const CryptoMethodDrawer = ({
</div>
</DrawerContent>
</Drawer>
<ActionModal
visible={showRiskModal}
<TokenAndNetworkConfirmationModal
onClose={() => {
setShowRiskModal(false)
setisDrawerOpen(true)
}}
icon={'alert'}
iconContainerClassName="bg-yellow-1"
modalClassName="z-[9999]"
title={`Only send USDC on Arbitrum`}
description={
<span className="text-sm">
Sending funds via any other network will result in a <b>permanent loss.</b>
</span>
}
footer={
<div className="w-full">
<Slider onValueChange={(v) => v && router.push('/add-money/crypto')} />
</div>
}
ctas={[]}
modalPanelClassName="max-w-xs"
onAccept={() => {
router.push('/add-money/crypto')
}}
isVisible={showRiskModal}
/>
</>
)
Expand Down
Loading
Loading