Skip to content

Commit

Permalink
Wagmi: Erc7715 permissions with Appkit embedded wallet (#2615)
Browse files Browse the repository at this point in the history
  • Loading branch information
KannuSingh authored Aug 8, 2024
1 parent 47ddd58 commit 9704718
Show file tree
Hide file tree
Showing 34 changed files with 13,256 additions and 16,208 deletions.
4 changes: 3 additions & 1 deletion apps/laboratory/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@
"rpc-websockets": "7.11.0",
"valtio": "1.11.2",
"viem": "2.17.8",
"wagmi": "2.12.2"
"wagmi": "2.12.2",
"webauthn-p256": "0.0.2",
"axios": "1.7.2"
},
"devDependencies": {
"@aws-sdk/client-cloudwatch": "3.509.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { useEffect } from 'react'
import { Button, Stack } from '@chakra-ui/react'
import { privateKeyToAccount } from 'viem/accounts'
import { useChakraToast } from '../Toast'
import { LOCAL_SIGNER_KEY, getItem } from '../../utils/LocalStorage'
import { createCredential } from 'webauthn-p256'
import { useWagmiPermissionsSync } from '../../context/WagmiPermissionsSyncContext'

export function WagmiCreatePasskeySignerTest() {
const { isPasskeyAvailable, setPasskey, passkeyId } = useWagmiPermissionsSync()
const toast = useChakraToast()

async function handleCreatePasskey() {
try {
const credential = await createCredential({
name: 'Session key'
})
setPasskey(credential)
toast({
type: 'success',
title: 'Passkey created succesfully',
description: ''
})
} catch (error) {
toast({
type: 'error',
title: `Unable to create passkey`,
description: `Reason ${error}`
})
}
}

useEffect(() => {
const storedLocalSignerPrivateKey = getItem(LOCAL_SIGNER_KEY)
if (storedLocalSignerPrivateKey) {
privateKeyToAccount(storedLocalSignerPrivateKey as `0x${string}`)
}
}, [])

return (
<Stack direction={['column', 'column', 'row']} align={'center'}>
<Button data-testid="sign-message-button" onClick={handleCreatePasskey}>
Create New Passkey
</Button>
{isPasskeyAvailable && passkeyId && <div>Passkey Id: {passkeyId}</div>}
</Stack>
)
}

This file was deleted.

29 changes: 29 additions & 0 deletions apps/laboratory/src/components/Wagmi/WagmiPermissionsAsyncTest.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Box, Card, CardBody, CardHeader, Heading, Stack, StackDivider } from '@chakra-ui/react'
import { WagmiRequestPermissionsAsyncTest } from './WagmiRequestPermissionsAsyncTest'
import { WagmiPurchaseDonutAsyncPermissionsTest } from './WagmiPurchaseDonutAsyncPermissionsTest'

export function WagmiPermissionsAsyncTest() {
return (
<Card marginTop={10} marginBottom={10}>
<CardHeader>
<Heading size="md">Test Interactions</Heading>
</CardHeader>
<CardBody>
<Stack divider={<StackDivider />} spacing="4">
<Box>
<Heading size="xs" textTransform="uppercase" pb="2">
Request Permissions
</Heading>
<WagmiRequestPermissionsAsyncTest />
</Box>
<Box>
<Heading size="xs" textTransform="uppercase" pb="2">
Purchase Donut With Permissions
</Heading>
<WagmiPurchaseDonutAsyncPermissionsTest />
</Box>
</Stack>
</CardBody>
</Card>
)
}
36 changes: 36 additions & 0 deletions apps/laboratory/src/components/Wagmi/WagmiPermissionsSyncTest.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Box, Card, CardBody, CardHeader, Heading, Stack, StackDivider } from '@chakra-ui/react'
import { WagmiRequestPermissionsSyncTest } from './WagmiRequestPermissionsSyncTest'
import { WagmiPurchaseDonutSyncPermissionsTest } from './WagmiPurchaseDonutSyncPermissionsTest'
import { WagmiCreatePasskeySignerTest } from './WagmiCreatePasskeySignerTest'

