Skip to content

Commit

Permalink
chore: temp
Browse files Browse the repository at this point in the history
  • Loading branch information
howydev committed Dec 19, 2024
1 parent 2333fb0 commit 0c590bb
Show file tree
Hide file tree
Showing 5 changed files with 414 additions and 173 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ import {
} from "viem";
import { accountFactoryAbi } from "../abis/accountFactoryAbi.js";
import { getDefaultMAV2FactoryAddress } from "../utils.js";
import { standardExecutor } from "../../msca/account/standardExecutor.js";
import { singleSignerMessageSigner } from "../modules/single-signer-validation/signer.js";
import { InvalidEntityIdError, InvalidNonceKeyError } from "@aa-sdk/core";
import { modularAccountAbi } from "../abis/modularAccountAbi.js";
import { serializeModuleEntity } from "../actions/common/utils.js";

Expand Down Expand Up @@ -70,11 +68,11 @@ export async function createSMAV2Account<
TSigner extends SmartAccountSigner = SmartAccountSigner
>(
config: CreateSMAV2AccountParams<TTransport, TSigner>
): Promise<SMAV2Account<TSigner> & CalldataEncoder>;
): Promise<SMAV2Account<TSigner>>;

export async function createSMAV2Account(
config: CreateSMAV2AccountParams
): Promise<SMAV2Account & CalldataEncoder> {
): Promise<SMAV2Account> {
const {
transport,
chain,
Expand Down Expand Up @@ -116,14 +114,48 @@ export async function createSMAV2Account(
]);
};

const encodeExecute: (tx: AccountOp) => Promise<Hex> = async ({
target,
data,
value,
}) => {
let callData = encodeFunctionData({
abi: modularAccountAbi,
functionName: "execute",
args: [target, value ?? 0n, data],
});

callData = (await baseAccount.isAccountDeployed())
? await encodeCallData(callData)
: callData;

return callData;
};

const encodeBatchExecute: (txs: AccountOp[]) => Promise<Hex> = async (txs) =>
await encodeCallData(
encodeFunctionData({
abi: modularAccountAbi,
functionName: "executeBatch",
args: [
txs.map((tx) => ({
target: tx.target,
data: tx.data,
value: tx.value ?? 0n,
})),
],
})
);

const baseAccount = await toSmartContractAccount({
transport,
chain,
entryPoint,
accountAddress,
source: `SMAV2Account`,
encodeExecute,
encodeBatchExecute,
getAccountInitCode,
...standardExecutor,
...singleSignerMessageSigner(signer),
});

Expand Down Expand Up @@ -188,39 +220,6 @@ export async function createSMAV2Account(
return numHooks ? concatHex([executeUserOpSelector, callData]) : callData;
};

const encodeExecute: (tx: AccountOp) => Promise<Hex> = async ({
target,
data,
value,
}) => {
let callData = encodeFunctionData({
abi: modularAccountAbi,
functionName: "execute",
args: [target, value ?? 0n, data],
});

callData = (await baseAccount.isAccountDeployed())
? await encodeCallData(callData)
: callData;

return callData;
};

const encodeBatchExecute: (txs: AccountOp[]) => Promise<Hex> = async (txs) =>
encodeCallData(
encodeFunctionData({
abi: modularAccountAbi,
functionName: "executeBatch",
args: [
txs.map((tx) => ({
target: tx.target,
data: tx.data,
value: tx.value ?? 0n,
})),
],
})
);

