Skip to content

Commit

Permalink
feat: added MerklePolicy
Browse files Browse the repository at this point in the history
  • Loading branch information
SahilVasava committed Feb 12, 2024
1 parent 2c9e1c8 commit c3905d0
Show file tree
Hide file tree
Showing 18 changed files with 869 additions and 88 deletions.
Binary file modified bun.lockb
Binary file not shown.
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,8 @@
},
"simple-git-hooks": {
"pre-commit": "bun run format && bun run lint:fix"
},
"dependencies": {
"merkletreejs": "^0.3.11"
}
}
154 changes: 151 additions & 3 deletions packages/test/modularPermissionKernelAccount.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,32 @@
import { beforeAll, describe, expect, test } from "bun:test"
import { http, PublicClient, createPublicClient, zeroAddress } from "viem"
import { KernelAccountClient, KernelSmartAccount } from "@zerodev/sdk"
import {
http,
Address,
Chain,
Hex,
PrivateKeyAccount,
PublicClient,
Transport,
createPublicClient,
encodeFunctionData,
parseEther,
zeroAddress
} from "viem"
import { privateKeyToAccount } from "viem/accounts"
import { polygonMumbai } from "viem/chains"
import { toGasPolicy } from "../../plugins/modularPermission/policies/toGasPolicy"
import {
ParamOperator,
toMerklePolicy
} from "../../plugins/modularPermission/policies/toMerklePolicy"
import { TEST_ERC20Abi } from "./abis/Test_ERC20Abi"
import {
Test_ERC20Address,
getEntryPoint,
getKernelAccountClient,
getPublicClient,
getSignerToEcdsaKernelAccount,
getSignerToModularPermissionKernelAccount,
getZeroDevPaymasterClient
} from "./utils"
Expand All @@ -13,17 +35,74 @@ const TEST_TIMEOUT = 1000000

