Skip to content

Commit

Permalink
feat: smart account creation (#2027)
Browse files Browse the repository at this point in the history
Co-authored-by: Luka Isailovic <[email protected]>
  • Loading branch information
tomiir and lukaisailovic authored Apr 1, 2024
1 parent da854da commit 75855d6
Show file tree
Hide file tree
Showing 48 changed files with 699 additions and 214 deletions.
2 changes: 2 additions & 0 deletions apps/laboratory/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@
"playwright:test:wallet": "playwright test --grep 'connect-qr.spec.ts|wallet.spec.ts'",
"playwright:test:email": "playwright test --grep 'email.spec.ts'",
"playwright:test:siwe": "playwright test --grep siwe.spec.ts",
"playwright:test:sa": "playwright test --grep smart-account.spec.ts",
"playwright:test:canary": "playwright test --retries=0 --grep canary.spec.ts --project='Desktop Chrome/wagmi'",
"playwright:debug": "npm run playwright:test -- --debug",
"playwright:debug:wallet": "npm run playwright:test:wallet -- --debug",
"playwright:debug:email": "npm run playwright:test:email -- --debug",
"playwright:debug:siwe": "npm run playwright:test:siwe -- --debug",
"playwright:debug:sa": "npm run playwright:test:sa -- --debug",
"playwright:debug:canary": "npm run playwright:test:canary -- --debug"
},
"dependencies": {
Expand Down
12 changes: 6 additions & 6 deletions apps/laboratory/src/components/Ethers/EthersTransactionTest.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Button, useToast, Stack, Link, Text, Spacer } from '@chakra-ui/react'
import { useWeb3ModalAccount, useWeb3ModalProvider } from '@web3modal/ethers/react'
import { BrowserProvider, JsonRpcSigner, ethers } from 'ethers'
import { sepolia } from '../../utils/ChainsUtil'
import { sepolia, optimism } from '../../utils/ChainsUtil'
import { useState } from 'react'
import { vitalikEthAddress } from '../../utils/DataUtil'

Expand All @@ -21,9 +21,7 @@ export function EthersTransactionTest() {
const signer = new JsonRpcSigner(provider, address)
const tx = await signer.sendTransaction({
to: vitalikEthAddress,
value: ethers.parseUnits('0.0001', 'gwei'),
maxFeePerGas: ethers.parseUnits('200', 'gwei'),
maxPriorityFeePerGas: ethers.parseUnits('200', 'gwei')
value: ethers.parseUnits('0.0001', 'gwei')
})
toast({ title: 'Succcess', description: tx.hash, status: 'success', isClosable: true })
} catch {
Expand All @@ -38,7 +36,9 @@ export function EthersTransactionTest() {
}
}

return chainId === sepolia.chainId && address ? (
const allowedChains = [sepolia.chainId, optimism.chainId]

return allowedChains.includes(Number(chainId)) && address ? (
<Stack direction={['column', 'column', 'row']}>
<Button
data-test-id="sign-transaction-button"
Expand All @@ -64,7 +64,7 @@ export function EthersTransactionTest() {
</Stack>
) : (
<Text fontSize="md" color="yellow">
Switch to Sepolia Ethereum Testnet to test this feature
Switch to Sepolia or OP to test this feature
</Text>
)
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Button, useToast, Stack, Link, Text, Spacer } from '@chakra-ui/react'
import { useWeb3ModalAccount, useWeb3ModalProvider } from '@web3modal/ethers/react'
import { BrowserProvider, JsonRpcSigner, ethers } from 'ethers'
import { sepolia } from '../../utils/ChainsUtil'
import { optimism, sepolia } from '../../utils/ChainsUtil'
import { useState } from 'react'

import { abi, address as donutAddress } from '../../utils/DonutContract'
Expand Down Expand Up @@ -35,8 +35,9 @@ export function EthersWriteContractTest() {
setLoading(false)
}
}
const allowedChains = [sepolia.chainId, optimism.chainId]

