From 13cb0ffabae838b577d1b8dc457b359a68d0764e Mon Sep 17 00:00:00 2001
From: Karandeep Singh <90941366+KannuSingh@users.noreply.github.com>
Date: Tue, 3 Sep 2024 18:28:03 -0400
Subject: [PATCH] Implement actions using userOpBuilder service instead of
permissionless.js (#2758)
---
apps/laboratory/next.config.mjs | 2 +-
apps/laboratory/package.json | 1 -
.../Wagmi/WagmiCreatePasskeySignerTest.tsx | 8 +-
...WagmiPurchaseDonutAsyncPermissionsTest.tsx | 36 +-
.../WagmiPurchaseDonutSyncPermissionsTest.tsx | 29 +-
.../WagmiRequestPermissionsAsyncTest.tsx | 160 +-
.../Wagmi/WagmiRequestPermissionsSyncTest.tsx | 183 +-
.../src/context/ERC7715PermissionsContext.tsx | 69 +
.../src/context/LocalEcdsaKeyContext.tsx | 72 +
.../laboratory/src/context/PasskeyContext.tsx | 73 +
.../context/WagmiPermissionsAsyncContext.tsx | 112 -
.../context/WagmiPermissionsSyncContext.tsx | 112 -
.../src/hooks/useERC7715Permissions.ts | 108 +
.../src/hooks/useERC7715PermissionsAsync.ts | 137 -
.../src/hooks/useERC7715PermissionsSync.ts | 158 -
.../src/hooks/useLocalStorageState.ts | 6 +-
apps/laboratory/src/hooks/useUserOpBuilder.ts | 312 -
.../src/hooks/useWagmiActiveCapabilities.ts | 12 +-
.../src/hooks/useWalletConnectCosigner.ts | 197 -
apps/laboratory/src/layout/CustomWallet.tsx | 3 +-
.../pages/library/wagmi-permissions-async.tsx | 13 +-
.../pages/library/wagmi-permissions-sync.tsx | 13 +-
apps/laboratory/src/utils/ConstantsUtil.ts | 7 +-
apps/laboratory/src/utils/ERC7715Utils.ts | 220 +-
apps/laboratory/src/utils/EncodingUtils.ts | 43 +
apps/laboratory/src/utils/LocalStorage.ts | 30 +-
apps/laboratory/src/utils/PermissionsUtils.ts | 67 -
.../src/utils/UserOpBuilderServiceUtils.ts | 141 +
.../src/utils/WalletConnectCosignerUtils.ts | 177 +
pnpm-lock.yaml | 28272 +++++++---------
30 files changed, 13237 insertions(+), 17536 deletions(-)
create mode 100644 apps/laboratory/src/context/ERC7715PermissionsContext.tsx
create mode 100644 apps/laboratory/src/context/LocalEcdsaKeyContext.tsx
create mode 100644 apps/laboratory/src/context/PasskeyContext.tsx
delete mode 100644 apps/laboratory/src/context/WagmiPermissionsAsyncContext.tsx
delete mode 100644 apps/laboratory/src/context/WagmiPermissionsSyncContext.tsx
create mode 100644 apps/laboratory/src/hooks/useERC7715Permissions.ts
delete mode 100644 apps/laboratory/src/hooks/useERC7715PermissionsAsync.ts
delete mode 100644 apps/laboratory/src/hooks/useERC7715PermissionsSync.ts
delete mode 100644 apps/laboratory/src/hooks/useUserOpBuilder.ts
delete mode 100644 apps/laboratory/src/hooks/useWalletConnectCosigner.ts
delete mode 100644 apps/laboratory/src/utils/PermissionsUtils.ts
create mode 100644 apps/laboratory/src/utils/UserOpBuilderServiceUtils.ts
create mode 100644 apps/laboratory/src/utils/WalletConnectCosignerUtils.ts
diff --git a/apps/laboratory/next.config.mjs b/apps/laboratory/next.config.mjs
index 04353ea4ea..aef6cc3eb9 100644
--- a/apps/laboratory/next.config.mjs
+++ b/apps/laboratory/next.config.mjs
@@ -11,7 +11,7 @@ const cspHeader = `
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
img-src * 'self' data: blob: https://walletconnect.org https://walletconnect.com https://secure.walletconnect.com https://secure.walletconnect.org https://tokens-data.1inch.io https://tokens.1inch.io https://ipfs.io https://lab.web3modal.com;
font-src 'self' https://fonts.gstatic.com;
- connect-src 'self' https://rpc.walletconnect.com https://rpc.walletconnect.org https://relay.walletconnect.com https://relay.walletconnect.org wss://relay.walletconnect.com wss://relay.walletconnect.org https://pulse.walletconnect.com https://pulse.walletconnect.org https://api.web3modal.com https://api.web3modal.org wss://www.walletlink.org https://o1095249.ingest.sentry.io;
+ connect-src 'self' https://react-wallet.walletconnect.com https://rpc.walletconnect.com https://rpc.walletconnect.org https://relay.walletconnect.com https://relay.walletconnect.org wss://relay.walletconnect.com wss://relay.walletconnect.org https://pulse.walletconnect.com https://pulse.walletconnect.org https://api.web3modal.com https://api.web3modal.org wss://www.walletlink.org https://o1095249.ingest.sentry.io;
frame-src 'self' https://verify.walletconnect.com https://verify.walletconnect.org https://secure.walletconnect.com https://secure.walletconnect.org;
object-src 'none';
base-uri 'self';
diff --git a/apps/laboratory/package.json b/apps/laboratory/package.json
index f3b253a383..255934ad6e 100644
--- a/apps/laboratory/package.json
+++ b/apps/laboratory/package.json
@@ -66,7 +66,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",
diff --git a/apps/laboratory/src/components/Wagmi/WagmiCreatePasskeySignerTest.tsx b/apps/laboratory/src/components/Wagmi/WagmiCreatePasskeySignerTest.tsx
index 2927920823..9f6e64ec6d 100644
--- a/apps/laboratory/src/components/Wagmi/WagmiCreatePasskeySignerTest.tsx
+++ b/apps/laboratory/src/components/Wagmi/WagmiCreatePasskeySignerTest.tsx
@@ -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() {
@@ -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}`)
}
diff --git a/apps/laboratory/src/components/Wagmi/WagmiPurchaseDonutAsyncPermissionsTest.tsx b/apps/laboratory/src/components/Wagmi/WagmiPurchaseDonutAsyncPermissionsTest.tsx
index 3b7ff7dd20..fb26dc97f0 100644
--- a/apps/laboratory/src/components/Wagmi/WagmiPurchaseDonutAsyncPermissionsTest.tsx
+++ b/apps/laboratory/src/components/Wagmi/WagmiPurchaseDonutAsyncPermissionsTest.tsx
@@ -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,
@@ -35,13 +32,15 @@ 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',
@@ -49,26 +48,27 @@ export function WagmiPurchaseDonutAsyncPermissionsTest() {
})
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({
- title: 'Transaction success',
- description: txHash,
+ title: 'UserOp submitted successfully',
+ description: `UserOp Hash: ${txHash}`,
type: 'success'
})
await fetchDonutsOwned()
}
} catch (error) {
- // Console.log(error)
toast({
title: 'Transaction Failed',
description: `${error}`,
diff --git a/apps/laboratory/src/components/Wagmi/WagmiPurchaseDonutSyncPermissionsTest.tsx b/apps/laboratory/src/components/Wagmi/WagmiPurchaseDonutSyncPermissionsTest.tsx
index d97f8f6d60..5ec66a05e0 100644
--- a/apps/laboratory/src/components/Wagmi/WagmiPurchaseDonutSyncPermissionsTest.tsx
+++ b/apps/laboratory/src/components/Wagmi/WagmiPurchaseDonutSyncPermissionsTest.tsx
@@ -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,
@@ -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({
@@ -48,20 +45,22 @@ 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({
- title: 'Transaction success',
- description: txHash,
+ title: 'UserOp submitted successfully',
+ description: `UserOp Hash: ${txHash}`,
type: 'success'
})
await fetchDonutsOwned()
diff --git a/apps/laboratory/src/components/Wagmi/WagmiRequestPermissionsAsyncTest.tsx b/apps/laboratory/src/components/Wagmi/WagmiRequestPermissionsAsyncTest.tsx
index 2eb7919111..12db6bf0cb 100644
--- a/apps/laboratory/src/components/Wagmi/WagmiRequestPermissionsAsyncTest.tsx
+++ b/apps/laboratory/src/components/Wagmi/WagmiRequestPermissionsAsyncTest.tsx
@@ -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 (
+
+ Wallet not connected
+
+ )
+ }
+ if (!supported) {
+ return (
+
+ Wallet does not support wallet_grantPermissions rpc method
+
+ )
+ }
+
+ return
+}
+
+function ConnectedTestContent({
+ chain,
+ provider,
+ address
+}: {
+ chain: Chain
+ provider: Provider
+ address: Address
+}) {
+ const { grantedPermissions, clearGrantedPermissions, grantPermissions } = useERC7715Permissions()
+ const { signer } = useLocalEcdsaKey()
const [isRequestPermissionLoading, setRequestPermissionLoading] = useState(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 (
-
- Wallet not connected
-
- )
- }
- if (!supported) {
- return (
-
- Wallet does not support wallet_grantPermissions rpc method
-
- )
- }
+ }, [signer, provider, address, chain, grantPermissions, toast])
return (