Skip to content

Commit

Permalink
feat: added toAllowedParamsEnforcer impl and integrated support for t…
Browse files Browse the repository at this point in the history
…his caveat in wallet eip1193provider
  • Loading branch information
SahilVasava committed Aug 9, 2024
1 parent 214c9c5 commit 0c34df3
Show file tree
Hide file tree
Showing 13 changed files with 540 additions and 86 deletions.
250 changes: 177 additions & 73 deletions packages/test/v0.7/multiTenantSessionAccount.test.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,21 @@
// @ts-expect-error
import { beforeAll, describe, test } from "bun:test"
import {
type KernelAccountClient,
type KernelSmartAccount,
KernelV3AccountAbi
} from "@zerodev/sdk"
import type { KernelAccountClient, KernelSmartAccount } from "@zerodev/sdk"
import { getInstallDMAsExecutorCallData } from "@zerodev/session-account"
import {
type BundlerClient,
ENTRYPOINT_ADDRESS_V07,
bundlerActions
} from "permissionless"
import { SmartAccount } from "permissionless/accounts"
import { paymasterActionsEip7677 } from "permissionless/experimental/eip7677/clients/decorators/paymasterActionsEip7677"
import { type BundlerClient, bundlerActions } from "permissionless"
import type { ENTRYPOINT_ADDRESS_V07_TYPE } from "permissionless/types/entrypoint"
import {
type Chain,
type Hex,
type PublicClient,
type Transport,
concatHex,
encodeAbiParameters,
encodeFunctionData,
parseAbiParameters,
zeroAddress
zeroAddress,
decodeErrorResult,
encodeFunctionData
} from "viem"
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts"
import type { SessionAccount } from "../../../plugins/multi-tenant-session-account"
import { dmActionsEip7710 } from "../../../plugins/multi-tenant-session-account/clients"
import {
DMVersionToAddressMap,
ROOT_AUTHORITY
} from "../../../plugins/multi-tenant-session-account/constants"
import { ROOT_AUTHORITY } from "../../../plugins/multi-tenant-session-account/constants"
import type { Delegation } from "../../../plugins/multi-tenant-session-account/types"
import type { YiSubAccount } from "../../../plugins/yiSubAccount"
import { toAllowedTargetsEnforcer } from "../../../plugins/yiSubAccount/enforcers/allowed-targets/toAllowedTargetsEnforcer"
Expand All @@ -41,9 +25,15 @@ import {
getKernelAccountClient,
getPublicClient,
getSessionAccount,
getSignerToEcdsaKernelAccount,
getZeroDevPaymasterClient
getZeroDevPaymasterClient,
mintToAccount
} from "./utils"
import {
ParamCondition,
toAllowedParamsEnforcer
} from "@zerodev/session-account/enforcers"
import { TEST_ERC20Abi } from "../abis/Test_ERC20Abi"
import { Test_ERC20Address } from "../utils"

const TEST_TIMEOUT = 1000000