return chainId === sepolia.chainId && address ? (
return allowedChains.includes(Number(chainId)) && address ? (
<Stack direction={['column', 'column', 'row']}>
<Button
data-test-id="sign-transaction-button"
Expand All @@ -62,7 +63,7 @@ export function EthersWriteContractTest() {
</Stack>
) : (
<Text fontSize="md" color="yellow">
Switch to Sepolia Ethereum Testnet to test this feature
Switch to Sepolia or OP to test this feature
</Text>
)
}
26 changes: 14 additions & 12 deletions apps/laboratory/src/components/Wagmi/WagmiSendUSDCTest.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Button, useToast, Stack, Link, Text, Spacer, Input } from '@chakra-ui/react'
import { useAccount, useWriteContract } from 'wagmi'
import { useCallback, useState } from 'react'
import { sepolia } from 'wagmi/chains'
import { optimism, sepolia } from 'wagmi/chains'

const minTokenAbi = [
{
Expand Down Expand Up @@ -70,25 +70,27 @@ export function WagmiSendUSDCTest() {
})
}, [writeContract, address, amount])

return chain?.id === sepolia.id && status === 'connected' ? (
const allowedChains = [sepolia.id, optimism.id] as number[]

return allowedChains.includes(Number(chain?.id)) && status === 'connected' ? (
<Stack direction={['column', 'column', 'row']}>
<Spacer />
<Input placeholder="0xf34ffa..." onChange={e => setAddress(e.target.value)} value={address} />
<Input
placeholder="Units (1000000000 for 1 USDC)"
onChange={e => setAmount(e.target.value)}
value={amount}
type="number"
/>
<Button
data-test-id="sign-transaction-button"
onClick={onSendTransaction}
disabled={!writeContract}
isDisabled={isLoading}
width="80%"
>
Send USDC
</Button>

<Spacer />
<Input placeholder="0xf34ffa..." onChange={e => setAddress(e.target.value)} value={address} />
<Input
placeholder="Enter an amount"
onChange={e => setAmount(e.target.value)}
value={amount}
type="number"
/>
<Link isExternal href="https://faucet.circle.com">
<Button variant="outline" colorScheme="blue" isDisabled={isLoading}>
USDC Faucet
Expand All @@ -97,7 +99,7 @@ export function WagmiSendUSDCTest() {
</Stack>
) : (
<Text fontSize="md" color="yellow">
Switch to Sepolia Ethereum Testnet to test this feature
Switch to Sepolia or OP to test this feature
</Text>
)
}
10 changes: 6 additions & 4 deletions apps/laboratory/src/components/Wagmi/WagmiTransactionTest.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import { parseGwei, type Address } from 'viem'
import { useEstimateGas, useSendTransaction, useAccount } from 'wagmi'
import { vitalikEthAddress } from '../../utils/DataUtil'
import { useCallback, useState } from 'react'
import { sepolia } from 'wagmi/chains'
import { optimism, optimismSepolia, sepolia } from 'wagmi/chains'

const TEST_TX = {
to: vitalikEthAddress as Address,
value: parseGwei('0.3')
value: parseGwei('0.001')
}

export function WagmiTransactionTest() {
Expand Down Expand Up @@ -56,7 +56,9 @@ export function WagmiTransactionTest() {
}
}, [sendTransaction, prepareError])

