Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
33 changes: 17 additions & 16 deletions plugins/permission/policies/toCallPolicy.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Abi, Address, Hex } from "viem"
import type { Abi, Address, Hex, Narrow } from "viem"
import { concatHex, pad } from "viem"
import {
CALL_POLICY_CONTRACT_V0_0_1,
Expand All @@ -13,7 +13,7 @@ import {
encodePermissionData,
getPermissionFromABI
} from "./callPolicyUtils.js"
import { CallType, type Permission } from "./types.js"
import { CallType, type InferPermissions, type Permission } from "./types.js"

export enum CallPolicyVersion {
V0_0_1 = "0.0.1",
Expand Down Expand Up @@ -43,31 +43,32 @@ export const getCallPolicyAddress = (
}

export type CallPolicyParams<
TAbi extends Abi | readonly unknown[],
TFunctionName extends string | undefined = string
permissions extends readonly Permission<
Abi,
string
>[] = readonly Permission<Abi, string>[]
> = PolicyParams & {
policyVersion: CallPolicyVersion
permissions?: Permission<TAbi, TFunctionName>[]
permissions?: InferPermissions<Narrow<permissions>>
}

export function toCallPolicy<
TAbi extends Abi | readonly unknown[],
TFunctionName extends string | undefined = string
const permissions extends readonly Permission<Abi, string>[]
>({
policyAddress,
policyFlag = PolicyFlags.FOR_ALL_VALIDATION,
policyVersion,
permissions = []
}: CallPolicyParams<TAbi, TFunctionName>): Policy {
permissions: inputPermissions
}: CallPolicyParams<permissions>): Policy {
const callPolicyAddress = getCallPolicyAddress(policyVersion, policyAddress)

const generatedPermissionParams = permissions?.map((perm) => {
const generatedPermissionParams = inputPermissions?.map((perm) => {
// Natural discrimination: if abi and functionName are present, do ABI-based validation
if (perm.abi && perm.functionName) {
return getPermissionFromABI({
abi: perm.abi as Abi,
functionName: perm.functionName as string,
args: perm.args as [],
args: perm.args,
policyAddress: callPolicyAddress,
selector: perm.selector
})
Expand All @@ -80,8 +81,8 @@ export function toCallPolicy<
}
})

permissions =
permissions?.map((perm, index) => ({
const processedPermissions =
inputPermissions?.map((perm, index) => ({
...perm,
callType: perm.callType ?? CallType.CALL,
selector:
Expand All @@ -96,7 +97,7 @@ export function toCallPolicy<
})) ?? []

const encodedPermissionData = encodePermissionData(
permissions,
processedPermissions,
callPolicyAddress
)

Expand All @@ -112,8 +113,8 @@ export function toCallPolicy<
policyVersion,
policyAddress,
policyFlag,
permissions
} as unknown as CallPolicyParams<Abi | readonly unknown[], string> & {
permissions: processedPermissions
} as unknown as CallPolicyParams<permissions> & {
type: "call"
}
}
Expand Down
44 changes: 43 additions & 1 deletion plugins/permission/policies/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import type {
AbiParameterToPrimitiveType,
AbiStateMutability,
Address,
ContractFunctionName,
Hex,
Narrow
Narrow,
Prettify
} from "viem"

export enum CallType {
Expand Down Expand Up @@ -156,3 +158,43 @@ export type GeneratePermissionFromArgsParameters<
: _FunctionName extends string
? { abi: [Narrow<TAbi[number]>] } & GetFunctionArgs<TAbi, _FunctionName>
: never)

// infer permission parameters from `unknown` - similar to GetMulticallContractParameters
export type GetPermissionParameters<permission> = permission extends {
abi: infer abi extends Abi
} // 1. Check if `abi` is const-asserted or defined inline
? // 1a. Check if `functionName` is valid for `abi`
permission extends {
functionName: infer functionName extends ContractFunctionName<abi>
}
? // Use PermissionWithABI which supports CombinedArgs
PermissionWithABI<abi, functionName>
: // 1b. `functionName` is invalid, check if `abi` is declared as `Abi`
Abi extends abi
? PermissionWithABI<abi, string> // `abi` declared as `Abi`, unable to infer types further
: // `abi` is const-asserted or defined inline, infer types for `functionName` and `args`
PermissionWithABI<abi, string>
: permission extends { target: Address } // manual permission
? PermissionManual
: never // invalid permission

// Process permissions array - similar to MulticallContracts
export type InferPermissions<
permissions extends readonly unknown[],
result extends readonly unknown[] = []
> = permissions extends readonly [] // no permissions, return empty
? readonly []
: permissions extends readonly [infer permission] // one permission left before returning `result`
? readonly [...result, Prettify<GetPermissionParameters<permission>>]
: permissions extends readonly [infer permission, ...infer rest] // grab first permission and recurse through `rest`
? InferPermissions<
[...rest],
[...result, Prettify<GetPermissionParameters<permission>>]
>
: readonly unknown[] extends permissions
? permissions
: // If `permissions` is *some* array but we couldn't assign `unknown[]` to it, then it must hold some known/homogenous type!
permissions extends readonly (infer permission)[]
? readonly Prettify<GetPermissionParameters<permission>>[]
: // Fallback
readonly Permission<Abi, string>[]
4 changes: 2 additions & 2 deletions plugins/permission/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type {
GetKernelVersion,
PluginValidityData
} from "@zerodev/sdk/types"
import type { Abi, Address, Hex, LocalAccount } from "viem"
import type { Address, Hex, LocalAccount } from "viem"
import type { EntryPointVersion } from "viem/account-abstraction"
import type { SignAuthorizationReturnType } from "viem/accounts"
import type { PolicyFlags } from "./constants.js"
Expand Down Expand Up @@ -42,7 +42,7 @@ export type Policy = {
getPolicyInfoInBytes: () => Hex
// return params directly to serialize/deserialize Policy
policyParams:
| (CallPolicyParams<Abi | readonly unknown[], string> & {
| (CallPolicyParams & {
type: "call"
})
| (GasPolicyParams & { type: "gas" })
Expand Down
Loading