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

Implement actions using userOpBuilder service instead of permissionless.js #2758

Merged
merged 23 commits into from
Sep 3, 2024
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
d611448
chores:refactor Erc7715 code
KannuSingh Aug 28, 2024
d32505b
Merge branch 'main' into refactor-erc7715-impl
KannuSingh Aug 28, 2024
57b9758
impl permissions tests using UserOpBuilder service
KannuSingh Aug 28, 2024
88001c5
fix: Ethereum provider issue for sample-wallet
KannuSingh Aug 28, 2024
6613c3b
removed permissions usage method from useErc7715Permissions hook
KannuSingh Aug 28, 2024
b1d44aa
Delete PermissionsUtils.ts
KannuSingh Aug 28, 2024
c50bd34
added type UserOperation v0.7
KannuSingh Aug 28, 2024
93b7bbd
remove permissionless dependency
KannuSingh Aug 28, 2024
b6e7723
chore: run prettier
KannuSingh Aug 28, 2024
683c71d
refactor requestPermissions method
KannuSingh Aug 28, 2024
284d1c2
chores:rename method requestPermissions to grantPermissions
KannuSingh Aug 28, 2024
a441d7c
add suggested changes
KannuSingh Aug 29, 2024
45787ac
chores: rename localStorage methods
KannuSingh Aug 30, 2024
c96c0f4
move const to ConstantsUtil
KannuSingh Aug 30, 2024
1b198fa
chores:remove lint suppression on userOpBuilder
KannuSingh Aug 30, 2024
35f129b
update callback hook deps array
KannuSingh Sep 3, 2024
835a9df
Merge branch 'main' into use-userOpBuilder-service
KannuSingh Sep 3, 2024
fb11a99
Update pnpm-lock.yaml
KannuSingh Sep 3, 2024
67451ef
updated cspHeader to include react-wallet
KannuSingh Sep 3, 2024
4320a74
update co-signer response type
KannuSingh Sep 3, 2024
493b59f
fix- local signer storage
KannuSingh Sep 3, 2024
fba3aab
update cosigner url to .org
KannuSingh Sep 3, 2024
553db5e
Merge branch 'main' into use-userOpBuilder-service
KannuSingh Sep 3, 2024
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
1 change: 0 additions & 1 deletion apps/laboratory/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@
"framer-motion": "10.17.9",
"next": "14.2.3",
"next-auth": "4.24.5",
"permissionless": "0.1.31",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-icons": "4.12.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ 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 { LOCAL_SIGNER_KEY, getLocalStorageItem } from '../../utils/LocalStorage'
import { createCredential } from 'webauthn-p256'
import { useWagmiPermissionsSync } from '../../context/WagmiPermissionsSyncContext'
import { usePasskey } from '../../context/PasskeyContext'

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