return chain?.id === sepolia.id && status === 'connected' ? (
const allowedChains = [sepolia.id, optimism.id, optimismSepolia.id] as number[]

return allowedChains.includes(Number(chain?.id)) && status === 'connected' ? (
<Stack direction={['column', 'column', 'row']}>
<Button
data-test-id="sign-transaction-button"
Expand All @@ -83,7 +85,7 @@ export function WagmiTransactionTest() {
</Stack>
) : (
<Text fontSize="md" color="yellow">
Switch to Sepolia Ethereum Testnet to test this feature
Switch to Sepolia or OP to test this feature
</Text>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Button, useToast, Stack, Link, Text, Spacer, Flex } from '@chakra-ui/re
import { parseEther } from 'viem'
import { useAccount, useSimulateContract, useWriteContract, useReadContract } from 'wagmi'
import { useCallback, useEffect } from 'react'
import { sepolia } from 'wagmi/chains'
import { optimism, sepolia } from 'wagmi/chains'
import { abi, address } from '../../utils/DonutContract'

export function WagmiWriteContractTest() {
Expand Down Expand Up @@ -62,7 +62,9 @@ export function WagmiWriteContractTest() {
reset()
}, [data, error])

return chain?.id === sepolia.id && status === 'connected' ? (
const allowedChains = [sepolia.id, optimism.id] as number[]

return allowedChains.includes(Number(chain?.id)) && status === 'connected' ? (
<Stack direction={['column', 'column', 'row']}>
<Button
data-test-id="sign-transaction-button"
Expand Down Expand Up @@ -96,7 +98,7 @@ export function WagmiWriteContractTest() {
</Stack>
) : (
<Text fontSize="md" color="yellow">
Switch to Sepolia Ethereum Testnet to test this feature
Switch to Sepolia or OP to test this feature
</Text>
)
}
4 changes: 3 additions & 1 deletion apps/laboratory/src/utils/WagmiConstants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
zkSync,
zora,
sepolia,
optimismSepolia,
type Chain
} from 'wagmi/chains'

Expand All @@ -29,6 +30,7 @@ export const WagmiConstantsUtil = {
base,
celo,
aurora,
sepolia
sepolia,
optimismSepolia
] as [Chain, ...Chain[]]
}
63 changes: 63 additions & 0 deletions apps/laboratory/tests/shared/fixtures/w3m-smart-account-fixture.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { test as base } from '@playwright/test'
import type { ModalFixture } from './w3m-fixture'
import { DeviceRegistrationPage } from '../pages/DeviceRegistrationPage'
import { Email } from '../utils/email'
import { ModalWalletPage } from '../pages/ModalWalletPage'
import { ModalWalletValidator } from '../validators/ModalWalletValidator'

const mailsacApiKey = process.env['MAILSAC_API_KEY']
if (!mailsacApiKey) {
throw new Error('MAILSAC_API_KEY is not set')
}

// Test Modal + Smart Account
export const testModalSmartAccount = base.extend<ModalFixture>({
library: ['wagmi', { option: true }],
modalPage: async ({ page, library, context }, use, testInfo) => {
const modalPage = new ModalWalletPage(page, library)
await modalPage.load()

const email = new Email(mailsacApiKey)

const tempEmail = email.getEmailAddressToUse(testInfo.parallelIndex)

await email.deleteAllMessages(tempEmail)
await modalPage.loginWithEmail(tempEmail)

let messageId = await email.getLatestMessageId(tempEmail)

if (!messageId) {
throw new Error('No messageId found')
}
let emailBody = await email.getEmailBody(tempEmail, messageId)
let otp = ''
if (email.isApproveEmail(emailBody)) {
const url = email.getApproveUrlFromBody(emailBody)

await email.deleteAllMessages(tempEmail)

const drp = new DeviceRegistrationPage(await context.newPage(), url)
drp.load()
await drp.approveDevice()
await drp.close()

messageId = await email.getLatestMessageId(tempEmail)

emailBody = await email.getEmailBody(tempEmail, messageId)
if (!email.isApproveEmail(emailBody)) {
otp = email.getOtpCodeFromBody(emailBody)
}
}
if (otp.length !== 6) {
otp = email.getOtpCodeFromBody(emailBody)
}
await modalPage.enterOTP(otp)
await modalPage.switchNetwork('Sepolia')
await modalPage.page.waitForTimeout(1500)
await use(modalPage)
},
modalValidator: async ({ modalPage }, use) => {
const modalValidator = new ModalWalletValidator(modalPage.page)
await use(modalValidator)
}
})
12 changes: 10 additions & 2 deletions apps/laboratory/tests/shared/pages/ModalPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { expect } from '@playwright/test'
import { BASE_URL } from '../constants'
import { doActionAndWaitForNewPage } from '../utils/actions'

export type ModalFlavor = 'default' | 'siwe' | 'email'
export type ModalFlavor = 'default' | 'siwe' | 'email' | 'wallet'

export class ModalPage {
private readonly baseURL = BASE_URL
Expand Down Expand Up @@ -166,12 +166,20 @@ export class ModalPage {
await this.page.getByTestId('account-button').click()
await this.page.getByTestId('w3m-account-select-network').click()
await this.page.getByTestId(`w3m-network-switch-${network}`).click()
await this.page.getByTestId(`w3m-header-close`).click()
await this.page.getByTestId('w3m-header-close').click()
}

async clickWalletDeeplink() {
await this.connectButton.click()
await this.page.getByTestId('wallet-selector-react-wallet-v2').click()
await this.page.getByTestId('tab-desktop').click()
}

async openAccount() {
await this.page.getByTestId('account-button').click()
}

async closeModal() {
await this.page.getByTestId('w3m-header-close')?.click?.()
}
}
32 changes: 32 additions & 0 deletions apps/laboratory/tests/shared/pages/ModalWalletPage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/* eslint-disable no-await-in-loop */
import type { Page } from '@playwright/test'
import { ModalPage } from './ModalPage'

export class ModalWalletPage extends ModalPage {
constructor(
public override readonly page: Page,
public override readonly library: string
) {
super(page, library, 'wallet')
}

async openSettings() {
await this.page.getByTestId('account-button').click()
await this.page.getByTestId('wui-profile-button').click()
}

override async switchNetwork(network: string) {
await this.openSettings()
await this.page.getByTestId('account-switch-network-button').click()
await this.page.getByTestId(`w3m-network-switch-${network}`).click()
await this.page.getByTestId('w3m-header-close').click()
await this.page.waitForTimeout(2000)
}

async togglePreferredAccountType() {
await this.openSettings()
await this.page.getByTestId('account-toggle-preferred-account-type').click()
await this.page.getByTestId('w3m-header-close').click()
await this.page.waitForTimeout(2000)
}
}
18 changes: 9 additions & 9 deletions apps/laboratory/tests/shared/utils/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ interface UseOptions {
}

interface CustomProperties {
testIgnore?: string
testIgnore?: RegExp | string
testMatch?: string
useOptions?: UseOptions
grep?: RegExp
Expand All @@ -36,32 +36,32 @@ const braveOptions: UseOptions = {

const customProjectProperties: CustomProjectProperties = {
'Desktop Brave/wagmi': {
testIgnore: 'email.spec.ts',
testIgnore: /(?:email\.spec\.ts|smart-account\.spec\.ts).*$/u,
useOptions: braveOptions
},
'Desktop Brave/ethers': {
testIgnore: 'email.spec.ts',
testIgnore: /(?:email\.spec\.ts|smart-account\.spec\.ts).*$/u,
useOptions: braveOptions
},
'Desktop Chrome/wagmi': {
testIgnore: 'email.spec.ts'
testIgnore: /(?:email\.spec\.ts|smart-account\.spec\.ts).*$/u
},
'Desktop Firefox/wagmi': {
testIgnore: 'email.spec.ts'
testIgnore: /(?:email\.spec\.ts|smart-account\.spec\.ts).*$/u
},
// Exclude email.spec.ts, siwe.spec.ts, and canary.spec.ts from solana, not yet implemented
'Desktop Chrome/solana': {
grep: /^(?!.*(?:email\.spec\.ts|siwe\.spec\.ts|canary\.spec\.ts)).*$/u
grep: /^(?!.*(?:email\.spec\.ts|siwe\.spec\.ts|canary\.spec\.ts|smart-account\.spec\.ts)).*$/u
},
'Desktop Brave/solana': {
useOptions: braveOptions,
grep: /^(?!.*(?:email\.spec\.ts|siwe\.spec\.ts|canary\.spec\.ts)).*$/u
grep: /^(?!.*(?:email\.spec\.ts|siwe\.spec\.ts|canary\.spec\.ts|smart-account\.spec\.ts)).*$/u
},
'Desktop Firefox/solana': {
grep: /^(?!.*(?:email\.spec\.ts|siwe\.spec\.ts|canary\.spec\.ts)).*$/u
grep: /^(?!.*(?:email\.spec\.ts|siwe\.spec\.ts|canary\.spec\.ts|smart-account\.spec\.ts)).*$/u
},
'Desktop Safari/solana': {
grep: /^(?!.*(?:email\.spec\.ts|siwe\.spec\.ts|canary\.spec\.ts)).*$/u
grep: /^(?!.*(?:email\.spec\.ts|siwe\.spec\.ts|canary\.spec\.ts|smart-account\.spec\.ts)).*$/u
}
}

Expand Down
Loading

0 comments on commit 75855d6

Please sign in to comment.