Skip to content

Commit

Permalink
Merge pull request #165 from pimlicolabs/reduce-chainid-call
Browse files Browse the repository at this point in the history
Add getPackedUserOperation
  • Loading branch information
plusminushalf authored Apr 10, 2024
2 parents 9ae6994 + 84d841d commit 8323c8e
Show file tree
Hide file tree
Showing 6 changed files with 163 additions and 4 deletions.
5 changes: 5 additions & 0 deletions .changeset/early-dogs-dream.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"permissionless": patch
---

Added util function getPackedUserOperation
29 changes: 25 additions & 4 deletions packages/permissionless-test/ep-0.7/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@ import {
getSenderAddress,
getUserOperationHash
} from "permissionless"
import type { PackedUserOperation } from "permissionless/types"
import {
getPackedUserOperation,
getRequiredPrefund,
signUserOperationHashWithECDSA
} from "permissionless/utils"
import {
Address,
Hash,
Hex,
WalletClient,
type Address,
type Hash,
type Hex,
type WalletClient,
encodeFunctionData,
zeroAddress
} from "viem"
Expand Down Expand Up @@ -241,4 +243,23 @@ describe("test public actions and utils", () => {
userOperation.maxFeePerGas
)
})

test("getPackedUserOperation", async () => {
const smartAccountClient = await getSmartAccountClient()

const userOperation =
await smartAccountClient.prepareUserOperationRequest({
userOperation: {
callData: await smartAccountClient.account.encodeCallData({
to: zeroAddress,
value: 0n,
data: "0x"
})
}
})

const packedUserOperation = getPackedUserOperation(userOperation)

expectTypeOf(packedUserOperation).toMatchTypeOf<PackedUserOperation>()
})
})
2 changes: 2 additions & 0 deletions packages/permissionless/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ export type {
EntryPoint
} from "./entrypoint"

export type { PackedUserOperation } from "./userOperation"

export type GetAccountParameterWithClient<
TTransport extends Transport = Transport,
TChain extends Chain | undefined = Chain | undefined,
Expand Down
14 changes: 14 additions & 0 deletions packages/permissionless/types/userOperation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,17 @@ export type UserOperation<entryPointVersion extends EntryPointVersion> =
initCode?: never
paymasterAndData?: never
}

export type Hex32 = `0x${string & { length: 64 }}`

export type PackedUserOperation = {
sender: Address
nonce: bigint
initCode: Hex
callData: Hex
accountGasLimits: Hex32
preVerificationGas: bigint
gasFees: Hex32
paymasterAndData: Hex
signature: Hex
}
114 changes: 114 additions & 0 deletions packages/permissionless/utils/getPackedUserOperation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import { type Hex, concat, getAddress, pad, slice, toHex } from "viem"
import type { UserOperation } from "../types/userOperation"
import type { Hex32, PackedUserOperation } from "../types/userOperation"

export function getInitCode(unpackedUserOperation: UserOperation<"v0.7">) {
return unpackedUserOperation.factory
? concat([
unpackedUserOperation.factory,
unpackedUserOperation.factoryData || ("0x" as Hex)
])
: "0x"
}

export function unPackInitCode(initCode: Hex) {
if (initCode === "0x") {
return {
factory: null,
factoryData: null
}
}
return {
factory: getAddress(slice(initCode, 0, 20)),
factoryData: slice(initCode, 20)
}
}

export function getAccountGasLimits(
unpackedUserOperation: UserOperation<"v0.7">
) {
return concat([
pad(toHex(unpackedUserOperation.verificationGasLimit), {
size: 16
}),
pad(toHex(unpackedUserOperation.callGasLimit), { size: 16 })
]) as Hex32
}

export function unpackAccountGasLimits(accountGasLimits: Hex) {
return {
verificationGasLimit: BigInt(slice(accountGasLimits, 0, 16)),
callGasLimit: BigInt(slice(accountGasLimits, 16))
}
}

export function getGasLimits(unpackedUserOperation: UserOperation<"v0.7">) {
return concat([
pad(toHex(unpackedUserOperation.maxPriorityFeePerGas), {
size: 16
}),
pad(toHex(unpackedUserOperation.maxFeePerGas), { size: 16 })
]) as Hex32
}

export function unpackGasLimits(gasLimits: Hex) {
return {
maxPriorityFeePerGas: BigInt(slice(gasLimits, 0, 16)),
maxFeePerGas: BigInt(slice(gasLimits, 16))
}
}

export function getPaymasterAndData(
unpackedUserOperation: UserOperation<"v0.7">
) {
return unpackedUserOperation.paymaster
? concat([
unpackedUserOperation.paymaster,
pad(
toHex(
unpackedUserOperation.paymasterVerificationGasLimit || 0n
),
{
size: 16
}
),
pad(toHex(unpackedUserOperation.paymasterPostOpGasLimit || 0n), {
size: 16
}),
unpackedUserOperation.paymasterData || ("0x" as Hex)
])
: "0x"
}

export function unpackPaymasterAndData(paymasterAndData: Hex) {
if (paymasterAndData === "0x") {
return {
paymaster: null,
paymasterVerificationGasLimit: null,
paymasterPostOpGasLimit: null,
paymasterData: null
}
}
return {
paymaster: getAddress(slice(paymasterAndData, 0, 20)),
paymasterVerificationGasLimit: BigInt(slice(paymasterAndData, 20, 36)),
paymasterPostOpGasLimit: BigInt(slice(paymasterAndData, 36, 52)),
paymasterData: slice(paymasterAndData, 52)
}
}

export const getPackedUserOperation = (
userOperation: UserOperation<"v0.7">
): PackedUserOperation => {
return {
sender: userOperation.sender,
nonce: userOperation.nonce,
initCode: getInitCode(userOperation),
callData: userOperation.callData,
accountGasLimits: getAccountGasLimits(userOperation),
preVerificationGas: userOperation.preVerificationGas,
gasFees: getGasLimits(userOperation),
paymasterAndData: getPaymasterAndData(userOperation),
signature: userOperation.signature
}
}
3 changes: 3 additions & 0 deletions packages/permissionless/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ import {
getEntryPointVersion
} from "./getEntryPointVersion"

import { getPackedUserOperation } from "./getPackedUserOperation"

export {
transactionReceiptStatus,
deepHexlify,
Expand All @@ -45,6 +47,7 @@ export {
isSmartAccountDeployed,
providerToSmartAccountSigner,
getAddressFromInitCodeOrPaymasterAndData,
getPackedUserOperation,
getEntryPointVersion,
ENTRYPOINT_ADDRESS_V06,
ENTRYPOINT_ADDRESS_V07
Expand Down

0 comments on commit 8323c8e

Please sign in to comment.