Skip to content

Commit

Permalink
feat: add low level support for 7702
Browse files Browse the repository at this point in the history
  • Loading branch information
moldy530 committed Dec 6, 2024
1 parent bf687af commit 1c41bf5
Show file tree
Hide file tree
Showing 13 changed files with 119 additions and 10 deletions.
7 changes: 6 additions & 1 deletion aa-sdk/core/src/account/smartContractAccount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
type TypedDataDefinition,
} from "viem";
import { toAccount } from "viem/accounts";
import type { Authorization } from "viem/experimental";
import { createBundlerClient } from "../client/bundlerClient.js";
import type {
EntryPointDef,
Expand Down Expand Up @@ -125,6 +126,7 @@ export type SmartContractAccount<
getFactoryData: () => Promise<Hex>;
getEntryPoint: () => EntryPointDef<TEntryPointVersion>;
getImplementationAddress: () => Promise<NullAddress | Address>;
signAuthorization?: () => Promise<Authorization<number, true>>;
};
// [!endregion SmartContractAccount]

Expand Down Expand Up @@ -155,7 +157,10 @@ export type ToSmartContractAccountParams<
// if not provided, will default to just using signMessage over the Hex
signUserOperationHash?: (uoHash: Hex) => Promise<Hex>;
encodeUpgradeToAndCall?: (params: UpgradeToAndCallParams) => Promise<Hex>;
} & Omit<CustomSource, "signTransaction" | "address">;
} & Omit<
CustomSource,
"signTransaction" | "address" | "experimental_signAuthorization"
>;
// [!endregion ToSmartContractAccountParams]

/**
Expand Down
10 changes: 10 additions & 0 deletions aa-sdk/core/src/actions/smartAccount/internal/sendUserOperation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,16 @@ export async function _sendUserOperation<
overrides,
});

if (
request.signature.startsWith(
// TODO: put this in a constant
"0x00000000000000000000000000000000000000000000000001ff00"
) &&
account.signAuthorization
) {
request.authorizationTuple = await account.signAuthorization();
}

return {
hash: await client.sendRawUserOperation(request, entryPoint.address),
request,
Expand Down
2 changes: 1 addition & 1 deletion aa-sdk/core/src/entrypoint/0.7.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ const packUserOperation = (request: UserOperationRequest<"0.7.0">): Hex => {
{ type: "bytes32" },
],
[
request.sender as Address,
request.sender,
hexToBigInt(request.nonce),
keccak256(initCode),
keccak256(request.callData),
Expand Down
1 change: 1 addition & 0 deletions aa-sdk/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ export {
} from "./errors/useroperation.js";
export { LogLevel, Logger } from "./logger.js";
export { middlewareActions } from "./middleware/actions.js";
export { default7702UserOpSigner } from "./middleware/defaults/7702signer.js";
export { defaultFeeEstimator } from "./middleware/defaults/feeEstimator.js";
export { defaultGasEstimator } from "./middleware/defaults/gasEstimator.js";
export { defaultPaymasterAndData } from "./middleware/defaults/paymasterAndData.js";
Expand Down
49 changes: 49 additions & 0 deletions aa-sdk/core/src/middleware/defaults/7702signer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { AccountNotFoundError } from "../../errors/account.js";
import type { ClientMiddlewareFn } from "../types";
import { defaultUserOpSigner } from "./userOpSigner.js";

/**
* Provides a default middleware function for signing user operations with a client account when using ERC-7702 to upgrade local accounts to smart accounts.
* If the SmartAccount doesn't support `signAuthorization`, then this just runs the default UserOpSigner middleware
*
* @param {UserOperationStruct} struct The user operation structure to be signed
* @param {*} params The middleware context containing the client and account information
* @param {Client} params.client The client object, which should include account and chain information
* @param {Account} [params.account] Optional, the account used for signing, defaults to the client's account if not provided
* @returns {Promise<UserOperationStruct>} A promise that resolves to the signed user operation structure
*/
export const default7702UserOpSigner: ClientMiddlewareFn = async (
struct,
params
) => {
const uo = await defaultUserOpSigner(struct, params);
const account = params.account ?? params.client.account;
if (!account) {
throw new AccountNotFoundError();
}

if (!account.signAuthorization) {
return uo;
}

const code =
(await params.client.getCode({ address: account.address })) ?? "0x";
// TODO: this isn't the cleanest because now the account implementation HAS to know that it needs to return an impl address
// even if the account is not deployed
const implAddress = await account.getImplementationAddress();
if (
code ===
"0x00000000000000000000000000000000000000000000000001ff00" +
implAddress.slice(2)
) {
return uo;
}

return {
...uo,
// TODO: put this in a constant
signature:
"0x00000000000000000000000000000000000000000000000001ff00" +
(await uo.signature).slice(2),
};
};
5 changes: 3 additions & 2 deletions aa-sdk/core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
type StateOverride,
type TransactionReceipt,
} from "viem";
import type { Authorization } from "viem/experimental";
import type { z } from "zod";
import type {
UserOperationFeeOptionsFieldSchema,
Expand Down Expand Up @@ -205,11 +206,11 @@ export interface UserOperationRequest_v7 {
// Reference: https://eips.ethereum.org/EIPS/eip-4337#definitions
export type UserOperationRequest<
TEntryPointVersion extends EntryPointVersion = EntryPointVersion
> = TEntryPointVersion extends "0.6.0"
> = (TEntryPointVersion extends "0.6.0"
? UserOperationRequest_v6
: TEntryPointVersion extends "0.7.0"
? UserOperationRequest_v7
: never;
: never) & { authorizationTuple?: Authorization };

// [!endregion UserOperationRequest]

Expand Down
2 changes: 1 addition & 1 deletion aa-sdk/core/src/version.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// This file is autogenerated by inject-version.ts. Any changes will be
// overwritten on commit!
export const VERSION = "4.5.1";
export const VERSION = "4.6.0";
2 changes: 1 addition & 1 deletion account-kit/core/src/version.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// This file is autogenerated by inject-version.ts. Any changes will be
// overwritten on commit!
export const VERSION = "4.5.1";
export const VERSION = "4.6.0";
2 changes: 1 addition & 1 deletion account-kit/infra/src/version.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// This file is autogenerated by inject-version.ts. Any changes will be
// overwritten on commit!
export const VERSION = "4.5.1";
export const VERSION = "4.6.0";
2 changes: 1 addition & 1 deletion account-kit/plugingen/src/version.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// This file is autogenerated by inject-version.ts. Any changes will be
// overwritten on commit!
export const VERSION = "4.5.1";
export const VERSION = "4.6.0";
2 changes: 1 addition & 1 deletion account-kit/react/src/version.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// This file is autogenerated by inject-version.ts. Any changes will be
// overwritten on commit!
export const VERSION = "4.5.1";
export const VERSION = "4.6.0";
2 changes: 1 addition & 1 deletion account-kit/signer/src/version.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// This file is autogenerated by inject-version.ts. Any changes will be
// overwritten on commit!
export const VERSION = "4.5.1";
export const VERSION = "4.6.0";

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 1c41bf5

Please sign in to comment.