return {
...baseAccount,
getAccountNonce,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import {
AccountNotFoundError,
IncompatibleClientError,
isSmartAccountClient,
EntityIdOverrideError,
type GetAccountParameter,
type GetEntryPointFromAccount,
type SendUserOperationResult,
type UserOperationOverridesParameter,
} from "@aa-sdk/core";
import {
encodeFunctionData,
concatHex,
type Address,
type Hex,
type Chain,
type Transport,
} from "viem";
import { semiModularAccountBytecodeAbi } from "../../abis/semiModularAccountBytecodeAbi.js";
import type { HookConfig, ValidationConfig } from "../common/types.js";
import {
serializeValidationConfig,
serializeHookConfig,
serializeModuleEntity,
} from "../common/utils.js";
import type { SMAV2Account } from "../../account/semiModularAccountV2.js";
import type { SMASmartAccountClient } from "../../client/client.js";

export type InstallValidationParams<
TSMAV2Account extends SMAV2Account | undefined = SMAV2Account | undefined
> = {
validationConfig: ValidationConfig;
selectors: Hex[];
installData: Hex;
hooks: {
hookConfig: HookConfig;
initData: Hex;
}[];
} & UserOperationOverridesParameter<GetEntryPointFromAccount<TSMAV2Account>> &
GetAccountParameter<TSMAV2Account>;

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

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

export const installValidationActions: <
TTransport extends Transport = Transport,
TChain extends Chain = Chain,
TSMAV2Account extends SMAV2Account = SMAV2Account
>(
client: SMASmartAccountClient<TTransport, TChain, TSMAV2Account>
) => InstallValidationActions<TSMAV2Account> = (client) => ({
installValidation: async ({
validationConfig,
selectors,
installData,
hooks,
account = client.account,
overrides,
}) => {
if (!account) {
throw new AccountNotFoundError();
}

if (!isSmartAccountClient(client)) {
throw new IncompatibleClientError(
"SmartAccountClient",
"installValidation",
client
);
}

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

const callData = await account.encodeCallData(
encodeFunctionData({
abi: semiModularAccountBytecodeAbi,
functionName: "installValidation",
args: [
serializeValidationConfig(validationConfig),
selectors,
installData,
hooks.map((hook: { hookConfig: HookConfig; initData: Hex }) =>
concatHex([serializeHookConfig(hook.hookConfig), hook.initData])
),
],
})
);

return client.sendUserOperation({
uo: callData,
account,
overrides,
});
},

uninstallValidation: async ({
moduleAddress,
entityId,
uninstallData,
hookUninstallDatas,
account = client.account,
overrides,
}) => {
if (!account) {
throw new AccountNotFoundError();
}

if (!isSmartAccountClient(client)) {
throw new IncompatibleClientError(
"SmartAccountClient",
"uninstallValidation",
client
);
}

const callData = await account.encodeCallData(
encodeFunctionData({
abi: semiModularAccountBytecodeAbi,
functionName: "uninstallValidation",
args: [
serializeModuleEntity({
moduleAddress,
entityId,
}),
uninstallData,
hookUninstallDatas,
],
})
);

return client.sendUserOperation({
uo: callData,
account,
overrides,
});
},
});
22 changes: 10 additions & 12 deletions account-kit/smart-contracts/src/ma-v2/client/client.test.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
import { custom, parseEther, publicActions } from "viem";

import {
LocalAccountSigner,
type SmartAccountSigner,
type SmartAccountClient,
} from "@aa-sdk/core";

import { LocalAccountSigner, type SmartAccountSigner } from "@aa-sdk/core";
import {
createSMAV2AccountClient,
type InstallValidationActions,
type SMASmartAccountClient,
} from "./client.js";

import { local070Instance } from "~test/instances.js";
import { setBalance } from "viem/actions";
import { accounts } from "~test/constants.js";
import { getDefaultSingleSignerValidationModuleAddress } from "../modules/utils.js";
import { SingleSignerValidationModule } from "../modules/single-signer-validation/module.js";
import { installValidationActions } from "../actions/install-validation/installValidation.js";

describe("MA v2 Tests", async () => {
const instance = local070Instance;
Expand Down Expand Up @@ -68,7 +62,9 @@ describe("MA v2 Tests", async () => {
});

it("adds a session key with no permissions", async () => {
let provider = await givenConnectedProvider({ signer });
let provider = (await givenConnectedProvider({ signer })).extend(
installValidationActions
);

await setBalance(client, {
address: provider.getAddress(),
Expand Down Expand Up @@ -124,7 +120,9 @@ describe("MA v2 Tests", async () => {
});

it("uninstalls a session key", async () => {
let provider = await givenConnectedProvider({ signer });
let provider = (await givenConnectedProvider({ signer })).extend(
installValidationActions
);

await setBalance(client, {
address: provider.getAddress(),
Expand Down Expand Up @@ -193,7 +191,7 @@ describe("MA v2 Tests", async () => {
}: {
signer: SmartAccountSigner;
accountAddress?: `0x${string}`;
}): Promise<SmartAccountClient & InstallValidationActions> =>
}): Promise<SMASmartAccountClient> =>
createSMAV2AccountClient({
chain: instance.chain,
signer,
Expand Down
Loading

0 comments on commit 0c590bb

Please sign in to comment.