Skip to content

Commit

Permalink
feat: safe smart accounts (#511)
Browse files Browse the repository at this point in the history
* fix: package versions

* fix: remove unnecessary fragmet

* fix: move smart account implementations

* feat: add abstract smart account lib with safe implementation

* feat: add modular smart account implementation
  • Loading branch information
lukaisailovic authored Mar 15, 2024
1 parent 9942501 commit cdfc562
Show file tree
Hide file tree
Showing 21 changed files with 555 additions and 682 deletions.
10 changes: 5 additions & 5 deletions advanced/wallets/react-wallet-v2/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@
"@taquito/signer": "^15.1.0",
"@taquito/taquito": "^15.1.0",
"@walletconnect/web3wallet": "1.10.2",
"@zerodev/ecdsa-validator": "^5.1.0",
"@zerodev/presets": "^5.1.4",
"@zerodev/sdk": "^5.1.8",
"@zerodev/session-key": "^5.1.1",
"@zerodev/weighted-ecdsa-validator": "^5.1.0",
"@zerodev/ecdsa-validator": "5.1.0",
"@zerodev/presets": "5.1.4",
"@zerodev/sdk": "5.1.8",
"@zerodev/session-key": "5.1.1",
"@zerodev/weighted-ecdsa-validator": "5.1.0",
"borsh": "^1.0.0",
"bs58": "5.0.0",
"cosmos-wallet": "1.2.0",
Expand Down
13 changes: 2 additions & 11 deletions advanced/wallets/react-wallet-v2/src/components/ChainDataMini.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,6 @@
import { COSMOS_MAINNET_CHAINS } from '@/data/COSMOSData'
import { EIP155_CHAINS } from '@/data/EIP155Data'
import { KADENA_CHAINS } from '@/data/KadenaData'
import { MULTIVERSX_CHAINS } from '@/data/MultiversxData'
import { NEAR_CHAINS } from '@/data/NEARData'
import { POLKADOT_CHAINS } from '@/data/PolkadotData'
import { SOLANA_CHAINS } from '@/data/SolanaData'
import { TEZOS_CHAINS } from '@/data/TezosData'
import { TRON_CHAINS } from '@/data/TronData'
import { getChainData } from '@/data/chainsUtil'
import { Card, Row, styled, Image, Avatar } from '@nextui-org/react'
import { ReactNode, useMemo } from 'react'
import { Row, Avatar } from '@nextui-org/react'
import { useMemo } from 'react'

interface Props {
chainId?: string // namespace + ":" + reference
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,21 @@
import ChainAddressMini from './ChainAddressMini'
import { Row, Spinner } from '@nextui-org/react'
import SettingsStore from '@/store/SettingsStore'
import { useSnapshot } from 'valtio'

interface Props {
chain:
| {
chainId: string
name: string
logo: string
rgb: string
namespace: string
}
| undefined
type SmartAccount = {
address: string
type: string
}

export default function ChainSmartAddressMini({ chain }: Props) {
const { kernelSmartAccountAddress } = useSnapshot(SettingsStore.state)
interface Props {
account: SmartAccount
}

if (!kernelSmartAccountAddress) return <Spinner />
export default function ChainSmartAddressMini({ account }: Props) {
if (!account) return <Spinner />
return (
<Row>
<Row>(Kernel)</Row>
<ChainAddressMini address={kernelSmartAccountAddress} />
<Row>({account.type})</Row>
<ChainAddressMini address={account.address} />
</Row>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,17 @@ interface IProps {

export default function PermissionDetailsCard({ scope }: IProps) {
return (
<>
<Row>
<Col>
<Text h5>Dapp is requesting following permissions</Text>
{scope.map((action, index) => {
return (
<Text color="$gray400" key={index}>
{action.description}
</Text>
)
})}
</Col>
</Row>
</>
<Row>
<Col>
<Text h5>Dapp is requesting following permissions</Text>
{scope.map((action, index) => {
return (
<Text color="$gray400" key={index}>
{action.description}
</Text>
)
})}
</Col>
</Row>
)
}
17 changes: 17 additions & 0 deletions advanced/wallets/react-wallet-v2/src/consts/smartAccounts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { KernelSmartAccountLib } from '@/lib/smart-accounts/KernelSmartAccountLib'
import { SafeSmartAccountLib } from '@/lib/smart-accounts/SafeSmartAccountLib'
import { goerli, polygonMumbai, sepolia } from 'viem/chains'

// Types
export const allowedChains = [sepolia, polygonMumbai, goerli]
// build chains so I can access them by id
export const chains = allowedChains.reduce((acc, chain) => {
acc[chain.id] = chain
return acc
}, {} as Record<Chain['id'], Chain>)
export type Chain = typeof allowedChains[number]

export const availableSmartAccounts = {
safe: SafeSmartAccountLib,
kernel: KernelSmartAccountLib
}
20 changes: 6 additions & 14 deletions advanced/wallets/react-wallet-v2/src/hooks/useInitialization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,14 @@ import { createWeb3Wallet, web3wallet } from '@/utils/WalletConnectUtil'
import { createOrRestoreKadenaWallet } from '@/utils/KadenaWalletUtil'
import { useCallback, useEffect, useRef, useState } from 'react'
import { useSnapshot } from 'valtio'
import { createOrRestoreKernelSmartAccount } from '@/utils/KernelSmartAccountUtils'
import useSmartAccounts from './useSmartAccounts'

export default function useInitialization() {
const [initialized, setInitialized] = useState(false)
const prevRelayerURLValue = useRef<string>('')

const { relayerRegionURL, smartAccountEnabled, kernelSmartAccountEnabled } = useSnapshot(
SettingsStore.state
)
const { relayerRegionURL } = useSnapshot(SettingsStore.state)
const { initializeSmartAccounts } = useSmartAccounts()

const onInitialize = useCallback(async () => {
try {
Expand All @@ -32,15 +31,7 @@ export default function useInitialization() {
const { tronAddresses } = await createOrRestoreTronWallet()
const { tezosAddresses } = await createOrRestoreTezosWallet()
const { kadenaAddresses } = await createOrRestoreKadenaWallet()

if (smartAccountEnabled) {
if (kernelSmartAccountEnabled) {
const { kernelSmartAccountAddress } = await createOrRestoreKernelSmartAccount(
eip155Wallets[eip155Addresses[0]].getPrivateKey()
)
SettingsStore.setKernelSmartAccountAddress(kernelSmartAccountAddress)
}
}
await initializeSmartAccounts(eip155Wallets[eip155Addresses[0]].getPrivateKey())

SettingsStore.setEIP155Address(eip155Addresses[0])
SettingsStore.setCosmosAddress(cosmosAddresses[0])
Expand All @@ -57,7 +48,8 @@ export default function useInitialization() {
console.error('Initialization failed', err)
alert(err)
}
}, [relayerRegionURL, smartAccountEnabled, kernelSmartAccountEnabled])
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [relayerRegionURL])

// restart transport if relayer region changes
const onRelayerRegionChange = useCallback(() => {
Expand Down
25 changes: 17 additions & 8 deletions advanced/wallets/react-wallet-v2/src/hooks/usePriorityAccounts.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,31 @@
import SettingsStore from '@/store/SettingsStore'
import {
kernelAllowedChains,
safeAllowedChains,
supportedAddressPriority
} from '@/utils/SmartAccountUtil'
import { SessionTypes } from '@walletconnect/types'
import { useSnapshot } from 'valtio'
import { allowedChains, kernelAddressPriority } from '@/utils/KernelSmartAccountUtils'

interface IProps {
namespaces: SessionTypes.Namespaces
}

export default function usePriorityAccounts({ namespaces }: IProps) {
const { smartAccountEnabled, kernelSmartAccountAddress, kernelSmartAccountEnabled } = useSnapshot(
SettingsStore.state
)
const {
smartAccountEnabled,
kernelSmartAccountAddress,
kernelSmartAccountEnabled,
safeSmartAccountAddress,
safeSmartAccountEnabled
} = useSnapshot(SettingsStore.state)

if (smartAccountEnabled) {
/**
* If our kernel account supports any of the requested chainIds, put it in the first spot
*/
if (safeSmartAccountEnabled) {
return supportedAddressPriority(namespaces, safeSmartAccountAddress, safeAllowedChains)
}
if (kernelSmartAccountEnabled) {
return kernelAddressPriority(namespaces, kernelSmartAccountAddress)
return supportedAddressPriority(namespaces, kernelSmartAccountAddress, kernelAllowedChains)
}
}
return []
Expand Down
48 changes: 48 additions & 0 deletions advanced/wallets/react-wallet-v2/src/hooks/useSmartAccounts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import SettingsStore from '@/store/SettingsStore'
import {
createOrRestoreKernelSmartAccount,
createOrRestoreSafeSmartAccount,
smartAccountWallets
} from '@/utils/SmartAccountUtil'

import { useSnapshot } from 'valtio'

export default function useSmartAccounts() {
const { smartAccountEnabled, kernelSmartAccountEnabled, safeSmartAccountEnabled } = useSnapshot(
SettingsStore.state
)

const initializeSmartAccounts = async (privateKey: string) => {
if (smartAccountEnabled) {
if (kernelSmartAccountEnabled) {
const { kernelSmartAccountAddress } = await createOrRestoreKernelSmartAccount(privateKey)
SettingsStore.setKernelSmartAccountAddress(kernelSmartAccountAddress)
}
if (safeSmartAccountEnabled) {
const { safeSmartAccountAddress } = await createOrRestoreSafeSmartAccount(privateKey)
SettingsStore.setSafeSmartAccountAddress(safeSmartAccountAddress)
}
}
}

const getAvailableSmartAccounts = () => {
if (!smartAccountEnabled) {
return []
}
const accounts = []
for (const [key, lib] of Object.entries(smartAccountWallets)) {
accounts.push({
address: key.split(':')[1],
type: lib.type,
chain: lib.chain
})
}

return accounts
}

return {
initializeSmartAccounts,
getAvailableSmartAccounts
}
}
Loading

0 comments on commit cdfc562

Please sign in to comment.