Expand All @@ -67,6 +57,22 @@ describe("Yi SubAccount", () => {
>
let delegations: Delegation[]

const res=decodeErrorResult({
abi: [
{
inputs: [
{
type: "string"
}
],
name: "Error",
type: "error"
}
],
data: "0x08c379a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000033416c6c6f776564506172616d73456e666f726365723a6e6f2d6d61746368696e672d7065726d697373696f6e732d666f756e6400000000000000000000000000"
})
console.log({res})

beforeAll(async () => {
const ownerPrivateKey = process.env.TEST_PRIVATE_KEY
if (!ownerPrivateKey) {
Expand All @@ -90,65 +96,163 @@ describe("Yi SubAccount", () => {
})

bundlerClient = kernelClient.extend(bundlerActions(getEntryPoint()))
})

const caveat = toAllowedTargetsEnforcer({
targets: [zeroAddress]
})
const caveats = []
const privateSessionKey = generatePrivateKey()
const sessionKeyAccount = privateKeyToAccount(privateSessionKey)
delegations = [
{
delegator: mainDelegatorAccount.address,
delegate: sessionKeyAccount.address,
authority: ROOT_AUTHORITY,
caveats,
salt: 0n,
signature: "0x"
}
]
test(
"Send a sudo tx without caveat from kernelAccount through sessionAccount",
async () => {
const caveats = []
const privateSessionKey = generatePrivateKey()
const sessionKeyAccount = privateKeyToAccount(privateSessionKey)
delegations = [
{
delegator: mainDelegatorAccount.address,
delegate: sessionKeyAccount.address,
authority: ROOT_AUTHORITY,
caveats,
salt: 0n,
signature: "0x"
}
]

const kernelClientDM = kernelClient.extend(
dmActionsEip7710<
ENTRYPOINT_ADDRESS_V07_TYPE,
KernelSmartAccount<ENTRYPOINT_ADDRESS_V07_TYPE>
>()
)
const kernelClientDM = kernelClient.extend(
dmActionsEip7710<
ENTRYPOINT_ADDRESS_V07_TYPE,
KernelSmartAccount<ENTRYPOINT_ADDRESS_V07_TYPE>
>()
)

const mainDeleGatorSignature = await kernelClientDM.signDelegation({
delegation: delegations[0]
})
console.log({ mainDeleGatorSignature })
delegations[0].signature = mainDeleGatorSignature
const initCode = await mainDelegatorAccount.getInitCode()
sessionAccount = await getSessionAccount(
delegations,
privateSessionKey,
initCode
)
sessionAccountClient = await getKernelAccountClient({
// @ts-ignore: fix return type error
account: sessionAccount,
middleware: {
sponsorUserOperation: async ({ userOperation }) => {
const zeroDevPaymaster = getZeroDevPaymasterClient()
return zeroDevPaymaster.sponsorUserOperation({
userOperation,
entryPoint: getEntryPoint()
})
const mainDeleGatorSignature = await kernelClientDM.signDelegation({
delegation: delegations[0]
})
console.log({ mainDeleGatorSignature })
delegations[0].signature = mainDeleGatorSignature
const initCode = await mainDelegatorAccount.getInitCode()
sessionAccount = await getSessionAccount(
delegations,
privateSessionKey,
initCode
)
sessionAccountClient = await getKernelAccountClient({
// @ts-ignore: fix return type error
account: sessionAccount,
middleware: {
sponsorUserOperation: async ({ userOperation }) => {
const zeroDevPaymaster = getZeroDevPaymasterClient()
return zeroDevPaymaster.sponsorUserOperation({
userOperation,
entryPoint: getEntryPoint()
})
}
}
}
})
})
})
const userOpHash = await sessionAccountClient.sendUserOperation({
userOperation: {
callData: await sessionAccount.encodeCallData({
to: zeroAddress,
data: "0x",
value: 0n
}),
preVerificationGas: 84700n,
callGasLimit: 1273781n,
verificationGasLimit: 726789n
}
})
const receipt = await bundlerClient.waitForUserOperationReceipt({
hash: userOpHash
})
console.log(
"transactionHash",
`https://sepolia.etherscan.io/tx/${receipt.receipt.transactionHash}`
)
},
TEST_TIMEOUT
)

test(
"Send tx from subAccount through sessionAccount",
"Send tx with allowedParams caveats from kernelAccount through sessionAccount",
async () => {
const privateSessionKey = generatePrivateKey()
const sessionKeyAccount = privateKeyToAccount(privateSessionKey)
const allowedParamsCaveat = toAllowedParamsEnforcer({
permissions: [
{
abi: TEST_ERC20Abi,
target: Test_ERC20Address,
functionName: "transfer",
args: [
{
condition: ParamCondition.EQUAL,
value: sessionKeyAccount.address
},
null
]
}
]
})
const caveats = [allowedParamsCaveat]

delegations = [
{
delegator: mainDelegatorAccount.address,
delegate: sessionKeyAccount.address,
authority: ROOT_AUTHORITY,
caveats,
salt: 0n,
signature: "0x"
}
]

const kernelClientDM = kernelClient.extend(
dmActionsEip7710<
ENTRYPOINT_ADDRESS_V07_TYPE,
KernelSmartAccount<ENTRYPOINT_ADDRESS_V07_TYPE>
>()
)

const mainDeleGatorSignature = await kernelClientDM.signDelegation({
delegation: delegations[0]
})
console.log({ mainDeleGatorSignature })
delegations[0].signature = mainDeleGatorSignature
const initCode = await mainDelegatorAccount.getInitCode()
sessionAccount = await getSessionAccount(
delegations,
privateSessionKey,
initCode
)
sessionAccountClient = await getKernelAccountClient({
// @ts-ignore: fix return type error
account: sessionAccount,
middleware: {
sponsorUserOperation: async ({ userOperation }) => {
const zeroDevPaymaster = getZeroDevPaymasterClient()
return zeroDevPaymaster.sponsorUserOperation({
userOperation,
entryPoint: getEntryPoint()
})
}
}
})

await mintToAccount(
kernelClient.account.client as PublicClient,
kernelClient,
kernelClient.account.address,
100000000n
)

const amountToTransfer = 10000n
const transferData = encodeFunctionData({
abi: TEST_ERC20Abi,
functionName: "transfer",
args: [sessionKeyAccount.address, amountToTransfer]
})
const userOpHash = await sessionAccountClient.sendUserOperation({
userOperation: {
callData: await sessionAccount.encodeCallData({
to: zeroAddress,
data: "0x",
to: Test_ERC20Address,
data: transferData,
value: 0n
}),
preVerificationGas: 84700n,
Expand Down
4 changes: 2 additions & 2 deletions packages/test/v0.7/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -275,12 +275,12 @@ export const getSessionAccount = async (
privateKey: Hex,
delegatorInitCode?: Hex
) => {
const sessionKeyAccount = privateKeyToAccount(privateKey)
const sessionKeySigner = privateKeyToAccount(privateKey)
const publicClient = await getPublicClient()

return createSessionAccount(publicClient, {
entryPoint: getEntryPoint(),
sessionKeyAccount,
sessionKeySigner,
delegations,
delegatorInitCode
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export type CreateSessionAccountParameters<
TAddress extends Address = Address
> = {
entryPoint: entryPoint
sessionKeyAccount: SmartAccountSigner<TSource, TAddress>
sessionKeySigner: SmartAccountSigner<TSource, TAddress>
delegations: Delegation[]
multiTenantSessionAccountAddress?: Address
delegatorInitCode?: Hex
Expand All @@ -75,14 +75,14 @@ export async function createSessionAccount<
{
entryPoint: entryPointAddress,
delegations,
sessionKeyAccount,
sessionKeySigner,
multiTenantSessionAccountAddress:
accountAddress = MULTI_TENANT_SESSION_ACCOUNT_ADDRESS,
delegatorInitCode = "0x"
}: CreateSessionAccountParameters<entryPoint, TSource, TAddress>
): Promise<SessionAccount<entryPoint, TTransport, TChain>> {
const viemSigner: LocalAccount = {
...sessionKeyAccount,
...sessionKeySigner,
signTransaction: (_, __) => {
throw new SignTransactionNotSupportedBySmartAccount()
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export enum CallType {
CALL = "0x00",
BATCH_CALL = "0x01",
DELEGATE_CALL = "0xff"
}

export enum ParamCondition {
EQUAL = 0,
GREATER_THAN = 1,
LESS_THAN = 2,
GREATER_THAN_OR_EQUAL = 3,
LESS_THAN_OR_EQUAL = 4,
NOT_EQUAL = 5,
ONE_OF = 6
}

export const AllowedParamsEnforcerAddress =
"0x54F1f6aAe77D2E3feA4c40A7d99E4aDcEFa00c79"
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from "./toAllowedParamsEnforcer.js"
export * from "./utils.js"
export type * from "./types.js"
export * from "./constants.js"
Loading

0 comments on commit 0c34df3

Please sign in to comment.