Skip to content

Commit

Permalink
feat: x
Browse files Browse the repository at this point in the history
  • Loading branch information
howydev committed Dec 19, 2024
1 parent 0c590bb commit 0f5fb16
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 262 deletions.
16 changes: 0 additions & 16 deletions aa-sdk/core/src/errors/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,19 +101,3 @@ export class EntityIdOverrideError extends BaseError {
);
}
}

/**
* Error class denoting that the provided entity id is invalid because it's overriding the native entity id.
*/
export class EntityIdOverrideError extends BaseError {
override name = "InvalidNonceKeyError";

/**
* Initializes a new instance of the error message with a default message indicating that the nonce key is invalid.
*/
constructor() {
super(
`Installing entityId of 0 overrides the owner's entity id in the account`
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,38 +9,71 @@ import {
createBundlerClient,
getEntryPoint,
toSmartContractAccount,
getAccountAddress,
InvalidEntityIdError,
InvalidNonceKeyError,
} from "@aa-sdk/core";
import {
concatHex,
encodeFunctionData,
getContract,
maxUint32,
maxUint152,
zeroAddress,
type Address,
type Chain,
type Hex,
type Transport,
} from "viem";
import { accountFactoryAbi } from "../abis/accountFactoryAbi.js";
import { getDefaultMAV2FactoryAddress } from "../utils.js";
import {
getDefaultMAV2FactoryAddress,
DEFAULT_OWNER_ENTITY_ID,
} from "../utils.js";
import { singleSignerMessageSigner } from "../modules/single-signer-validation/signer.js";
import { modularAccountAbi } from "../abis/modularAccountAbi.js";
import { serializeModuleEntity } from "../actions/common/utils.js";

const executeUserOpSelector: Hex = "0x8DD7712F";

export const DEFAULT_OWNER_ENTITY_ID = 0;

export type SignerEntity = {
isGlobalValidation: boolean;
entityId: number;
};

export type ExecutionDataView = {
module: Address;
skipRuntimeValidation: boolean;
allowGlobalValidation: boolean;
executionHooks: readonly Hex[];
};

export type ValidationDataView = {
validationHooks: readonly Hex[];
executionHooks: readonly Hex[];
selectors: readonly Hex[];
validationFlags: number;
};

export type ValidationDataParams =
| {
validationModuleAddress: Address;
entityId?: never;
}
| {
validationModuleAddress?: never;
entityId: number;
};

export type SMAV2Account<
TSigner extends SmartAccountSigner = SmartAccountSigner
> = SmartContractAccountWithSigner<"SMAV2Account", TSigner, "0.7.0"> &
SignerEntity;
SignerEntity & {
getExecutionData: (selector: Hex) => Promise<ExecutionDataView>;
getValidationData: (
args: ValidationDataParams
) => Promise<ValidationDataView>;
encodeCallData: (callData: Hex) => Promise<Hex>;
};

export type CreateSMAV2AccountParams<
TTransport extends Transport = Transport,
Expand Down Expand Up @@ -84,7 +117,7 @@ export async function createSMAV2Account(
accountAddress,
entryPoint = getEntryPoint(chain, { version: "0.7.0" }),
isGlobalValidation = true,
entityId = 0,
entityId = DEFAULT_OWNER_ENTITY_ID,
} = config;

if (entityId > Number(maxUint32)) {
Expand Down Expand Up @@ -176,10 +209,10 @@ export async function createSMAV2Account(
BigInt(entityId << 8) +
(isGlobalValidation ? 1n : 0n);

return entryPointContract.read.getNonce([
return await entryPointContract.read.getNonce([
baseAccount.address,
fullNonceKey,
]) as Promise<bigint>;
]);
};

const accountContract = getContract({
Expand All @@ -190,15 +223,25 @@ export async function createSMAV2Account(

const getExecutionData = async (selector: Hex) => {
if (!(await baseAccount.isAccountDeployed())) {
return {} as ExecutionDataView;
return {
module: zeroAddress,
skipRuntimeValidation: false,
allowGlobalValidation: false,
executionHooks: [],
};
}

return await accountContract.read.getExecutionData([selector]);
};

const getValidationData = async (args: ValidationDataParams) => {
if (!(await baseAccount.isAccountDeployed())) {
return {} as ValidationDataView;
return {
validationHooks: [],
executionHooks: [],
selectors: [],
validationFlags: 0,
};
}

const { validationModuleAddress, entityId } = args;
Expand All @@ -215,9 +258,9 @@ export async function createSMAV2Account(
entityId: Number(entityId),
});

const numHooks = validationData?.executionHooks?.length ?? 0;

return numHooks ? concatHex([executeUserOpSelector, callData]) : callData;
return validationData.executionHooks.length
? concatHex([executeUserOpSelector, callData])
: callData;
};

return {
Expand All @@ -226,5 +269,8 @@ export async function createSMAV2Account(
getSigner: () => signer,
isGlobalValidation,
entityId,
getExecutionData,
getValidationData,
encodeCallData,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import {
IncompatibleClientError,
isSmartAccountClient,
EntityIdOverrideError,
type GetAccountParameter,
type GetEntryPointFromAccount,
type SendUserOperationResult,
type UserOperationOverridesParameter,
type SmartAccountSigner,
} from "@aa-sdk/core";
import {
encodeFunctionData,
Expand All @@ -24,10 +24,11 @@ import {
serializeModuleEntity,
} from "../common/utils.js";
import type { SMAV2Account } from "../../account/semiModularAccountV2.js";
import type { SMASmartAccountClient } from "../../client/client.js";
import { DEFAULT_OWNER_ENTITY_ID } from "../../utils.js";
import { type SMAV2AccountClient } from "../../client/client.js";

export type InstallValidationParams<
TSMAV2Account extends SMAV2Account | undefined = SMAV2Account | undefined
TSigner extends SmartAccountSigner = SmartAccountSigner
> = {
validationConfig: ValidationConfig;
selectors: Hex[];
Expand All @@ -36,37 +37,39 @@ export type InstallValidationParams<
hookConfig: HookConfig;
initData: Hex;
}[];
} & UserOperationOverridesParameter<GetEntryPointFromAccount<TSMAV2Account>> &
GetAccountParameter<TSMAV2Account>;
account?: SMAV2Account<TSigner> | undefined;
} & UserOperationOverridesParameter<
GetEntryPointFromAccount<SMAV2Account<TSigner>>
>;

export type UninstallValidationParams<
TSMAV2Account extends SMAV2Account | undefined = SMAV2Account | undefined
TSigner extends SmartAccountSigner = SmartAccountSigner
> = {
moduleAddress: Address;
entityId: number;
uninstallData: Hex;
hookUninstallDatas: Hex[];
} & UserOperationOverridesParameter<GetEntryPointFromAccount<TSMAV2Account>> &
GetAccountParameter<TSMAV2Account>;
account?: SMAV2Account<TSigner> | undefined;
} & UserOperationOverridesParameter<
GetEntryPointFromAccount<SMAV2Account<TSigner>>
>;

export type InstallValidationActions<
TSMAV2Account extends SMAV2Account | undefined = SMAV2Account | undefined
TSigner extends SmartAccountSigner = SmartAccountSigner
> = {
installValidation: (
args: InstallValidationParams<TSMAV2Account>
args: InstallValidationParams<TSigner>
) => Promise<SendUserOperationResult>;
uninstallValidation: (
args: UninstallValidationParams<TSMAV2Account>
args: UninstallValidationParams<TSigner>
) => Promise<SendUserOperationResult>;
};

export const installValidationActions: <
TTransport extends Transport = Transport,
TChain extends Chain = Chain,
TSMAV2Account extends SMAV2Account = SMAV2Account
TSigner extends SmartAccountSigner = SmartAccountSigner
>(
client: SMASmartAccountClient<TTransport, TChain, TSMAV2Account>
) => InstallValidationActions<TSMAV2Account> = (client) => ({
client: SMAV2AccountClient<TSigner>
) => InstallValidationActions<TSigner> = (client) => ({
installValidation: async ({
validationConfig,
selectors,
Expand All @@ -87,7 +90,7 @@ export const installValidationActions: <
);
}

if (validationConfig.entityId === 0) {
if (validationConfig.entityId === DEFAULT_OWNER_ENTITY_ID) {
throw new EntityIdOverrideError();
}

Expand Down
7 changes: 2 additions & 5 deletions account-kit/smart-contracts/src/ma-v2/client/client.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import { custom, parseEther, publicActions } from "viem";
import { LocalAccountSigner, type SmartAccountSigner } from "@aa-sdk/core";
import {
createSMAV2AccountClient,
type SMASmartAccountClient,
} from "./client.js";
import { createSMAV2AccountClient, type SMAV2AccountClient } from "./client.js";
import { local070Instance } from "~test/instances.js";
import { setBalance } from "viem/actions";
import { accounts } from "~test/constants.js";
Expand Down Expand Up @@ -191,7 +188,7 @@ describe("MA v2 Tests", async () => {
}: {
signer: SmartAccountSigner;
accountAddress?: `0x${string}`;
}): Promise<SMASmartAccountClient> =>
}) =>
createSMAV2AccountClient({
chain: instance.chain,
signer,
Expand Down
26 changes: 7 additions & 19 deletions account-kit/smart-contracts/src/ma-v2/client/client.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,20 @@
import {
createSmartAccountClient,
type SmartContractAccount,
type SmartAccountClient,
type SmartAccountSigner,
type SmartAccountClientConfig,
type SmartAccountClientActions,
} from "@aa-sdk/core";

import { type Transport, type Chain, type CustomTransport } from "viem";
import { type Chain, type CustomTransport, type Transport } from "viem";

import {
createSMAV2Account,
type CreateSMAV2AccountParams,
type SMAV2Account,
} from "../account/semiModularAccountV2.js";

import {
type MAV2AccountClientActions,
mav2AccountActions,
} from "../decorators/modularAccountV2.js";
export type SMAV2AccountClient<
TSigner extends SmartAccountSigner = SmartAccountSigner
> = SmartAccountClient<Transport, Chain, SMAV2Account<TSigner>>;

export type CreateSMAV2AccountClientParams<
TTransport extends Transport = Transport,
Expand All @@ -35,15 +31,7 @@ export function createSMAV2AccountClient<
TSigner extends SmartAccountSigner = SmartAccountSigner
>(
args: CreateSMAV2AccountClientParams<Transport, TChain, TSigner>
): Promise<
SmartAccountClient<
CustomTransport,
TChain,
SMAV2Account<TSigner>,
SmartAccountClientActions<TChain, SmartContractAccount> &
MAV2AccountClientActions<TSigner, SMAV2Account<TSigner>>
>
>;
): Promise<SMAV2AccountClient<TSigner>>;

/**
* Creates a MAv2 account client using the provided configuration parameters.
Expand Down Expand Up @@ -76,13 +64,13 @@ export function createSMAV2AccountClient<
*/
export async function createSMAV2AccountClient({
...config
}: CreateSMAV2AccountClientParams): Promise<SmartAccountClient> {
}: CreateSMAV2AccountClientParams): Promise<SMAV2AccountClient> {
const maV2Account = await createSMAV2Account({
...config,
});

return createSmartAccountClient({
...config,
account: maV2Account,
}).extend(mav2AccountActions);
});
}
Loading

0 comments on commit 0f5fb16

Please sign in to comment.