async function handleCreatePasskey() {
Expand All @@ -31,7 +31,7 @@ export function WagmiCreatePasskeySignerTest() {
}

useEffect(() => {
const storedLocalSignerPrivateKey = getItem(LOCAL_SIGNER_KEY)
const storedLocalSignerPrivateKey = getLocalStorageItem(LOCAL_SIGNER_KEY)
if (storedLocalSignerPrivateKey) {
privateKeyToAccount(storedLocalSignerPrivateKey as `0x${string}`)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,14 @@ 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'
import { useLocalEcdsaKey } from '../../context/LocalEcdsaKeyContext'
import { useERC7715Permissions } from '../../hooks/useERC7715Permissions'
import { executeActionsWithECDSAAndCosignerPermissions } from '../../utils/ERC7715Utils'

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

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

const {
data: donutsOwned,
Expand All @@ -35,29 +32,33 @@ export function WagmiPurchaseDonutAsyncPermissionsTest() {
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`)
}
if (!grantedPermissions) {
throw Error('No permissions available')
}
if (!pci) {
throw Error('No WC cosigner data(PCI) available')
}
const purchaseDonutCallData = encodeFunctionData({
abi: donutContractAbi,
functionName: 'purchase',
args: [1]
})
const purchaseDonutCallDataExecution = [
{
target: donutContractaddress as `0x${string}`,
to: donutContractaddress as `0x${string}`,
value: parseEther('0.0001'),
callData: purchaseDonutCallData
data: purchaseDonutCallData
}
]
const txHash = await executeActionsWithECDSAAndCosignerPermissions({
actions: purchaseDonutCallDataExecution,
chain: sepolia,
ecdsaPrivateKey: privateKey as `0x${string}`
ecdsaPrivateKey: privateKey as `0x${string}`,
permissions: grantedPermissions,
pci
})
if (txHash) {
toast({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,14 @@ import { useState } from 'react'
import { useChakraToast } from '../Toast'
import { encodeFunctionData, parseEther } from 'viem'
import { abi as donutContractAbi, address as donutContractaddress } from '../../utils/DonutContract'
import { useERC7715PermissionsSync } from '../../hooks/useERC7715PermissionsSync'
import { useWagmiPermissionsSync } from '../../context/WagmiPermissionsSyncContext'
import { useERC7715Permissions } from '../../hooks/useERC7715Permissions'
import { usePasskey } from '../../context/PasskeyContext'
import { sepolia } from 'viem/chains'
import { executeActionsWithPasskeyAndCosignerPermissions } from '../../utils/ERC7715Utils'

export function WagmiPurchaseDonutSyncPermissionsTest() {
const { grantedPermissions, wcCosignerData, passkeyId, projectId } = useWagmiPermissionsSync()
const { executeActionsWithPasskeyAndCosignerPermissions } = useERC7715PermissionsSync({
chain: sepolia,
permissions: grantedPermissions,
projectId
})
const { passkeyId } = usePasskey()
const { grantedPermissions, pci } = useERC7715Permissions()

const {
data: donutsOwned,
Expand All @@ -37,8 +34,8 @@ export function WagmiPurchaseDonutSyncPermissionsTest() {
if (!grantedPermissions) {
throw Error('No permissions available')
}
if (!wcCosignerData) {
throw Error('No wc-cosigner data available')
if (!pci) {
throw Error('No WC cosigner data(PCI) available')
}

const purchaseDonutCallData = encodeFunctionData({
Expand All @@ -48,15 +45,17 @@ export function WagmiPurchaseDonutSyncPermissionsTest() {
})
const purchaseDonutCallDataExecution = [
{
target: donutContractaddress as `0x${string}`,
to: donutContractaddress as `0x${string}`,
value: parseEther('0.0001'),
callData: purchaseDonutCallData
data: purchaseDonutCallData
}
]
const txHash = await executeActionsWithPasskeyAndCosignerPermissions({
actions: purchaseDonutCallDataExecution,
chain: sepolia,
passkeyId,
wcCosignerData
permissions: grantedPermissions,
pci
})
if (txHash) {
toast({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,134 +3,102 @@ import { useAccount } from 'wagmi'
import { walletActionsErc7715 } from 'viem/experimental'
import { useCallback, useState } from 'react'
import { useChakraToast } from '../Toast'
import { createPublicClient, custom } from 'viem'
import { createWalletClient, custom, type Address, type Chain } from 'viem'
import { EIP_7715_RPC_METHODS } from '../../utils/EIP5792Utils'
import { useWalletConnectCosigner } from '../../hooks/useWalletConnectCosigner'
import { useWagmiAvailableCapabilities } from '../../hooks/useWagmiActiveCapabilities'
import { useWagmiPermissionsAsync } from '../../context/WagmiPermissionsAsyncContext'
import {
decodeUncompressedPublicKey,
encodePublicKeyToDID,
hexStringToBase64
} from '../../utils/EncodingUtils'
useWagmiAvailableCapabilities,
type Provider
} from '../../hooks/useWagmiActiveCapabilities'
import { useLocalEcdsaKey } from '../../context/LocalEcdsaKeyContext'
import { bigIntReplacer } from '../../utils/CommonUtils'
import { getSampleAsyncPermissions } from '../../utils/ERC7715Utils'
import { useERC7715Permissions } from '../../hooks/useERC7715Permissions'
import { getPurchaseDonutPermissions } from '../../utils/ERC7715Utils'
import { KeyTypes } from '../../utils/EncodingUtils'

export function WagmiRequestPermissionsAsyncTest() {
const { provider, supported } = useWagmiAvailableCapabilities({
method: EIP_7715_RPC_METHODS.WALLET_GRANT_PERMISSIONS
})
const { chain, address, isConnected } = useAccount()
const caip10Address = `eip155:${chain?.id}:${address}`

const {
projectId,
signer,
grantedPermissions,
clearGrantedPermissions,
setGrantedPermissions,
setWCCosignerData
} = useWagmiPermissionsAsync()
if (!isConnected || !provider || !address || !chain) {
return (
<Text fontSize="md" color="yellow">
Wallet not connected
</Text>
)
}
if (!supported) {
return (
<Text fontSize="md" color="yellow">
Wallet does not support wallet_grantPermissions rpc method
</Text>
)
}

return <ConnectedTestContent chain={chain} provider={provider} address={address} />
}

function ConnectedTestContent({
chain,
provider,
address
}: {
chain: Chain
provider: Provider
address: Address
}) {
const { grantedPermissions, clearGrantedPermissions, grantPermissions } = useERC7715Permissions()
const { signer } = useLocalEcdsaKey()
const [isRequestPermissionLoading, setRequestPermissionLoading] = useState<boolean>(false)
const { addPermission, updatePermissionsContext } = useWalletConnectCosigner(
caip10Address,
projectId
)
const toast = useChakraToast()

const onRequestPermissions = useCallback(async () => {
setRequestPermissionLoading(true)

if (!signer) {
throw new Error('PrivateKey signer not available')
}
if (!provider) {
throw new Error('No Provider available, Please connect your wallet.')
}
try {
const addPermissionResponse = await addPermission({
permissionType: 'donut-purchase',
data: '',
onChainValidated: false,
required: true
})
setWCCosignerData(addPermissionResponse)
const cosignerPublicKey = decodeUncompressedPublicKey(addPermissionResponse.key)

const dAppECDSAPublicKey = signer.publicKey
const dAppSecp256k1DID = encodePublicKeyToDID(dAppECDSAPublicKey, 'secp256k1')
const coSignerSecp256k1DID = encodePublicKeyToDID(cosignerPublicKey, 'secp256k1')
if (!signer) {
throw new Error('PrivateKey signer not available')
}
if (!provider) {
throw new Error('No Provider available, Please connect your wallet.')
}

const publicClient = createPublicClient({
const walletClient = createWalletClient({
account: address,
chain,
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
transport: custom(provider)
}).extend(walletActionsErc7715())
const samplePermissions = getSampleAsyncPermissions([coSignerSecp256k1DID, dAppSecp256k1DID])
const approvedPermissions = await publicClient.grantPermissions(samplePermissions)
if (approvedPermissions) {
await updatePermissionsContext({
pci: addPermissionResponse.pci,
context: {
expiry: approvedPermissions.expiry,
signer: {
type: 'donut-purchase',
data: {
ids: [addPermissionResponse.key, hexStringToBase64(dAppECDSAPublicKey)]
}
},
signerData: {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-non-null-asserted-optional-chain
userOpBuilder: approvedPermissions.signerData?.userOpBuilder!
},
permissionsContext: approvedPermissions.permissionsContext,
factory: approvedPermissions.factory || '',
factoryData: approvedPermissions.factoryData || ''
}
})
setGrantedPermissions(approvedPermissions)
setRequestPermissionLoading(false)
toast({
type: 'success',
title: 'Permissions Granted',
description: JSON.stringify(approvedPermissions, bigIntReplacer)
})

return
}
toast({ title: 'Error', description: 'Failed to obtain permissions' })
const purchaseDonutPermissions = getPurchaseDonutPermissions()
const response = await grantPermissions(walletClient, {
permissions: purchaseDonutPermissions,
signerKey: {
key: signer.publicKey,
type: KeyTypes.secp256k1
}
})
toast({
type: 'success',
title: 'Permissions Granted',
description: JSON.stringify(response.approvedPermissions, bigIntReplacer)
})
} catch (error) {
toast({
type: 'error',
title: 'Permissions Erros',
description: error instanceof Error ? error.message : 'Some error occurred'
title: 'Request Permissions Errors',
description: error instanceof Error ? error.message : 'Unknown Error'
})
} finally {
setRequestPermissionLoading(false)
}
setRequestPermissionLoading(false)
}, [signer, provider])
if (!isConnected || !provider || !address) {
return (
<Text fontSize="md" color="yellow">
Wallet not connected
</Text>
)
}
if (!supported) {
return (
<Text fontSize="md" color="yellow">
Wallet does not support wallet_grantPermissions rpc method
</Text>
)
}

return (
<Stack direction={['column', 'column', 'row']}>
<Button
data-test-id="request-permissions-button"
onClick={onRequestPermissions}
isDisabled={Boolean(
isRequestPermissionLoading || Boolean(grantedPermissions) || !isConnected
)}
isDisabled={Boolean(isRequestPermissionLoading || Boolean(grantedPermissions))}
isLoading={isRequestPermissionLoading}
>
Request Permissions
Expand Down
Loading