Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: custom 5792 transactions #2666

Merged
merged 13 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from 11 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
4 changes: 2 additions & 2 deletions apps/laboratory/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@
"@tanstack/react-query": "5.24.8",
"@wagmi/connectors": "5.1.9",
"@wagmi/core": "2.13.4",
"@walletconnect/universal-provider": "2.16.1",
"@walletconnect/utils": "2.16.1",
"@walletconnect/universal-provider": "2.16.2",
"@walletconnect/utils": "2.16.2",
"@reown/appkit": "workspace:*",
"@reown/appkit-ethers": "workspace:*",
"@reown/appkit-ethers5": "workspace:*",
Expand Down
94 changes: 94 additions & 0 deletions apps/laboratory/src/components/AddTransactionModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import {
Box,
Button,
Input,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalFooter,
ModalHeader,
ModalOverlay
} from '@chakra-ui/react'
import { useCallback, useState } from 'react'
import { ethers } from 'ethers'
import { useChakraToast } from './Toast'

type IAddTransactionModalProps = {
isOpen: boolean
onClose: () => void
onSubmit: (params: { eth: string; to: string }) => void
}
export function AddTransactionModal(props: IAddTransactionModalProps) {
const toast = useChakraToast()
const { isOpen, onClose, onSubmit } = props
const [eth, setEth] = useState(0)
const [to, setTo] = useState('')
const onAddTransaction = useCallback(() => {
ganchoradkov marked this conversation as resolved.
Show resolved Hide resolved
if (!ethers.isAddress(to)) {
toast({
title: 'Error',
description: 'Invalid address',
type: 'error'
})

return
}
if (!eth || isNaN(eth)) {
toast({
title: 'Error',
description: 'Invalid ETH amount',
type: 'error'
})

return
}
onSubmit({ eth: eth.toString(), to })
reset()
onClose()
}, [eth, to])

const reset = useCallback(() => {
ganchoradkov marked this conversation as resolved.
Show resolved Hide resolved
setEth(0)
setTo('')
}, [])

return (
<>
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay />
<ModalContent>
<ModalHeader>Add a transaction</ModalHeader>
<ModalCloseButton />
<ModalBody>
Transactions will be batched and sent together to your wallet for approval
<Box mt={4}>
<label>Amount ETH</label>
<Input
placeholder="0.001"
type="number"
onChange={event => setEth(parseFloat(event.target.value))}
ganchoradkov marked this conversation as resolved.
Show resolved Hide resolved
/>
</Box>
<Box mt={4}>
<label>To</label>
<Input
placeholder="0x0..."
type="text"
onChange={event => setTo(event.target.value)}
/>
</Box>
</ModalBody>
<ModalFooter>
<Button variant="ghost" mr={3} onClick={onClose}>
Cancel
</Button>
<Button colorScheme="blue" onClick={onAddTransaction}>
Add
</Button>
</ModalFooter>
</ModalContent>
</Modal>
</>
)
}
5 changes: 3 additions & 2 deletions apps/laboratory/src/components/Ethers/Ethers5Tests.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { EthersSendCallsWithPaymasterServiceTest } from './EthersSendCallsWithPa