describe("Modular Permission kernel Account", async () => {
let publicClient: PublicClient
let accountAddress: Address
let testPrivateKey: Hex
let owner: PrivateKeyAccount

let ecdsaSmartAccountClient: KernelAccountClient<
Transport,
Chain,
KernelSmartAccount
>

async function mintToAccount(amount: bigint) {
const balanceBefore = await publicClient.readContract({
abi: TEST_ERC20Abi,
address: Test_ERC20Address,
functionName: "balanceOf",
args: [accountAddress]
})

const amountToMint = balanceBefore > amount ? 0n : amount

const mintData = encodeFunctionData({
abi: TEST_ERC20Abi,
functionName: "mint",
args: [accountAddress, amountToMint]
})

if (amountToMint > 0n) {
const mintTransactionHash =
await ecdsaSmartAccountClient.sendTransaction({
to: Test_ERC20Address,
data: mintData
})
console.log(
"mintTransactionHash",
`https://mumbai.polygonscan.com/tx/${mintTransactionHash}`
)
}
}

beforeAll(async () => {
publicClient = await getPublicClient()
testPrivateKey = process.env.TEST_PRIVATE_KEY as Hex
owner = privateKeyToAccount(testPrivateKey)
ecdsaSmartAccountClient = await getKernelAccountClient({
account: await getSignerToEcdsaKernelAccount(),
sponsorUserOperation: async ({ userOperation }) => {
const kernelPaymaster = getZeroDevPaymasterClient()
const entryPoint = getEntryPoint()
return kernelPaymaster.sponsorUserOperation({
userOperation,
entryPoint
})
}
})
accountAddress = (await ecdsaSmartAccountClient.account
?.address) as Address
})

test(
"should send a tx",
"should execute a transaction using GasPolicy",
async () => {
const modularPermissionSmartAccountClient =
await getKernelAccountClient({
account: await getSignerToModularPermissionKernelAccount(),
account: await getSignerToModularPermissionKernelAccount([
await toGasPolicy({
maxGasAllowedInWei: 1000000000000000000n
})
]),
sponsorUserOperation: async ({ userOperation }) => {
const kernelPaymaster = getZeroDevPaymasterClient()
const entryPoint = getEntryPoint()
Expand All @@ -44,4 +123,73 @@ describe("Modular Permission kernel Account", async () => {
},
TEST_TIMEOUT
)

test(
"should execute the erc20 token transfer action using MerklePolicy",
async () => {
await mintToAccount(100000000n)
const amountToTransfer = 10000n
const transferData = encodeFunctionData({
abi: TEST_ERC20Abi,
functionName: "transfer",
args: [owner.address, amountToTransfer]
})

const balanceOfReceipientBefore = await publicClient.readContract({
abi: TEST_ERC20Abi,
address: Test_ERC20Address,
functionName: "balanceOf",
args: [owner.address]
})
const modularPermissionSmartAccountClient =
await getKernelAccountClient({
account: await getSignerToModularPermissionKernelAccount([
await toGasPolicy({
maxGasAllowedInWei: 1000000000000000000n
}),
await toMerklePolicy({
permissions: [
{
target: Test_ERC20Address,
abi: TEST_ERC20Abi,
functionName: "transfer",
args: [
{
operator: ParamOperator.EQUAL,
value: owner.address
},
null
]
}
]
})
]),
sponsorUserOperation: async ({ userOperation }) => {
const kernelPaymaster = getZeroDevPaymasterClient()
const entryPoint = getEntryPoint()
return kernelPaymaster.sponsorUserOperation({
userOperation,
entryPoint
})
}
})

const txHash =
await modularPermissionSmartAccountClient.sendTransaction({
to: Test_ERC20Address,
data: transferData
})
console.log("txHash", `https://mumbai.polygonscan.com/tx/${txHash}`)
const balanceOfReceipientAfter = await publicClient.readContract({
abi: TEST_ERC20Abi,
address: Test_ERC20Address,
functionName: "balanceOf",
args: [owner.address]
})
expect(balanceOfReceipientAfter).toBe(
balanceOfReceipientBefore + amountToTransfer
)
},
TEST_TIMEOUT
)
})
71 changes: 34 additions & 37 deletions packages/test/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import {
import { type Chain, goerli } from "viem/chains"
import * as allChains from "viem/chains"
import { toGasPolicy } from "../../plugins/modularPermission/policies/toGasPolicy.js"
import { Policy } from "../../plugins/modularPermission/policies/types.js"
import { toECDSASigner } from "../../plugins/modularPermission/signers/toECDSASigner.js"
import { signerToModularPermissionValidator } from "../../plugins/modularPermission/toModularPermissionValidatorPlugin.js"
import { EntryPointAbi } from "./abis/EntryPoint.js"
Expand Down Expand Up @@ -235,46 +236,42 @@ export const getSignerToSessionKeyKernelAccount =
)
}

export const getSignerToModularPermissionKernelAccount =
async (): Promise<SmartAccount> => {
const privateKey = process.env.TEST_PRIVATE_KEY as Hex
if (!privateKey) {
throw new Error("TEST_PRIVATE_KEY environment variable not set")
}

const publicClient = await getPublicClient()
const signer = privateKeyToAccount(privateKey)
const sessionPrivateKey = generatePrivateKey()
const sessionKey = privateKeyToAccount(sessionPrivateKey)
const ecdsaValidatorPlugin = await signerToEcdsaValidator(
publicClient,
{
entryPoint: getEntryPoint(),
signer: { ...signer, source: "local" as "local" | "external" }
}
)
export const getSignerToModularPermissionKernelAccount = async (
policies: Policy[]
): Promise<SmartAccount> => {
const privateKey = process.env.TEST_PRIVATE_KEY as Hex
if (!privateKey) {
throw new Error("TEST_PRIVATE_KEY environment variable not set")
}

const ecdsaModularSigner = toECDSASigner({ signer: sessionKey })
const modularPermissionPlugin =
await signerToModularPermissionValidator(publicClient, {
signer: ecdsaModularSigner,
validatorData: {
policies: [
await toGasPolicy({
maxGasAllowedInWei: 1000000000000000000n
})
]
}
})
const publicClient = await getPublicClient()
const signer = privateKeyToAccount(privateKey)
const sessionPrivateKey = generatePrivateKey()
const sessionKey = privateKeyToAccount(sessionPrivateKey)
const ecdsaValidatorPlugin = await signerToEcdsaValidator(publicClient, {
entryPoint: getEntryPoint(),
signer: { ...signer, source: "local" as "local" | "external" }
})

return await createKernelAccount(publicClient, {
entryPoint: getEntryPoint(),
plugins: {
regular: modularPermissionPlugin,
sudo: ecdsaValidatorPlugin
const ecdsaModularSigner = toECDSASigner({ signer: sessionKey })
const modularPermissionPlugin = await signerToModularPermissionValidator(
publicClient,
{
signer: ecdsaModularSigner,
validatorData: {
policies
}
})
}
}
)

return await createKernelAccount(publicClient, {
entryPoint: getEntryPoint(),
plugins: {
regular: modularPermissionPlugin,
sudo: ecdsaValidatorPlugin
}
})
}

export const getSessionKeyToSessionKeyKernelAccount = async <
TTransport extends Transport = Transport,
Expand Down
13 changes: 13 additions & 0 deletions plugins/modularPermission/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export const MODULAR_PERMISSION_VALIDATOR_ADDRESS =
"0x965Bea0f8b65aABD1F5148F64654BbAAfB9d2Efa"
export const MAX_FLAG = "0xffffffffffffffffffffffff"
export const ECDSA_SIGNER_CONTRACT =
"0xF9E712F44A360ED8820aD624e41164f74a5a7456"
export const GAS_POLICY_CONTRACT = "0x62868E950Efbb336DCFf033598Ee5E602f0a93cD"
export const MERKLE_POLICY_CONTRACT =
"0xb808d75b5acf6b5513eb816d3980c733ae6be468"
export enum PolicyFlags {
FOR_ALL_VALIDATION = "0x000000000000000000000000",
NOT_FOR_VALIDATE_USEROP = "0x000000000000000000000001",
NOT_FOR_VALIDATE_SIG = "0x000000000000000000000002"
}
15 changes: 4 additions & 11 deletions plugins/modularPermission/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
export const MODULAR_PERMISSION_VALIDATOR_ADDRESS =
"0x965Bea0f8b65aABD1F5148F64654BbAAfB9d2Efa"
export const MAX_FLAG = "0xffffffffffffffffffffffff"
export const ECDSA_SIGNER_CONTRACT =
"0xF9E712F44A360ED8820aD624e41164f74a5a7456"
export const GAS_POLICY_CONTRACT = "0x62868E950Efbb336DCFf033598Ee5E602f0a93cD"
export enum PolicyFlags {
FOR_ALL_VALIDATION = "0x000000000000000000000000",
NOT_FOR_VALIDATE_USEROP = "0x000000000000000000000001",
NOT_FOR_VALIDATE_SIG = "0x000000000000000000000002"
}
export { signerToModularPermissionValidator } from "./toModularPermissionValidatorPlugin.js"
export * as constants from "./constants.js"
export type * from "./types.js"
export { ModularPermissionValidatorAbi } from "./abi/ModularPermissionValidatorAbi.js"
17 changes: 17 additions & 0 deletions plugins/modularPermission/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,23 @@
"lint": "biome check .",
"lint:fix": "bun run lint --apply"
},
"exports": {
".": {
"types": "./_types/index.d.ts",
"import": "./_esm/index.js",
"default": "./_cjs/index.js"
},
"./policies": {
"types": "./_types/policies/index.d.ts",
"import": "./_esm/policies/index.js",
"default": "./_cjs/policies/index.js"
},
"./signers": {
"types": "./_types/signers/index.d.ts",
"import": "./_esm/signers/index.js",
"default": "./_cjs/signers/index.js"
}
},
"dependencies": {
"merkletreejs": "^0.3.11"
},
Expand Down
8 changes: 8 additions & 0 deletions plugins/modularPermission/policies/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export { toGasPolicy, type GasPolicyParams } from "./toGasPolicy.js"
export {
toMerklePolicy,
type MerklePolicyParams,
Operation,
ParamOperator
} from "./toMerklePolicy.js"
export type * from "./types.js"
Loading

0 comments on commit c3905d0

Please sign in to comment.