export function WagmiPermissionsSyncTest() {
return (
<Card marginTop={10} marginBottom={10}>
<CardHeader>
<Heading size="md">Test Interactions</Heading>
</CardHeader>
<CardBody>
<Stack divider={<StackDivider />} spacing="4">
<Box>
<Heading size="xs" textTransform="uppercase" pb="2">
New Passkey
</Heading>
<WagmiCreatePasskeySignerTest />
</Box>
<Box>
<Heading size="xs" textTransform="uppercase" pb="2">
Request Permissions
</Heading>
<WagmiRequestPermissionsSyncTest />
</Box>
<Box>
<Heading size="xs" textTransform="uppercase" pb="2">
Purchase Donut With Permissions
</Heading>
<WagmiPurchaseDonutSyncPermissionsTest />
</Box>
</Stack>
</CardBody>
</Card>
)
}
51 changes: 0 additions & 51 deletions apps/laboratory/src/components/Wagmi/WagmiPermissionsTest.tsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { Button, Flex, Stack, Text } from '@chakra-ui/react'
import { useReadContract } from 'wagmi'
import { useState } from 'react'
import { useChakraToast } from '../Toast'
import { encodeFunctionData, parseEther } from 'viem'
import { abi as donutContractAbi, address as donutContractaddress } from '../../utils/DonutContract'
import { sepolia } from 'viem/chains'
import { useWagmiPermissionsAsync } from '../../context/WagmiPermissionsAsyncContext'
import { useERC7715PermissionsAsync } from '../../hooks/useERC7715PermissionsAsync'

export function WagmiPurchaseDonutAsyncPermissionsTest() {
const { grantedPermissions, wcCosignerData, privateKey, projectId } = useWagmiPermissionsAsync()

const { executeActionsWithECDSAAndCosignerPermissions } = useERC7715PermissionsAsync({
chain: sepolia,
permissions: grantedPermissions,
projectId
})

const {
data: donutsOwned,
refetch: fetchDonutsOwned,
isLoading: donutsQueryLoading,
isRefetching: donutsQueryRefetching
} = useReadContract({
abi: donutContractAbi,
address: donutContractaddress,
functionName: 'getBalance',
args: [grantedPermissions?.signerData?.submitToAddress || '0x']
})

const [isTransactionPending, setTransactionPending] = useState<boolean>(false)
const toast = useChakraToast()

async function onPurchaseDonutWithPermissions() {
setTransactionPending(true)
try {
if (!wcCosignerData) {
throw Error('No wc-cosigner data available')
}

if (!privateKey) {
throw new Error(`Unable to get dApp private key`)
}
const purchaseDonutCallData = encodeFunctionData({
abi: donutContractAbi,
functionName: 'purchase',
args: [1]
})
const purchaseDonutCallDataExecution = [
{
target: donutContractaddress as `0x${string}`,
value: parseEther('0.0001'),
callData: purchaseDonutCallData
}
]
const txHash = await executeActionsWithECDSAAndCosignerPermissions({
actions: purchaseDonutCallDataExecution,
chain: sepolia,
ecdsaPrivateKey: privateKey as `0x${string}`
})
if (txHash) {
toast({
title: 'Transaction success',
description: txHash,
type: 'success'
})
await fetchDonutsOwned()
}
} catch (error) {
// Console.log(error)
toast({
title: 'Transaction Failed',
description: `${error}`,
type: 'error'
})
}
setTransactionPending(false)
}
if (!grantedPermissions) {
return (
<Text fontSize="md" color="yellow">
Dapp does not have the permissions
</Text>
)
}

return (
<Stack direction={['column', 'column', 'row']}>
<Button
isDisabled={!grantedPermissions}
isLoading={isTransactionPending}
onClick={onPurchaseDonutWithPermissions}
>
Purchase Donut
</Button>
<Flex alignItems="center">
{donutsQueryLoading || donutsQueryRefetching ? (
<Text>Fetching donuts...</Text>
) : (
<>
<Text marginRight="5px">Crypto donuts left:</Text>
<Text>{donutsOwned?.toString()}</Text>
</>
)}
</Flex>
</Stack>
)
}
Loading

0 comments on commit 9704718

Please sign in to comment.