Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add signTypedData to providers #66

Merged
merged 2 commits into from
Aug 5, 2023
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
9 changes: 5 additions & 4 deletions packages/accounts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,10 @@
"@alchemy/aa-core": "^0.1.0-alpha.19",
"typescript": "^5.0.4",
"typescript-template": "*",
"viem": "^1.1.7",
"vitest": "^0.31.0"
},
"peerDependencies": {
"@alchemy/aa-core": "^0.1.0-alpha.1",
"viem": "^1.1.7"
"@alchemy/aa-core": "^0.1.0-alpha.1"
},
"publishConfig": {
"access": "public",
Expand All @@ -61,5 +59,8 @@
"url": "https://github.com/alchemyplatform/aa-sdk/issues"
},
"homepage": "https://github.com/alchemyplatform/aa-sdk#readme",
"gitHead": "ee46e8bb857de3b631044fa70714ea706d9e317d"
"gitHead": "ee46e8bb857de3b631044fa70714ea706d9e317d",
"dependencies": {
"viem": "^1.5.3"
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import type { Address, Hex, SmartAccountSigner } from "@alchemy/aa-core";
import type {
Address,
Hex,
SignTypedDataParams,
SmartAccountSigner,
} from "@alchemy/aa-core";

export class MockSigner implements SmartAccountSigner {
getAddress(): Promise<Address> {
Expand All @@ -10,4 +15,10 @@ export class MockSigner implements SmartAccountSigner {
"0x4d61c5c27fb64b207cbf3bcf60d78e725659cff5f93db9a1316162117dff72aa631761619d93d4d97dfb761ba00b61f9274c6a4a76e494df644d968dd84ddcdb1c"
);
}

signTypedData(_params: SignTypedDataParams): Promise<`0x${string}`> {
return Promise.resolve(
"0x4d61c5c27fb64b207cbf3bcf60d78e725659cff5f93db9a1316162117dff72aa631761619d93d4d97dfb761ba00b61f9274c6a4a76e494df644d968dd84ddcdb1c"
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import {
parseAbiParameters,
toHex,
type Address,
type Hex,
type Hash,
type Hex,
} from "viem";
import { mnemonicToAccount } from "viem/accounts";
import { polygonMumbai } from "viem/chains";
Expand Down Expand Up @@ -40,6 +40,9 @@ describe("Kernel Account Tests", () => {
message: { raw: toHex(msg) },
}),
getAddress: async () => ownerAccount.address,
signTypedData: async (params) => {
return ownerAccount.signTypedData(params);
},
};
const mockOwner = new MockSigner();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import type { Address, Hex, SmartAccountSigner } from "@alchemy/aa-core";
import type {
Address,
Hex,
SignTypedDataParams,
SmartAccountSigner,
} from "@alchemy/aa-core";

export class MockSigner implements SmartAccountSigner {
getAddress(): Promise<Address> {
Expand All @@ -10,4 +15,10 @@ export class MockSigner implements SmartAccountSigner {
"0x4d61c5c27fb64b207cbf3bcf60d78e725659cff5f93db9a1316162117dff72aa631761619d93d4d97dfb761ba00b61f9274c6a4a76e494df644d968dd84ddcdb1c"
);
}

signTypedData(_params: SignTypedDataParams): Promise<`0x${string}`> {
return Promise.resolve(
"0x4d61c5c27fb64b207cbf3bcf60d78e725659cff5f93db9a1316162117dff72aa631761619d93d4d97dfb761ba00b61f9274c6a4a76e494df644d968dd84ddcdb1c"
);
}
}
6 changes: 4 additions & 2 deletions packages/alchemy/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,11 @@
"viem": "^1.1.7",
"vitest": "^0.31.0"
},
"dependencies": {
"viem": "^1.5.3"
},
"peerDependencies": {
"@alchemy/aa-core": "^0.1.0-alpha.1",
"viem": "^1.1.7"
"@alchemy/aa-core": "^0.1.0-alpha.1"
},
"publishConfig": {
"access": "public",
Expand Down
8 changes: 3 additions & 5 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,14 @@
"ts-node": "^10.9.1",
"typescript": "^5.0.4",
"typescript-template": "*",
"viem": "^1.1.7",
"vitest": "^0.31.0"
},
"dependencies": {
"abitype": "^0.8.3",
"eventemitter3": "^5.0.1"
},
"peerDependencies": {
"viem": "^1.1.7"
"eventemitter3": "^5.0.1",
"viem": "^1.5.3"
},
"peerDependencies": {},
"repository": {
"type": "git",
"url": "git+https://github.com/alchemyplatform/aa-sdk.git"
Expand Down
5 changes: 2 additions & 3 deletions packages/core/src/account/__tests__/simple.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ describe("Account Simple Tests", () => {
entryPointAddress: "0xENTRYPOINT_ADDRESS",
chain,
owner,
factoryAddress: "0xSIMPLE_ACCOUNT_FACTORY_ADDRESS",
factoryAddress: "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef",
rpcClient: provider,
});

Expand All @@ -36,8 +36,7 @@ describe("Account Simple Tests", () => {

it("should correctly sign the message", async () => {
expect(
// TODO: expose sign message on the provider too
await signer.account.signMessage(
await signer.signMessage(
"0xa70d0af2ebb03a44dcd0714a8724f622e3ab876d0aa312f0ee04823285d6fb1b"
)
).toBe(
Expand Down
17 changes: 16 additions & 1 deletion packages/core/src/account/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import type {
} from "../client/types.js";
import { Logger } from "../logger.js";
import type { BatchUserOperationCallData } from "../types.js";
import type { ISmartContractAccount } from "./types.js";
import type { ISmartContractAccount, SignTypedDataParams } from "./types.js";

export enum DeploymentState {
UNDEFINED = "0x0",
Expand Down Expand Up @@ -75,8 +75,23 @@ export abstract class BaseSmartContractAccount<
data: string
): Promise<`0x${string}`>;
abstract signMessage(msg: string | Uint8Array): Promise<`0x${string}`>;

protected abstract getAccountInitCode(): Promise<`0x${string}`>;

async signMessageWith6492(_msg: string | Uint8Array): Promise<`0x${string}`> {
throw new Error("signMessageWith6492 not supported");
}

async signTypedData(_params: SignTypedDataParams): Promise<`0x${string}`> {
throw new Error("signTypedData not supported");
}

async signTypedDataWith6492(
_params: SignTypedDataParams
): Promise<`0x${string}`> {
throw new Error("signTypedDataWith6492 not supported");
}

async encodeBatchExecute(
_txs: BatchUserOperationCallData
): Promise<`0x${string}`> {
Expand Down
11 changes: 7 additions & 4 deletions packages/core/src/account/simple.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
encodeFunctionData,
hexToBytes,
type FallbackTransport,
type Hash,
type Hex,
type Transport,
} from "viem";
Expand All @@ -14,10 +15,12 @@ import {
BaseSmartContractAccount,
type BaseSmartAccountParams,
} from "./base.js";
import type { SignTypedDataParams } from "./types.js";

export interface SimpleSmartAccountOwner {
signMessage: (msg: Uint8Array) => Promise<Address>;
signMessage: (msg: Uint8Array) => Promise<Hash>;
getAddress: () => Promise<Address>;
signTypedData: (params: SignTypedDataParams) => Promise<Hash>;
}

export interface SimpleSmartAccountParams<
Expand All @@ -31,9 +34,9 @@ export interface SimpleSmartAccountParams<
export class SimpleSmartContractAccount<
TTransport extends Transport | FallbackTransport = Transport
> extends BaseSmartContractAccount<TTransport> {
private owner: SimpleSmartAccountOwner;
private factoryAddress: Address;
private index: bigint;
protected owner: SimpleSmartAccountOwner;
protected factoryAddress: Address;
protected index: bigint;

constructor(params: SimpleSmartAccountParams) {
super(params);
Expand Down
29 changes: 28 additions & 1 deletion packages/core/src/account/types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import type { Address } from "abitype";
import type { Hex } from "viem";
import type { Hash, Hex } from "viem";
import type { SignTypedDataParameters } from "viem/accounts";
import type { BatchUserOperationCallData } from "../types";

export type SignTypedDataParams = Omit<SignTypedDataParameters, "privateKey">;

export interface ISmartContractAccount {
/**
* @returns the init code for the account
Expand Down Expand Up @@ -46,6 +49,30 @@ export interface ISmartContractAccount {
*/
signMessage(msg: string | Uint8Array | Hex): Promise<Hex>;

/**
* Signs a typed data object as per ERC-712
*
* @param params - {@link SignTypedDataParams}
* @returns the signed hash for the message passed
*/
signTypedData(params: SignTypedDataParams): Promise<Hash>;

/**
* If the account is not deployed, it will sign the message and then wrap it in 6492 format
*
* @param msg - the message to sign
* @returns ths signature wrapped in 6492 format
*/
signMessageWith6492(msg: string | Uint8Array | Hex): Promise<Hex>;

/**
* If the account is not deployed, it will sign the typed data blob and then wrap it in 6492 format
*
* @param params - {@link SignTypedDataParams}
* @returns the signed hash for the params passed in wrapped in 6492 format
*/
signTypedDataWith6492(params: SignTypedDataParams): Promise<Hash>;

/**
* @returns the address of the account
*/
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export { HdAccountSigner } from "./signer/hd-account.js";
export { LocalAccountSigner } from "./signer/local-account.js";
export { PrivateKeySigner } from "./signer/private-key.js";
export type { SmartAccountSigner } from "./signer/types.js";
export { wrapWith6492 } from "./signer/utils.js";

export {
createPublicErc4337Client,
Expand Down
25 changes: 25 additions & 0 deletions packages/core/src/provider/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
} from "viem";
import { arbitrum, arbitrumGoerli } from "viem/chains";
import { BaseSmartContractAccount } from "../account/base.js";
import type { SignTypedDataParams } from "../account/types.js";
import { createPublicErc4337Client } from "../client/create-client.js";
import type {
PublicErc4337Client,
Expand Down Expand Up @@ -180,6 +181,30 @@ export class SmartAccountProvider<
return this.account.signMessage(msg);
};

signTypedData = async (params: SignTypedDataParams): Promise<Hash> => {
if (!this.account) {
throw new Error("account not connected!");
}

return this.account.signTypedData(params);
};

signMessageWith6492(msg: string | Uint8Array): Promise<`0x${string}`> {
if (!this.account) {
throw new Error("account not connected!");
}

return this.account.signMessageWith6492(msg);
}

signTypedDataWith6492(params: SignTypedDataParams): Promise<`0x${string}`> {
if (!this.account) {
throw new Error("account not connected!");
}

return this.account.signTypedDataWith6492(params);
}

sendTransactions = async (requests: RpcTransactionRequest[]) => {
const batch = requests.map((request) => {
if (!request.to) {
Expand Down
26 changes: 26 additions & 0 deletions packages/core/src/provider/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import type { Address } from "abitype";
import type { Hash, Hex, RpcTransactionRequest, Transport } from "viem";
import type { SignTypedDataParameters } from "viem/accounts";
import type { BaseSmartContractAccount } from "../account/base.js";
import type { SignTypedDataParams } from "../account/types.js";
import type {
PublicErc4337Client,
SupportedTransports,
Expand Down Expand Up @@ -157,6 +159,30 @@ export interface ISmartAccountProvider<
*/
signMessage: (msg: string | Uint8Array) => Promise<Hash>;

/**
* This method is used to sign typed data as per ERC-712
*
* @param params - {@link SignTypedDataParameters}
* @returns the signed hash for the message passed
*/
signTypedData: (params: SignTypedDataParameters) => Promise<Hash>;

/**
* If the account is not deployed, it will sign the message and then wrap it in 6492 format
*
* @param msg - the message to sign
* @returns ths signature wrapped in 6492 format
*/
signMessageWith6492(msg: string | Uint8Array | Hex): Promise<Hex>;

/**
* If the account is not deployed, it will sign the typed data blob and then wrap it in 6492 format
*
* @param params - {@link SignTypedDataParameters}
* @returns the signed hash for the params passed in wrapped in 6492 format
*/
signTypedDataWith6492(params: SignTypedDataParams): Promise<Hash>;

// TODO: potentially add methods here for something like viem's walletActions?
/**
* @returns the address of the connected account
Expand Down
5 changes: 5 additions & 0 deletions packages/core/src/signer/local-account.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { isHex, type HDAccount, type Hex, type PrivateKeyAccount } from "viem";
import { mnemonicToAccount, privateKeyToAccount } from "viem/accounts";
import type { SignTypedDataParams } from "../account/types.js";
import type { SmartAccountSigner } from "./types.js";

export class LocalAccountSigner<T extends HDAccount | PrivateKeyAccount>
Expand All @@ -26,6 +27,10 @@ export class LocalAccountSigner<T extends HDAccount | PrivateKeyAccount>
}
};

readonly signTypedData = (params: SignTypedDataParams) => {
return this.owner.signTypedData(params);
};

readonly getAddress: () => Promise<`0x${string}`> = async () => {
return this.owner.address;
};
Expand Down
6 changes: 4 additions & 2 deletions packages/core/src/signer/types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import type { Address } from "abitype";
import type { Hex } from "viem";
import type { Hash, Hex } from "viem";
import type { SignTypedDataParams } from "../account/types.js";

export interface SmartAccountSigner {
signMessage: (msg: Uint8Array | Hex | string) => Promise<Hex>;
signMessage: (msg: Uint8Array | Hex | string) => Promise<Hash>;
signTypedData: (params: SignTypedDataParams) => Promise<Hash>;
getAddress: () => Promise<Address>;
}
29 changes: 29 additions & 0 deletions packages/core/src/signer/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import {
concat,
encodeAbiParameters,
parseAbiParameters,
type Address,
type Hash,
type Hex,
} from "viem";

type SignWith6492Params = {
factoryAddress: Address;
initCode: Hex;
signature: Hash;
};

export const wrapWith6492 = ({
factoryAddress,
initCode,
signature,
}: SignWith6492Params): Hash => {
return concat([
encodeAbiParameters(parseAbiParameters("address, bytes, bytes"), [
factoryAddress,
initCode,
signature,
]),
"0x6492649264926492649264926492649264926492649264926492649264926492",
]);
};
Loading