Skip to content

Commit

Permalink
feat: add optional param account loupe address to msca
Browse files Browse the repository at this point in the history
  • Loading branch information
denniswon committed Dec 4, 2023
1 parent 669e96c commit 5d1f24e
Show file tree
Hide file tree
Showing 5 changed files with 270 additions and 3 deletions.
142 changes: 142 additions & 0 deletions packages/accounts/src/msca/abis/IAccountLoupe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
export const IAccountLoupeAbi = [
{
inputs: [
{
internalType: "bytes4",
name: "selector",
type: "bytes4",
},
],
name: "getExecutionFunctionConfig",
outputs: [
{
components: [
{
internalType: "address",
name: "plugin",
type: "address",
},
{
internalType: "FunctionReference",
name: "userOpValidationFunction",
type: "bytes21",
},
{
internalType: "FunctionReference",
name: "runtimeValidationFunction",
type: "bytes21",
},
],
internalType: "struct IAccountLoupe.ExecutionFunctionConfig",
name: "",
type: "tuple",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "bytes4",
name: "selector",
type: "bytes4",
},
],
name: "getExecutionHooks",
outputs: [
{
components: [
{
internalType: "FunctionReference",
name: "preExecHook",
type: "bytes21",
},
{
internalType: "FunctionReference",
name: "postExecHook",
type: "bytes21",
},
],
internalType: "struct IAccountLoupe.ExecutionHooks[]",
name: "",
type: "tuple[]",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "getInstalledPlugins",
outputs: [
{
internalType: "address[]",
name: "",
type: "address[]",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "address",
name: "callingPlugin",
type: "address",
},
{
internalType: "bytes4",
name: "selector",
type: "bytes4",
},
],
name: "getPermittedCallHooks",
outputs: [
{
components: [
{
internalType: "FunctionReference",
name: "preExecHook",
type: "bytes21",
},
{
internalType: "FunctionReference",
name: "postExecHook",
type: "bytes21",
},
],
internalType: "struct IAccountLoupe.ExecutionHooks[]",
name: "",
type: "tuple[]",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "bytes4",
name: "selector",
type: "bytes4",
},
],
name: "getPreValidationHooks",
outputs: [
{
internalType: "FunctionReference[]",
name: "preUserOpValidationHooks",
type: "bytes21[]",
},
{
internalType: "FunctionReference[]",
name: "preRuntimeValidationHooks",
type: "bytes21[]",
},
],
stateMutability: "view",
type: "function",
},
] as const;
48 changes: 48 additions & 0 deletions packages/accounts/src/msca/account-loupe/decorator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import type { Address, ISmartContractAccount } from "@alchemy/aa-core";
import type { Hash } from "viem";
import { IAccountLoupeAbi } from "../abis/IAccountLoupe.js";
import type { FunctionReference, IAccountLoupe } from "./types.js";

export const accountLoupeDecorators = (
account: ISmartContractAccount,
accountLoupeAddress: Address
): IAccountLoupe => ({
getExecutionFunctionConfig: async (selector: FunctionReference) =>
account.rpcProvider.readContract({
address: accountLoupeAddress,
abi: IAccountLoupeAbi,
functionName: "getExecutionFunctionConfig",
args: [selector],
}),

getExecutionHooks: async (selector: FunctionReference) =>
account.rpcProvider.readContract({
address: accountLoupeAddress,
abi: IAccountLoupeAbi,
functionName: "getExecutionHooks",
args: [selector],
}),

getPermittedCallHooks: async (callingPlugin: Address, selector: Hash) =>
account.rpcProvider.readContract({
address: accountLoupeAddress,
abi: IAccountLoupeAbi,
functionName: "getPermittedCallHooks",
args: [callingPlugin, selector],
}),

getPreValidationHooks: async (selector: Hash) =>
account.rpcProvider.readContract({
address: accountLoupeAddress,
abi: IAccountLoupeAbi,
functionName: "getPreValidationHooks",
args: [selector],
}),

getInstalledPlugins: async () =>
account.rpcProvider.readContract({
address: accountLoupeAddress,
abi: IAccountLoupeAbi,
functionName: "getInstalledPlugins",
}),
});
56 changes: 56 additions & 0 deletions packages/accounts/src/msca/account-loupe/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import type { Address, Hash, Hex } from "viem";

// Treats the first 20 bytes as an address, and the last byte as a identifier.
export type FunctionReference = Hex;

export type ExecutionFunctionConfig = {
plugin: Address;
userOpValidationFunction: FunctionReference;
runtimeValidationFunction: FunctionReference;
};

export type ExecutionHooks = {
preExecHook: FunctionReference;
postExecHook: FunctionReference;
};

export type PreValidationHooks = [
readonly FunctionReference[],
readonly FunctionReference[]
];

export interface IAccountLoupe {
/// @notice Gets the validation functions and plugin address for a selector
/// @dev If the selector is a native function, the plugin address will be the address of the account
/// @param selector The selector to get the configuration for
/// @return The configuration for this selector
getExecutionFunctionConfig(
selector: FunctionReference
): Promise<ExecutionFunctionConfig>;

/// @notice Gets the pre and post execution hooks for a selector
/// @param selector The selector to get the hooks for
/// @return The pre and post execution hooks for this selector
getExecutionHooks(
selector: FunctionReference
): Promise<ReadonlyArray<ExecutionHooks>>;

/// @notice Gets the pre and post permitted call hooks applied for a plugin calling this selector
/// @param callingPlugin The plugin that is calling the selector
/// @param selector The selector the plugin is calling
/// @return The pre and post permitted call hooks for this selector
getPermittedCallHooks(
callingPlugin: Address,
selector: Hash
): Promise<ReadonlyArray<ExecutionHooks>>;

/// @notice Gets the pre user op and runtime validation hooks associated with a selector
/// @param selector The selector to get the hooks for
/// @return preUserOpValidationHooks The pre user op validation hooks for this selector
/// @return preRuntimeValidationHooks The pre runtime validation hooks for this selector
getPreValidationHooks(selector: Hash): Promise<Readonly<PreValidationHooks>>;

/// @notice Gets an array of all installed plugins
/// @return The addresses of all installed plugins
getInstalledPlugins(): Promise<ReadonlyArray<Address>>;
}
17 changes: 17 additions & 0 deletions packages/accounts/src/msca/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import {
} from "viem";
import { z } from "zod";
import { IStandardExecutorAbi } from "./abis/IStandardExecutor.js";
import { accountLoupeDecorators } from "./account-loupe/decorator.js";
import type { IAccountLoupe } from "./account-loupe/types.js";
import { pluginManagerDecorator } from "./plugin-manager/decorator.js";
import type { Plugin } from "./plugins/types";

Expand All @@ -30,6 +32,10 @@ export interface IMSCA<
plugin: Plugin<AD, PD>
) => IMSCA<TTransport, TProviderDecorators & PD> & AD;

extendWithAccountLoupeMethods: <AD, PD>(
accountLoupeAddress: Address
) => IMSCA<TTransport, TProviderDecorators & PD> & AD & IAccountLoupe;

addProviderDecorator: <
PD,
TProvider extends ISmartAccountProvider<TTransport> & { account: IMSCA }
Expand Down Expand Up @@ -190,6 +196,17 @@ export class MSCABuilder {
return result as unknown as DynamicMSCA<TProviderDecorators & PD> & AD;
};

extendWithAccountLoupeMethods = <AD, PD>(
accountLoupeAddress: Address
): DynamicMSCA<TProviderDecorators & PD> & AD & IAccountLoupe => {
return Object.assign(
this,
accountLoupeDecorators(this, accountLoupeAddress)
) as unknown as DynamicMSCA<TProviderDecorators & PD> &
AD &
IAccountLoupe;
};

addProviderDecorator = <
PD,
TProvider extends ISmartAccountProvider<TTransport> & { account: IMSCA }
Expand Down
10 changes: 7 additions & 3 deletions packages/accounts/src/msca/multi-owner-account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
type SignTypedDataParams,
type SupportedTransports,
} from "@alchemy/aa-core";
import { Address as zAddress } from "abitype/zod";
import {
concatHex,
encodeFunctionData,
Expand All @@ -26,6 +27,7 @@ export const createMultiOwnerMSCASchema = <
>() =>
createBaseSmartAccountParamsSchema<TTransport>().extend({
owner: SignerSchema,
accountLoupeAddress: zAddress.optional(),
index: z.bigint().optional().default(0n),
});

Expand Down Expand Up @@ -120,9 +122,11 @@ export const createMultiOwnerMSCA = <
const params = createMultiOwnerMSCASchema<TTransport>().parse(params_);
const builder = createMultiOwnerMSCABuilder<TTransport>(params);

const account = builder
.build(params)
.extendWithPluginMethods(MultiOwnerPlugin);
let account = builder.build(params).extendWithPluginMethods(MultiOwnerPlugin);

if (params.accountLoupeAddress != null) {
account = account.extendWithAccountLoupeMethods(params.accountLoupeAddress);
}

return account;
};

0 comments on commit 5d1f24e

Please sign in to comment.