diff --git a/apps/next/pages/_app.tsx b/apps/next/pages/_app.tsx
index e110ddaf9..aa37944fc 100644
--- a/apps/next/pages/_app.tsx
+++ b/apps/next/pages/_app.tsx
@@ -10,11 +10,11 @@ import type { AuthProviderProps } from 'app/provider/auth'
import { api } from 'app/utils/api'
import type { NextPage } from 'next'
import Head from 'next/head'
-import type { ReactElement, ReactNode } from 'react'
+import { useEffect, type ReactElement, type ReactNode } from 'react'
import type { SolitoAppProps } from 'solito'
import { Provider } from 'app/provider'
import { projectId, config as wagmiConfig } from 'app/provider/wagmi/config'
-import { createWeb3Modal } from '@web3modal/wagmi/react'
+import { createWeb3Modal, useWeb3ModalTheme } from '@web3modal/wagmi/react'
import { baseMainnetClient } from '@my/wagmi'
import { YStack, H1, H2 } from '@my/ui'
import { IconSendLogo } from 'app/components/icons'
@@ -23,6 +23,23 @@ createWeb3Modal({
wagmiConfig,
projectId,
defaultChain: baseMainnetClient.chain,
+ themeVariables: {
+ '--w3m-accent': '#86AE80',
+ },
+ tokens: {
+ 8453: {
+ address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
+ },
+ 845337: {
+ address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
+ },
+ 1: {
+ address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
+ },
+ 1337: {
+ address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
+ },
+ },
})
if (process.env.NODE_ENV === 'production') {
@@ -40,7 +57,12 @@ function MyApp({
// reference: https://nextjs.org/docs/pages/building-your-application/routing/pages-and-layouts
const getLayout = Component.getLayout || ((page) => page)
- const [, setTheme] = useRootTheme()
+ const [theme, setTheme] = useRootTheme()
+ const { setThemeMode } = useWeb3ModalTheme()
+
+ useEffect(() => {
+ setThemeMode(theme)
+ }, [theme, setThemeMode])
return (
<>
diff --git a/packages/app/features/deposit/web3/__snapshots__/screen.test.tsx.snap b/packages/app/features/deposit/web3/__snapshots__/screen.test.tsx.snap
index 267474384..6bcb940fd 100644
--- a/packages/app/features/deposit/web3/__snapshots__/screen.test.tsx.snap
+++ b/packages/app/features/deposit/web3/__snapshots__/screen.test.tsx.snap
@@ -1,388 +1,375 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`DepositWeb3Screen renders the connect to deposit when wallet is not connected 1`] = `
-
-
- Connect to Deposit
-
-
- You need to connect to a wallet to deposit funds.
-
-
+ Connect to Deposit
+
+
-
+ You need to connect to a wallet to deposit funds.
+
+
+
+
+ Or direct deposit on base
+
+
-
-
-
+ 0xb0b...0000
+
+
-
-
-
-
+
-
-
+
-
-
-
-
-
-
-
-
+
+
+
+
+ ,
+
-
- Connect to Deposit
-
-
-
-`;
-
-exports[`DepositWeb3Screen renders the deposit web3 form when wallet is connected 1`] = `
-[
-
-
-
-
-
-
- Depositing from
- 0x123
-
-
+
+
+
+ ,
+]
+`;
+
+exports[`DepositWeb3Screen renders the deposit web3 form when wallet is connected 1`] = `
+[
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Send recommends depositing USDC first. This will ensure a smooth sending experience throughout the app
+
+
Token
-
+
+ USDC
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Amount
@@ -894,16 +852,6 @@ exports[`DepositWeb3Screen renders the deposit web3 form when wallet is connecte
"value": undefined,
},
},
- "token": {
- "_f": {
- "mount": true,
- "name": "token",
- "ref": {
- "name": "token",
- },
- "value": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
- },
- },
},
"_formState": {
"dirtyFields": {},
@@ -930,7 +878,6 @@ exports[`DepositWeb3Screen renders the deposit web3 form when wallet is connecte
"array": Set {},
"focus": "",
"mount": Set {
- "token",
"amount",
},
"unMount": Set {},
@@ -982,9 +929,6 @@ exports[`DepositWeb3Screen renders the deposit web3 form when wallet is connecte
{
"next": [Function],
},
- {
- "next": [Function],
- },
],
"subscribe": [Function],
"unsubscribe": [Function],
@@ -995,9 +939,6 @@ exports[`DepositWeb3Screen renders the deposit web3 form when wallet is connecte
{
"next": [Function],
},
- {
- "next": [Function],
- },
],
"subscribe": [Function],
"unsubscribe": [Function],
@@ -1016,7 +957,7 @@ exports[`DepositWeb3Screen renders the deposit web3 form when wallet is connecte
}
focusVisibleStyle={{}}
focusable={true}
- id=":r8:"
+ id=":r3:"
name="amount"
onBlur={[Function]}
onChangeText={[Function]}
@@ -1051,6 +992,7 @@ exports[`DepositWeb3Screen renders the deposit web3 form when wallet is connecte
"position": "relative",
}
}
+ testID="amountInput"
value=""
/>
@@ -1065,25 +1007,6 @@ exports[`DepositWeb3Screen renders the deposit web3 form when wallet is connecte
}
/>
-
- Balance:
-
- >0.00
-
- USDC
-
@@ -1115,359 +1038,31 @@ exports[`DepositWeb3Screen renders the deposit web3 form when wallet is connecte
-
-
-
-
- Deposit
-
-
-
-
-
- View
- 0x123
- on
-
- Basescan
-
-
-
-
-
-
-
-
- ,
-
-
-
-
-
- ,
-
-
-
-
-
-
- USDC
-
-
-
-
-
- ETH
+ suppressHighlighting={true}
+ >
+ Deposit USDC
+
-
- SEND
+ View
+ 0x123
+ on
+
+ Basescan
@@ -1671,6 +1171,76 @@ exports[`DepositWeb3Screen renders the deposit web3 form when wallet is connecte
+
+ ,
+
+
+
-
-
-
-
-
-
-
-
- Switch
-
-
+
`;
diff --git a/packages/app/features/deposit/web3/screen.test.tsx b/packages/app/features/deposit/web3/screen.test.tsx
index 0da6b9d50..065e5ead3 100644
--- a/packages/app/features/deposit/web3/screen.test.tsx
+++ b/packages/app/features/deposit/web3/screen.test.tsx
@@ -10,6 +10,16 @@ jest.mock('wagmi')
jest.mock('@my/wagmi')
jest.mock('@web3modal/wagmi/react')
+jest.mock('app/utils/useSendAccountBalances', () => ({
+ useSendAccountBalances: jest.fn().mockReturnValue({
+ balances: {
+ 0: { result: 0n },
+ 1: { result: 1n },
+ },
+ totalBalance: () => 1n,
+ }),
+}))
+
const { useAccount, useSendTransaction, useBalance, useSwitchAccount } =
wagmi as unknown as typeof import('app/__mocks__/wagmi')
const { useWriteErc20Transfer } = myWagmi as unknown as typeof import('app/__mocks__/@my/wagmi')
@@ -77,11 +87,14 @@ describe('DepositWeb3Screen', () => {
)
- await waitFor(() => expect(screen.getByText(`Depositing from ${'0x123'}`)).toBeVisible())
+ await waitFor(() => expect(screen.getByTestId('DepositWeb3ScreenBefore')).toBeVisible())
+ const usdcLabel = screen.getByTestId('noUsdc')
+ await waitFor(() => expect(usdcLabel).toBeVisible())
+
expect(screen).toMatchSnapshot()
const user = userEvent.setup()
- await user.type(screen.getByLabelText('Amount'), '0.01')
- const depositButton = screen.getByRole('button', { name: 'Deposit' })
+ await user.type(screen.getByTestId('amountInput'), '0.01')
+ const depositButton = screen.getByRole('button', { name: 'Deposit USDC' })
await act(async () => {
// await user.press(depositButton) // something about tamagui button is causing this to fail
await depositButton.props.onPress()
@@ -101,14 +114,10 @@ describe('DepositWeb3Screen', () => {
)
- // screen.debug({ message: 'DepositWeb3Screen: render' })
await waitFor(() =>
expect(screen.getByRole('header', { name: 'Connect to Deposit' })).toBeVisible()
)
expect(screen).toMatchSnapshot()
- const user = userEvent.setup()
- await user.press(screen.getByRole('button', { name: 'Connect to Deposit' }))
- expect(useWeb3Modal).toHaveBeenCalled()
})
it('renders the switch network screen when base network is not selected', async () => {
useAccount.mockReturnValue({
@@ -133,11 +142,6 @@ describe('DepositWeb3Screen', () => {
)
- const switchNetworkButton = screen.getByRole('button', { name: 'Switch' })
- await waitFor(() => expect(switchNetworkButton).toBeVisible())
expect(screen).toMatchSnapshot()
- const user = userEvent.setup()
- await user.press(switchNetworkButton)
- expect(useWeb3Modal).toHaveBeenCalled()
})
})
diff --git a/packages/app/features/deposit/web3/screen.tsx b/packages/app/features/deposit/web3/screen.tsx
index f86167ba9..77c444f69 100644
--- a/packages/app/features/deposit/web3/screen.tsx
+++ b/packages/app/features/deposit/web3/screen.tsx
@@ -16,7 +16,7 @@ import {
import { baseMainnet, useWriteErc20Transfer } from '@my/wagmi'
import { useWeb3Modal } from '@web3modal/wagmi/react'
import { DepositAddress } from 'app/components/DepositAddress'
-import { IconEthereum, IconRefresh } from 'app/components/icons'
+import { IconInfoCircle, IconRefresh } from 'app/components/icons'
import { IconChainBase } from 'app/components/icons/IconChainBase'
import { coins } from 'app/data/coins'
import { SchemaForm, formFields } from 'app/utils/SchemaForm'
@@ -24,6 +24,7 @@ import { assert } from 'app/utils/assert'
import formatAmount from 'app/utils/formatAmount'
import { useSendAccount } from 'app/utils/send-accounts'
import { shorten } from 'app/utils/strings'
+import { useSendAccountBalances } from 'app/utils/useSendAccountBalances'
import { useEffect, useState } from 'react'
import { useForm } from 'react-hook-form'
import { Link } from 'solito/link'
@@ -44,15 +45,8 @@ import { z } from 'zod'
* 3. Sign transaction
*/
export function DepositWeb3Screen() {
- const { open: openConnectModal } = useWeb3Modal()
const { isConnected, chainId, chain } = useAccount()
- useEffect(() => {
- if (!isConnected) {
- openConnectModal?.()
- }
- }, [isConnected, openConnectModal])
-
if (!isConnected) {
return (
@@ -62,14 +56,9 @@ export function DepositWeb3Screen() {
You need to connect to a wallet to deposit funds.
- }
- onPress={() => openConnectModal()}
- maxWidth={'$20'}
- >
- Connect to Deposit
-
+
+
+
)
}
@@ -83,14 +72,7 @@ export function DepositWeb3Screen() {
You are currently on {chain?.name}. Switch to {baseMainnet.name} to deposit funds.
- }
- onPress={() => openConnectModal({ view: 'Networks' })}
- maxWidth={'$20'}
- >
- Switch
-
+
)
}
@@ -102,6 +84,17 @@ export function DepositWeb3Screen() {
)
}
+function DepositAddressWrapper() {
+ const { data: sendAccount } = useSendAccount()
+
+ return (
+
+ Or direct deposit on base
+
+
+ )
+}
+
const schema = z.object({
token: formFields.select.describe('Token'),
amount: formFields.text.describe('Amount'),
@@ -114,6 +107,8 @@ function DepositForm() {
const options = coins.map((coin) => ({ name: coin.symbol, value: coin.token }))
const first = options[0]
assert(!!first, 'first coin not found')
+ const { balances } = useSendAccountBalances()
+ const sendUSDCBalance = balances?.[0]?.result
const coin = coins.find((coin) => coin.token === form.watch('token'))
const isCoinSelected = !!coin
@@ -270,6 +265,7 @@ function DepositForm() {
},
amount: {
autoFocus: true,
+ testID: 'amountInput',
},
}}
formProps={{
@@ -282,18 +278,8 @@ function DepositForm() {
}}
renderBefore={() => (
-
-
- Depositing from {account}
-
-
-
- Or direct deposit on base
-
-
+
+
)}
renderAfter={({ submit }) => (
@@ -339,7 +325,7 @@ function DepositForm() {
br={12}
>
- {isLoadingReceipt ? 'Depositing...' : 'Deposit'}
+ {isLoadingReceipt ? 'Depositing...' : `Deposit ${coin?.symbol}`}
@@ -360,17 +346,36 @@ function DepositForm() {
>
{({ token, amount }) => (
+ {!sendUSDCBalance && (
+
+
+
+ Send recommends depositing USDC first. This will ensure a smooth sending experience
+ throughout the app
+
+
+ )}
- {token}
+ {sendUSDCBalance ? (
+ token
+ ) : (
+
+
+ Token
+
+
+ USDC
+
+
+ )}
{amount}
- {depositorBalance?.value !== undefined && !!coin ? (
-
- Balance:{' '}
- {formatAmount(formatUnits(depositorBalance?.value ?? 0n, coin?.decimals ?? 0))}{' '}
- {coin?.symbol}
-
- ) : null}
diff --git a/packages/playwright/tests/deposit.onboarded.spec.ts b/packages/playwright/tests/deposit.onboarded.spec.ts
index 4e1ee3cc2..8bd1d1f4a 100644
--- a/packages/playwright/tests/deposit.onboarded.spec.ts
+++ b/packages/playwright/tests/deposit.onboarded.spec.ts
@@ -72,7 +72,8 @@ test('can deposit USDC with web3 wallet', async ({
await depositWeb3Link.click()
await page.waitForURL('/deposit/web3')
await expect(page.locator('w3m-modal')).toBeVisible()
-
+ const connectButton = await page.locator('w3m-button')
+ await connectButton.click()
await page.locator('w3m-connect-injected-widget').click()
await expect
@@ -102,9 +103,7 @@ test('can deposit USDC with web3 wallet', async ({
.toBe(1)
await wallet.authorize(HeadlessWeb3Provider.Web3RequestKind.RequestAccounts)
- await expect(
- page.getByRole('heading', { name: `Depositing from ${account.address}` })
- ).toBeVisible()
+ await expect(page.getByText('10 USDC')).toBeVisible()
expect(await page.getByLabel('Token').inputValue()).toBe(usdcAddress[testBaseClient.chain.id])
await page.getByLabel('Amount').fill('10')
@@ -209,7 +208,8 @@ test('can deposit ETH with web3 wallet', async ({
await depositWeb3Button.click()
await page.waitForURL('/deposit/web3')
await expect(page.locator('w3m-modal')).toBeVisible()
-
+ const connectButton = await page.locator('w3m-button')
+ await connectButton.click()
await page.locator('w3m-connect-injected-widget').click()
await expect
@@ -239,10 +239,6 @@ test('can deposit ETH with web3 wallet', async ({
.toBe(1)
await wallet.authorize(HeadlessWeb3Provider.Web3RequestKind.RequestAccounts)
- await expect(
- page.getByRole('heading', { name: `Depositing from ${account.address}` })
- ).toBeVisible()
-
const tokenSelect = page.getByLabel('Token')
await page.getByLabel('Token').selectOption('eth')
expect(await tokenSelect.inputValue()).toBe('eth')
@@ -290,3 +286,120 @@ test('can deposit ETH with web3 wallet', async ({
timeout: 10000,
})
})
+
+test('can connect and disconnect using wallet button', async ({
+ page,
+ injectWeb3Provider,
+ accounts,
+ user: { profile },
+ supabase,
+}) => {
+ log = debug(`test:activity:${profile.id}:${test.info().parallelIndex}`)
+ const { data: sendAccount, error } = await supabase.from('send_accounts').select('*').single()
+ expect(error).toBeFalsy()
+ assert(!!sendAccount, 'no send account found')
+
+ const wallet = await injectWeb3Provider()
+ const account = accounts[0]
+ assert(!!account, 'no web3 accounts found')
+ log('account', account)
+
+ await page.goto('/deposit/web3')
+
+ const connectButton = await page.locator('w3m-button')
+ expect(connectButton).toHaveText('Connect Wallet')
+ await connectButton.click()
+ await page.locator('w3m-connect-injected-widget').click()
+
+ await expect
+ .poll(
+ async () => {
+ return wallet.getPendingRequestCount(
+ HeadlessWeb3Provider.Web3RequestKind.RequestPermissions
+ )
+ },
+ {
+ timeout: 5000,
+ message: 'Did not receive accounts request',
+ }
+ )
+ .toBe(1)
+ await wallet.authorize(HeadlessWeb3Provider.Web3RequestKind.RequestPermissions)
+ await expect
+ .poll(
+ async () => {
+ return wallet.getPendingRequestCount(HeadlessWeb3Provider.Web3RequestKind.RequestAccounts)
+ },
+ {
+ timeout: 5000,
+ message: 'Did not receive accounts request',
+ }
+ )
+ .toBe(1)
+ await wallet.authorize(HeadlessWeb3Provider.Web3RequestKind.RequestAccounts)
+ const walletButton = page.getByTestId('account-button')
+ await expect(walletButton).toBeVisible()
+ await walletButton.click()
+ await page.getByRole('button', { name: 'Disconnect' }).click()
+ expect(page.locator('w3m-button')).toHaveText('Connect Wallet')
+})
+
+test('must switch to supported network', async ({
+ page,
+ injectWeb3Provider,
+ accounts,
+ user: { profile },
+ supabase,
+}) => {
+ log = debug(`test:activity:${profile.id}:${test.info().parallelIndex}`)
+ const { data: sendAccount, error } = await supabase.from('send_accounts').select('*').single()
+ expect(error).toBeFalsy()
+ assert(!!sendAccount, 'no send account found')
+
+ const wallet = await injectWeb3Provider()
+ const account = accounts[0]
+ assert(!!account, 'no web3 accounts found')
+ log('account', account)
+
+ await page.goto('/deposit/web3')
+
+ const walletButton = page.locator('w3m-button')
+ expect(walletButton).toHaveText('Connect Wallet')
+ await walletButton.click()
+ await page.locator('w3m-connect-injected-widget').click()
+
+ await expect
+ .poll(
+ async () => {
+ return wallet.getPendingRequestCount(
+ HeadlessWeb3Provider.Web3RequestKind.RequestPermissions
+ )
+ },
+ {
+ timeout: 5000,
+ message: 'Did not receive accounts request',
+ }
+ )
+ .toBe(1)
+ await wallet.authorize(HeadlessWeb3Provider.Web3RequestKind.RequestPermissions)
+ await expect
+ .poll(
+ async () => {
+ return wallet.getPendingRequestCount(HeadlessWeb3Provider.Web3RequestKind.RequestAccounts)
+ },
+ {
+ timeout: 5000,
+ message: 'Did not receive accounts request',
+ }
+ )
+ .toBe(1)
+ await wallet.authorize(HeadlessWeb3Provider.Web3RequestKind.RequestAccounts)
+
+ await expect(walletButton).toContainText('0.000')
+
+ wallet.addNetwork(1, 'https://eth.public-rpc.com')
+ wallet.switchNetwork(1)
+ await expect(page.getByTestId('account-button')).toContainText('Switch Network')
+ await expect(page.getByRole('heading', { name: 'Switch to Base Localhost' })).toBeVisible()
+ await expect(page.getByTestId('SubmitButton')).toHaveCount(0)
+})