export function Ethers5Tests() {
const [ready, setReady] = React.useState(false)
const [callsHash, setCallsHash] = React.useState<string>('')
const { isConnected } = useAppKitAccount()

React.useEffect(() => {
Expand Down Expand Up @@ -59,13 +60,13 @@ export function Ethers5Tests() {
<Heading size="xs" textTransform="uppercase" pb="2">
Send Calls (Atomic Batch)
</Heading>
<EthersSendCallsTest />
<EthersSendCallsTest onCallsHash={setCallsHash} />
</Box>
<Box>
<Heading size="xs" textTransform="uppercase" pb="2">
Get Calls Status
</Heading>
<EthersGetCallsStatusTest />
<EthersGetCallsStatusTest callsHash={callsHash} />
</Box>
<Box>
<Heading size="xs" textTransform="uppercase" pb="2">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Button, Stack, Text, Input } from '@chakra-ui/react'
import { useState } from 'react'
import { useEffect, useState } from 'react'
import {
useAppKitAccount,
useAppKitNetwork,
Expand All @@ -13,15 +13,20 @@ import { W3mFrameProvider } from '@reown/appkit-wallet'
import { type GetCallsStatusParams } from '../../types/EIP5792'
import { EIP_5792_RPC_METHODS } from '../../utils/EIP5792Utils'

export function EthersGetCallsStatusTest() {
export function EthersGetCallsStatusTest(params: { callsHash: string }) {
ganchoradkov marked this conversation as resolved.
Show resolved Hide resolved
const callsHash = params.callsHash
const [isLoading, setLoading] = useState(false)
const [batchCallId, setBatchCallId] = useState('')
const [batchCallId, setBatchCallId] = useState(callsHash)
ganchoradkov marked this conversation as resolved.
Show resolved Hide resolved

const { chainId } = useAppKitNetwork()
const { address, isConnected } = useAppKitAccount()
const { walletProvider } = useAppKitProvider<Provider>('eip155')
const toast = useChakraToast()

useEffect(() => {
setBatchCallId(callsHash)
}, [callsHash])

async function onGetCallsStatus() {
try {
setLoading(true)
Expand Down
113 changes: 98 additions & 15 deletions apps/laboratory/src/components/Ethers/EthersSendCallsTest.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,61 @@
import {
Box,
Link,
Stat,
StatLabel,
StatNumber,
StatHelpText,
Card,
CardBody
} from '@chakra-ui/react'
import { useCallback, useState, useEffect } from 'react'
import { Button, Stack, Text, Spacer, Heading } from '@chakra-ui/react'
import { useState, useEffect } from 'react'
import { useAppKitAccount, useAppKitNetwork, useAppKitProvider } from '@reown/appkit/react'
import { UniversalProvider } from '@walletconnect/universal-provider'
import { useChakraToast } from '../Toast'
import type { Address } from 'viem'
import { parseGwei, type Address } from 'viem'
import { vitalikEthAddress } from '../../utils/DataUtil'
import { BrowserProvider, type Eip1193Provider } from 'ethers'
import {
EIP_5792_RPC_METHODS,
WALLET_CAPABILITIES,
getCapabilitySupportedChainInfo
} from '../../utils/EIP5792Utils'
import { AddIcon, DeleteIcon } from '@chakra-ui/icons'
import { AddTransactionModal } from '../AddTransactionModal'
import { W3mFrameProvider } from '@reown/appkit-wallet'
type Provider = W3mFrameProvider | Awaited<ReturnType<(typeof UniversalProvider)['init']>>

export function EthersSendCallsTest() {
export function EthersSendCallsTest(params: { onCallsHash: (hash: string) => void }) {
const { onCallsHash } = params
ganchoradkov marked this conversation as resolved.
Show resolved Hide resolved

const [loading, setLoading] = useState(false)

const { chainId } = useAppKitNetwork()
const { address, isConnected } = useAppKitAccount()
const { walletProvider } = useAppKitProvider<Eip1193Provider>('eip155')
const [transactionsToBatch, setTransactionsToBatch] = useState<{ value: string; to: string }[]>(
[]
)
const toast = useChakraToast()

const [isOpen, setIsOpen] = useState(false)
const onSubmit = useCallback(
(args: { to: string; eth: string }) => {
setLastCallsBatchId(null)
setTransactionsToBatch(prev => [
...prev,
{
to: args.to as `0x${string}`,
data: '0x' as `0x${string}`,
value: `0x${parseGwei(args.eth).toString(16)}`
}
])
},
[transactionsToBatch]
)
const onClose = useCallback(() => setIsOpen(false), [])
ganchoradkov marked this conversation as resolved.
Show resolved Hide resolved

const [atomicBatchSupportedChains, setAtomicBatchSupportedChains] = useState<
Awaited<ReturnType<typeof getCapabilitySupportedChainInfo>>
>([])
Expand All @@ -47,6 +81,14 @@ export function EthersSendCallsTest() {
chainInfo => chainInfo.chainId === Number(chainId)
)

const onAddTransactionButtonClick = useCallback(() => {
setIsOpen(true)
}, [])

const onRemoveTransaction = useCallback((index: number) => {
setTransactionsToBatch(prev => prev.filter((_, i) => i !== index))
}, [])

async function onSendCalls() {
try {
setLoading(true)
Expand All @@ -73,7 +115,7 @@ export function EthersSendCallsTest() {
version: '1.0',
chainId: `0x${BigInt(chainId).toString(16)}`,
from: address,
calls
calls: transactionsToBatch.length ? transactionsToBatch : calls
}
const batchCallHash = await provider.send(EIP_5792_RPC_METHODS.WALLET_SEND_CALLS, [
sendCallsParams
Expand All @@ -85,6 +127,8 @@ export function EthersSendCallsTest() {
description: batchCallHash,
type: 'success'
})
setTransactionsToBatch([])
onCallsHash(batchCallHash)
} catch {
toast({
title: 'Error',
Expand Down Expand Up @@ -133,23 +177,62 @@ export function EthersSendCallsTest() {
}

return currentChainsInfo ? (
<Stack direction={['column', 'column']}>
<Button
data-testid="send-calls-button"
onClick={onSendCalls}
isDisabled={loading}
maxWidth={'50%'}
>
Send Batch Calls to Vitalik
</Button>
<Spacer />
<>
<Box>
<Stack direction={['column', 'column', 'row']}>
<Stack direction={['column']}>
(
{transactionsToBatch.length ? (
transactionsToBatch.map((tx, index) => (
<>
<Card>
<CardBody>
<Stat>
<StatLabel>
({index + 1}) Sending
<DeleteIcon
style={{ float: 'right', cursor: 'pointer' }}
onClick={() => onRemoveTransaction(index)}
ganchoradkov marked this conversation as resolved.
Show resolved Hide resolved
/>
</StatLabel>
<StatNumber>{parseInt(tx.value, 16) / 1000000000} ETH</StatNumber>
<StatHelpText>to {tx.to}</StatHelpText>
</Stat>
</CardBody>
</Card>{' '}
<Spacer />
</>
))
) : (
<Button data-test-id="send-calls-button" onClick={onSendCalls} isDisabled={loading}>
Send Batch Calls to Vitalik
</Button>
)}
)
</Stack>
<Spacer />
<Link onClick={onAddTransactionButtonClick}>
<Button variant="outline" colorScheme="blue" isDisabled={loading}>
<AddIcon mr={2} /> Add Transaction
</Button>
</Link>
</Stack>
{transactionsToBatch.length ? (
<Button data-test-id="send-calls-button" onClick={onSendCalls} isDisabled={loading}>
Send Calls
</Button>
) : null}
</Box>
<AddTransactionModal isOpen={isOpen} onSubmit={onSubmit} onClose={onClose} />

<Spacer m={2} />
{lastCallsBatchId && (
<>
<Heading size="xs">Last batch call ID:</Heading>
<Text data-testid="send-calls-id">{lastCallsBatchId}</Text>
</>
)}
</Stack>
</>
) : (
<Text fontSize="md" color="yellow">
Switch to {atomicBatchSupportedChainsNames} to test atomic batch feature
Expand Down
16 changes: 14 additions & 2 deletions apps/laboratory/src/components/Ethers/EthersTests.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,20 @@ import { EthersSendCallsWithPaymasterServiceTest } from './EthersSendCallsWithPa

export function EthersTests() {
const [ready, setReady] = React.useState(false)

const [callsHash, setCallsHash] = React.useState<string>('')
const { isConnected } = useAppKitAccount()

const onCallsHash = React.useCallback((hash: string) => {
setCallsHash(hash)
}, [])

React.useEffect(() => {
if (!isConnected) {
setCallsHash('')
}
}, [isConnected])

React.useEffect(() => {
setReady(true)
}, [])
Expand Down Expand Up @@ -59,13 +71,13 @@ export function EthersTests() {
<Heading size="xs" textTransform="uppercase" pb="2">
Send Calls (Atomic Batch)
</Heading>
<EthersSendCallsTest />
<EthersSendCallsTest onCallsHash={onCallsHash} />
</Box>
<Box>
<Heading size="xs" textTransform="uppercase" pb="2">
Get Calls Status
</Heading>
<EthersGetCallsStatusTest />
<EthersGetCallsStatusTest callsHash={callsHash} />
</Box>
<Box>
<Heading size="xs" textTransform="uppercase" pb="2">
Expand Down
6 changes: 3 additions & 3 deletions packages/adapters/ethers/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"test": "vitest run --coverage.enabled=true --coverage.reporter=json --coverage.reporter=json-summary --coverage.reportOnFailure=true"
},
"dependencies": {
"@walletconnect/utils": "2.16.1",
"@walletconnect/utils": "2.16.2",
"@reown/appkit": "workspace:*",
"@reown/appkit-common": "workspace:*",
"@reown/appkit-core": "workspace:*",
Expand All @@ -33,8 +33,8 @@
"@coinbase/wallet-sdk": "4.0.3",
"@ethersproject/sha2": "5.7.0",
"@vitest/coverage-v8": "2.0.5",
"@walletconnect/types": "2.16.1",
"@walletconnect/universal-provider": "2.16.1",
"@walletconnect/types": "2.16.2",
"@walletconnect/universal-provider": "2.16.2",
"ethers": "6.13.0",
"vitest": "2.0.5"
},
Expand Down
Loading
Loading