Skip to content

Commit

Permalink
feat: Smart Account relay connection + paymaster base (reown-com#351)
Browse files Browse the repository at this point in the history
* feat: added Goerli smart accounts

* chore: remove viem version modifier. Split useSmartAccount usage into multiliune

* feat: fix error handling

* feat: added smart wallets to proposal modal

* feat: added paymasters to be able to freely transact on testnet with Pimlico sponsorship. Serialize SA addresses in relay response

* feat: adapted SmartWalletLib interface to be able to use same methods as EIP155Lib. Hooked up all operations on EIP155RequestHandler to smart accounts.

* chore: remove logs

* feat: added spinner to modal footer. Use it when handling eip155 requests

* feat: added sponsorship toggle in settings

* feat: upgraded to [email protected]

* fix: conflicts after merge

* chore: unify loaders

* chore: kristoph refactor + multi chain support

* fix: chain Id issue. remove unused logs
  • Loading branch information
tomiir authored Feb 1, 2024
1 parent 46bfda7 commit 9439c9a
Show file tree
Hide file tree
Showing 18 changed files with 537 additions and 124 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import useSmartAccount from '@/hooks/useSmartAccount'
import { Hex } from 'viem'
import ChainAddressMini from './ChainAddressMini'
import { createOrRestoreEIP155Wallet, eip155Wallets } from '@/utils/EIP155WalletUtil'
import { Spinner } from '@nextui-org/react'
import { Chain, allowedChains } from '@/utils/SmartAccountUtils'
import { useSnapshot } from 'valtio'
import SettingsStore from '@/store/SettingsStore'

interface Props {
namespace: string
}

const getKey = (namespace?: string) => {
switch (namespace) {
case 'eip155':
createOrRestoreEIP155Wallet()
const key = Object.values(eip155Wallets)[0]?.getPrivateKey() as Hex
return key
}
}

export default function ChainSmartAddressMini({ namespace }: Props) {
const { activeChainId } = useSnapshot(SettingsStore.state)
const { address } = useSmartAccount(getKey(namespace) as `0x${string}`, allowedChains.find((c) => c.id.toString() === activeChainId) as Chain)

if (!address) return <Spinner />
return (
<ChainAddressMini address={address}/>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ interface Props {
onReject: () => void
infoBoxCondition?: boolean
infoBoxText?: string
disabledApprove?: boolean
approveLoader?: LoaderProps
rejectLoader?: LoaderProps
}
Expand All @@ -23,7 +22,6 @@ export default function ModalFooter({
rejectLoader,
infoBoxCondition,
infoBoxText,
disabledApprove
}: Props) {
const { currentRequestVerifyContext } = useSnapshot(SettingsStore.state)
const validation = currentRequestVerifyContext?.verified.validation
Expand All @@ -46,13 +44,14 @@ export default function ModalFooter({
<span>{infoBoxText || ''}</span>
</Row>
)}
<Row justify="space-between">
<Row justify="space-between" align='center'>
<Button
auto
flat
style={{ color: 'white', backgroundColor: 'grey' }}
onPress={onReject}
data-testid="session-reject-button"
disabled={rejectLoader?.active}
>
{rejectLoader && rejectLoader.active ? (
<Loading size="md" type="points" color={rejectLoader.color || 'white'} />
Expand All @@ -64,7 +63,7 @@ export default function ModalFooter({
auto
flat
color={approveButtonColor}
disabled={disabledApprove}
disabled={approveLoader?.active}
onPress={onApprove}
data-testid="session-approve-button"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import { updateSignClientChainId } from '@/utils/WalletConnectUtil'
import { Avatar, Button, Text, Tooltip, Loading } from '@nextui-org/react'
import { eip155Wallets } from '@/utils/EIP155WalletUtil'
import Image from 'next/image'
import { useState, useEffect } from 'react'
import { useState } from 'react'
import { useSnapshot } from 'valtio'
import useSmartAccount from '@/hooks/useSmartAccount'
import { Chain, FAUCET_URLS, allowedChains } from '@/utils/SmartAccountUtils'

interface Props {
name: string
Expand All @@ -28,13 +29,14 @@ export default function SmartAccountCard({
}: Props) {
const [copied, setCopied] = useState(false)
const { activeChainId } = useSnapshot(SettingsStore.state)
const chain = allowedChains.find((c) => c.id.toString() === chainId.split(':')[1]) as Chain
const {
deploy,
isDeployed,
address: smartAccountAddress,
loading,
sendTestTransaction,
} = useSmartAccount(eip155Wallets[address].getPrivateKey() as `0x${string}`)
} = useSmartAccount(eip155Wallets[address].getPrivateKey() as `0x${string}`, chain)

function onCopy() {
navigator?.clipboard?.writeText(address)
Expand All @@ -56,9 +58,7 @@ export default function SmartAccountCard({
console.error(error)
}
}

const getFaucetUrl = () => `https://${name?.toLowerCase()?.replace('ethereum', '')?.trim()}faucet.com`


return (
<ChainCard rgb={rgb} flexDirection="row" alignItems="center" flexWrap="wrap">
<Avatar src={logo} />
Expand Down Expand Up @@ -124,7 +124,7 @@ export default function SmartAccountCard({
disabled={!isActiveChain || loading}
size="sm"
css={{ marginTop: 20, width: '100%' }}
onClick={() => window.open(getFaucetUrl(), '_blank')}
onClick={() => window.open(FAUCET_URLS[chain?.name], '_blank')}
>
{name} Faucet
</Button>
Expand Down
10 changes: 6 additions & 4 deletions advanced/wallets/react-wallet-v2/src/data/EIP155Data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
*/
export type TEIP155Chain = keyof typeof EIP155_CHAINS

export type EIP155TestChain = {
export type EIP155Chain = {
chainId: number
name: string
logo: string
Expand All @@ -21,7 +21,7 @@ export type EIP155TestChain = {
/**
* Chains
*/
export const EIP155_MAINNET_CHAINS = {
export const EIP155_MAINNET_CHAINS: Record<string, EIP155Chain> = {
'eip155:1': {
chainId: 1,
name: 'Ethereum',
Expand Down Expand Up @@ -64,7 +64,7 @@ export const EIP155_MAINNET_CHAINS = {
}
}

export const EIP155_TEST_CHAINS: Record<string,EIP155TestChain> = {
export const EIP155_TEST_CHAINS: Record<string,EIP155Chain> = {
'eip155:5': {
chainId: 5,
name: 'Ethereum Goerli',
Expand All @@ -81,6 +81,7 @@ export const EIP155_TEST_CHAINS: Record<string,EIP155TestChain> = {
rgb: '99, 125, 234',
rpc: 'https://rpc.sepolia.org',
namespace: 'eip155',
smartAccountEnabled: true,
},
'eip155:43113': {
chainId: 43113,
Expand All @@ -96,7 +97,8 @@ export const EIP155_TEST_CHAINS: Record<string,EIP155TestChain> = {
logo: '/chain-logos/eip155-137.png',
rgb: '130, 71, 229',
rpc: 'https://matic-mumbai.chainstacklabs.com',
namespace: 'eip155'
namespace: 'eip155',
smartAccountEnabled: true,
},
'eip155:420': {
chainId: 420,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export default function useInitialization() {
// restart transport if relayer region changes
const onRelayerRegionChange = useCallback(() => {
try {
web3wallet.core.relayer.restartTransport(relayerRegionURL)
web3wallet?.core?.relayer.restartTransport(relayerRegionURL)
prevRelayerURLValue.current = relayerRegionURL
} catch (err: unknown) {
alert(err)
Expand Down
33 changes: 24 additions & 9 deletions advanced/wallets/react-wallet-v2/src/hooks/useSmartAccount.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
import { SmartAccountLib } from "@/lib/SmartAccountLib";
import { styledToast } from "@/utils/HelperUtil";
import SettingsStore from "@/store/SettingsStore";
import { Chain, VITALIK_ADDRESS } from "@/utils/SmartAccountUtils";
import { useCallback, useEffect, useState } from "react";
import { useSnapshot } from "valtio";
import { Hex } from "viem";
import { styledToast } from "@/utils/HelperUtil";
import { TransactionExecutionError } from "viem";

export default function useSmartAccount(signerPrivateKey: `0x${string}`) {
export default function useSmartAccount(signerPrivateKey: Hex, chain: Chain) {
const [loading, setLoading] = useState(false)
const [client, setClient] = useState<SmartAccountLib>();
const [isDeployed, setIsDeployed] = useState(false)
const [address, setAddress] = useState<`0x${string}`>()
const [address, setAddress] = useState<Hex>()
const { smartAccountSponsorshipEnabled } = useSnapshot(SettingsStore.state);

const execute = useCallback(async (callback: () => void) => {
try {
setLoading(true)
await callback()
const res = await callback()
console.log('result:', res)
setLoading(false)
}
catch (e) {
Expand All @@ -34,21 +40,30 @@ export default function useSmartAccount(signerPrivateKey: `0x${string}`) {

const sendTestTransaction = useCallback(async () => {
if (!client) return
execute(client?.sendTestTransaction)
execute(() => client?.sendTransaction({
to: VITALIK_ADDRESS,
value: 0n,
data: '0x',
}))
}, [client, execute])

useEffect(() => {
const smartAccountClient = new SmartAccountLib(signerPrivateKey, 'goerli')
setClient(smartAccountClient)
}, [signerPrivateKey])
if (!signerPrivateKey || !chain) return
const smartAccountClient = new SmartAccountLib({
chain,
privateKey: signerPrivateKey,
sponsored: smartAccountSponsorshipEnabled,
})
setClient(smartAccountClient)
}, [signerPrivateKey, smartAccountSponsorshipEnabled, chain])

useEffect(() => {
client?.checkIfSmartAccountDeployed()
.then((deployed: boolean) => {
setIsDeployed(deployed)
setAddress(client?.address)
})
}, [client])
}, [client, chain])


return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ export default function useWalletConnectEventsManager(initialized: boolean) {
* Set up WalletConnect event listeners
*****************************************************************************/
useEffect(() => {
if (initialized) {
if (initialized && web3wallet) {
//sign
web3wallet.on('session_proposal', onSessionProposal)
web3wallet.on('session_request', onSessionRequest)
Expand Down
2 changes: 1 addition & 1 deletion advanced/wallets/react-wallet-v2/src/lib/EIP155Lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export default class EIP155Lib {
return this.wallet.signMessage(message)
}

_signTypedData(domain: any, types: any, data: any) {
_signTypedData(domain: any, types: any, data: any, _primaryType?: string) {
return this.wallet._signTypedData(domain, types, data)
}

Expand Down
Loading

0 comments on commit 9439c9a

Please sign in to comment.