From cd9053ba1b4282eaf315f23065f4b1e877c70555 Mon Sep 17 00:00:00 2001 From: Blu-J <2364004+Blu-J@users.noreply.github.com> Date: Fri, 10 Jan 2025 17:19:16 +0000 Subject: [PATCH 1/4] feat(aa-sdk): sdk light client can call the alchemy client (#1236) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Pull Request Checklist - [x] Did you add new tests and confirm existing tests pass? (`yarn test`) - [x] Did you update relevant docs? (docs are found in the `site` folder, and guidelines for updating/adding docs can be found in the [contribution guide](https://github.com/alchemyplatform/aa-sdk/blob/main/CONTRIBUTING.md)) - [x] Do your commits follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) standard? - [x] Does your PR title also follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) standard? - [x] If you have a breaking change, is it [correctly reflected in your commit message](https://www.conventionalcommits.org/en/v1.0.0/#examples)? (e.g. `feat!: breaking change`) - [x] Did you run lint (`yarn lint:check`) and fix any issues? (`yarn lint:write`) - [x] Did you follow the [contribution guidelines](https://github.com/alchemyplatform/aa-sdk/blob/main/CONTRIBUTING.md)? --- ## PR-Codex overview This PR focuses on enhancing the `createLightAccountClient` function to support an `AlchemyTransport`, modifying its return type accordingly. Additionally, it introduces the `isAlchemyTransport` utility to check the transport type. ### Detailed summary - Modified `createLightAccountClient` to return `AlchemySmartAccountClient` when using `AlchemyTransport`. - Added `isAlchemyTransport` function to verify if the transport is an `AlchemyTransport`. - Updated type parameters in `CreateLightAccountClientParams` to include `AlchemyTransport`. - Enhanced documentation for the `createLightAccountClient` function. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` --- .../src/light-account/clients/client.test.ts | 92 ++++++++++++++++++- .../src/light-account/clients/client.ts | 48 +++++++++- .../infra/functions/isAlchemyTransport.mdx | 36 ++++++++ .../functions/createLightAccountClient.mdx | 2 + 4 files changed, 172 insertions(+), 6 deletions(-) create mode 100644 site/pages/reference/account-kit/infra/functions/isAlchemyTransport.mdx diff --git a/account-kit/smart-contracts/src/light-account/clients/client.test.ts b/account-kit/smart-contracts/src/light-account/clients/client.test.ts index 0c58a7c142..25442a97da 100644 --- a/account-kit/smart-contracts/src/light-account/clients/client.test.ts +++ b/account-kit/smart-contracts/src/light-account/clients/client.test.ts @@ -4,12 +4,21 @@ import { erc7677Middleware, LocalAccountSigner, type BatchUserOperationCallData, + type SmartAccountClient, type SmartAccountSigner, type UserOperationCallData, type UserOperationOverrides, type UserOperationStruct, } from "@aa-sdk/core"; -import { custom, parseEther, type Address, publicActions } from "viem"; +import { + custom, + parseEther, + type Address, + publicActions, + type Chain, + type Client, + type CustomTransport, +} from "viem"; import { setBalance } from "viem/actions"; import { resetBalance } from "~test/accounts.js"; import { accounts } from "~test/constants.js"; @@ -21,6 +30,15 @@ import { getMSCAUpgradeToData } from "../../msca/utils.js"; import type { LightAccountVersion } from "../types.js"; import { AccountVersionRegistry } from "../utils.js"; import { createLightAccountClient } from "./client.js"; +import { + alchemy, + polygonMumbai, + alchemyEnhancedApiActions, + type AlchemyTransport, + type AlchemySmartAccountClient, + type AlchemyEnhancedApis, +} from "@account-kit/infra"; +import { Alchemy, Network } from "alchemy-sdk"; const versions = Object.keys( AccountVersionRegistry.LightAccount @@ -387,4 +405,76 @@ describe("Light Account Tests", () => { chain: instance.chain, ...(usePaymaster ? erc7677Middleware() : {}), }); + + const givenAlchemyConnectedProvider = async ({ + signer, + chain, + }: { + signer: SmartAccountSigner; + chain: Chain; + }) => + createLightAccountClient({ + transport: alchemy({ + jwt: "test", + }), + chain, + signer, + accountAddress: "0x86f3B0211764971Ad0Fc8C8898d31f5d792faD84", + }); + it("Should have some alchemy specific types", async () => { + const alchemy = new Alchemy({ + network: Network.MATIC_MUMBAI, + apiKey: "test", + }); + const chain = polygonMumbai; + + const provider = ( + await givenAlchemyConnectedProvider({ signer, chain }) + ).extend(alchemyEnhancedApiActions(alchemy)); + + assertType>(provider); + assertType(provider); + assertType(provider); + assertType(provider); + assertType( + // @ts-expect-error + await givenAlchemyConnectedProvider({ signer, chain }) + ); + // @ts-expect-error + assertType>(provider); + }); + it("Should have some non-alchemy specific types", async () => { + const chain = polygonMumbai; + + const signer: SmartAccountSigner = new LocalAccountSigner( + accounts.fundedAccountOwner + ); + const provider = await givenConnectedProvider({ + signer, + version: "v1.0.1", + }); + + assertType(provider); + assertType>(provider); + assertType( + // @ts-expect-error + await givenAlchemyConnectedProvider({ signer, chain }) + ); + // @ts-expect-error + assertType>(provider); + // @ts-expect-error + assertType(provider); + // @ts-expect-error + assertType(provider); + + expect(() => { + const alchemy = new Alchemy({ + network: Network.MATIC_MUMBAI, + apiKey: "test", + }); + + // @ts-expect-error + provider.extend(alchemyEnhancedApiActions(alchemy)); + }).not.toBeFalsy(); + }); }); diff --git a/account-kit/smart-contracts/src/light-account/clients/client.ts b/account-kit/smart-contracts/src/light-account/clients/client.ts index ee1bab0ff8..b700030efc 100644 --- a/account-kit/smart-contracts/src/light-account/clients/client.ts +++ b/account-kit/smart-contracts/src/light-account/clients/client.ts @@ -16,9 +16,17 @@ import { lightAccountClientActions, type LightAccountClientActions, } from "../decorators/lightAccount.js"; +import { + type AlchemySmartAccountClient, + type AlchemyTransport, +} from "@account-kit/infra"; +import { + createLightAccountAlchemyClient, + type AlchemyLightAccountClientConfig, +} from "./alchemyClient.js"; export type CreateLightAccountClientParams< - TTransport extends Transport = Transport, + TTransport extends Transport | AlchemyTransport = Transport, TChain extends Chain | undefined = Chain | undefined, TSigner extends SmartAccountSigner = SmartAccountSigner > = { @@ -31,14 +39,28 @@ export type CreateLightAccountClientParams< >; export function createLightAccountClient< - TChain extends Chain | undefined = Chain | undefined, TSigner extends SmartAccountSigner = SmartAccountSigner >( - args: CreateLightAccountClientParams + params: AlchemyLightAccountClientConfig & { + transport: AlchemyTransport; + } +): Promise< + AlchemySmartAccountClient< + Chain | undefined, + LightAccount, + LightAccountClientActions + > +>; +export function createLightAccountClient< + TChain extends Chain | undefined = Chain | undefined, + TSigner extends SmartAccountSigner = SmartAccountSigner, + TTransport extends Transport = Transport +>( + args: CreateLightAccountClientParams ): Promise< SmartAccountClient< CustomTransport, - Chain, + TChain, LightAccount, SmartAccountClientActions & LightAccountClientActions> @@ -48,6 +70,8 @@ export function createLightAccountClient< /** * Creates a light account client using the provided parameters, including account information, transport mechanism, blockchain chain, and additional client configurations. This function first creates a light account and then uses it to create a smart account client, extending it with light account client actions. * + * Also, we modified the return type to be the light account alchemy client if the transport is alchemy. + * * @example * ```ts * import { createLightAccountClient } from "@account-kit/smart-contracts"; @@ -67,9 +91,16 @@ export function createLightAccountClient< */ export async function createLightAccountClient( params: CreateLightAccountClientParams -): Promise { +): Promise { const { transport, chain } = params; + if (isAlchemyTransport(transport, chain)) { + return await createLightAccountAlchemyClient({ + ...params, + transport, + }); + } + const lightAccount = await createLightAccount({ ...params, transport, @@ -83,3 +114,10 @@ export async function createLightAccountClient( account: lightAccount, }).extend(lightAccountClientActions); } + +function isAlchemyTransport( + transport: Transport, + chain: Chain +): transport is AlchemyTransport { + return transport({ chain }).config.type === "alchemy"; +} diff --git a/site/pages/reference/account-kit/infra/functions/isAlchemyTransport.mdx b/site/pages/reference/account-kit/infra/functions/isAlchemyTransport.mdx new file mode 100644 index 0000000000..8e3c9944c1 --- /dev/null +++ b/site/pages/reference/account-kit/infra/functions/isAlchemyTransport.mdx @@ -0,0 +1,36 @@ +--- +# This file is autogenerated +title: isAlchemyTransport +description: Overview of the isAlchemyTransport method +--- + +# isAlchemyTransport + +Checks whether the given transport is an AlchemyTransport. + +## Import + +```ts +import { isAlchemyTransport } from "@account-kit/infra"; +``` + +## Usage + +```ts +import { isAlchemyTransport } from "@account-kit/infra"; +if (isAlchemyTransport(transport)) { + // do things here that are only when transport is an AlchemyTransport +} +``` + +## Parameters + +### x + +`Transport | AlchemyTransport` +The transport to check. + +## Returns + +`boolean` +True if the transport is of type AlchemyTransport, otherwise false. diff --git a/site/pages/reference/account-kit/smart-contracts/functions/createLightAccountClient.mdx b/site/pages/reference/account-kit/smart-contracts/functions/createLightAccountClient.mdx index a412ec27a4..568b40462c 100644 --- a/site/pages/reference/account-kit/smart-contracts/functions/createLightAccountClient.mdx +++ b/site/pages/reference/account-kit/smart-contracts/functions/createLightAccountClient.mdx @@ -9,6 +9,8 @@ description: Overview of the createLightAccountClient method Creates a light account client using the provided parameters, including account information, transport mechanism, blockchain chain, and additional client configurations. This function first creates a light account and then uses it to create a smart account client, extending it with light account client actions. +Also, we modified the return type to be the light account alchemy client if the transport is alchemy. + ## Import ```ts From 21acc9f37b8e45f99d8a7fcba0429858bb849d5f Mon Sep 17 00:00:00 2001 From: Blu-J <2364004+Blu-J@users.noreply.github.com> Date: Fri, 10 Jan 2025 17:19:16 +0000 Subject: [PATCH 2/4] test(test-d): add test-d files for vitest typechecking: (#1248) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Pull Request Checklist - [x] Did you add new tests and confirm existing tests pass? (`yarn test`) - [x] Did you update relevant docs? (docs are found in the `site` folder, and guidelines for updating/adding docs can be found in the [contribution guide](https://github.com/alchemyplatform/aa-sdk/blob/main/CONTRIBUTING.md)) - [x] Do your commits follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) standard? - [x] Does your PR title also follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) standard? - [x] If you have a breaking change, is it [correctly reflected in your commit message](https://www.conventionalcommits.org/en/v1.0.0/#examples)? (e.g. `feat!: breaking change`) - [x] Did you run lint (`yarn lint:check`) and fix any issues? (`yarn lint:write`) - [x] Did you follow the [contribution guidelines](https://github.com/alchemyplatform/aa-sdk/blob/main/CONTRIBUTING.md)? --- ## PR-Codex overview This PR focuses on enhancing type checking and testing for the `account-kit` packages, particularly by adding `test-d.ts` files and updating test commands. It also removes unused code related to Alchemy transport. ### Detailed summary - Added `test-d.ts` files for type definitions in multiple packages. - Updated `.github/workflows/on-pull-request.yml` to include type checking in tests. - Modified `package.json` to add a new `test:typecheck` script. - Updated `CONTRIBUTING.md` to reflect changes in testing commands. - Removed Alchemy-related code from `client.test.ts`. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` --- .github/workflows/on-pull-request.yml | 4 + .vitest/vitest.shared.ts | 3 + CONTRIBUTING.md | 4 +- aa-sdk/core/package.json | 1 + aa-sdk/core/tsconfig.build.json | 1 + aa-sdk/ethers/package.json | 1 + aa-sdk/ethers/tsconfig.build.json | 1 + account-kit/core/package.json | 1 + account-kit/core/tsconfig.build.json | 1 + account-kit/infra/package.json | 1 + account-kit/infra/tsconfig.build.json | 1 + account-kit/logging/package.json | 1 + account-kit/logging/tsconfig.build.json | 1 + account-kit/plugingen/package.json | 1 + account-kit/plugingen/tsconfig.build.json | 1 + account-kit/react/package.json | 1 + account-kit/react/tsconfig.build.json | 1 + account-kit/react/tsconfig.storybook.json | 1 + account-kit/signer/package.json | 1 + account-kit/signer/tsconfig.build.json | 1 + account-kit/smart-contracts/package.json | 1 + .../light-account/clients/client.test-d.ts | 125 ++++++++++++++++++ .../src/light-account/clients/client.test.ts | 92 +------------ .../smart-contracts/tsconfig.build.json | 1 + doc-gen/package.json | 1 + doc-gen/tsconfig.build.json | 1 + package.json | 1 + .../infra/functions/isAlchemyTransport.mdx | 36 ----- 28 files changed, 157 insertions(+), 129 deletions(-) create mode 100644 account-kit/smart-contracts/src/light-account/clients/client.test-d.ts delete mode 100644 site/pages/reference/account-kit/infra/functions/isAlchemyTransport.mdx diff --git a/.github/workflows/on-pull-request.yml b/.github/workflows/on-pull-request.yml index d8e8c49db6..deeb9f23d7 100644 --- a/.github/workflows/on-pull-request.yml +++ b/.github/workflows/on-pull-request.yml @@ -101,6 +101,9 @@ jobs: - name: Unit Test run: yarn test:ci + + - name: Typecheck Test + run: yarn test:typecheck build_ios: name: Build iOS @@ -131,3 +134,4 @@ jobs: - name: Build example for iOS run: | yarn turbo run build:ios + diff --git a/.vitest/vitest.shared.ts b/.vitest/vitest.shared.ts index c085cdec58..50c85b8d64 100644 --- a/.vitest/vitest.shared.ts +++ b/.vitest/vitest.shared.ts @@ -3,6 +3,9 @@ import { configDefaults, defineConfig } from "vitest/config"; export const sharedConfig = defineConfig({ test: { + typecheck: { + ignoreSourceErrors: true, + }, alias: { "~test": join(__dirname, "./src"), }, diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9c1a8dba3d..1378393894 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,11 +12,11 @@ We are excited to have you contribute to the `aa-sdk`. Here's a step-by-step gui - Use the Node version specified in `package.json` (currently 18.16.0). Run `node -v` to check your version. - Build the project with `yarn build`. - - Run existing tests using `yarn test` to ensure everything is working correctly. + - Run existing tests using `yarn test` & `yarn test:typecheck` to ensure everything is working correctly. 4. **Make Changes**: Now, you can start making changes to the packages or docs. When updating or adding new functionality, update or add a new doc in `site/packages/*` corresponding to the package you have worked on to document the changes. -5. **Re-verify Tests**: After making your changes, re-run `yarn test` to ensure all tests still pass. +5. **Re-verify Tests**: After making your changes, re-run `yarn test` & `yarn test:typecheck` to ensure all tests still pass. 6. **Code Formatting**: diff --git a/aa-sdk/core/package.json b/aa-sdk/core/package.json index f2e45bcf4d..04b2ba2975 100644 --- a/aa-sdk/core/package.json +++ b/aa-sdk/core/package.json @@ -17,6 +17,7 @@ "!vitest.config.ts", "!.env", "!src/**/*.test.ts", + "!src/**/*.test-d.ts", "!src/__tests__/**/*" ], "exports": { diff --git a/aa-sdk/core/tsconfig.build.json b/aa-sdk/core/tsconfig.build.json index 7bae05bd62..5de5b77262 100644 --- a/aa-sdk/core/tsconfig.build.json +++ b/aa-sdk/core/tsconfig.build.json @@ -4,6 +4,7 @@ "node_modules", "**/*/__tests__", "**/*/*.test.ts", + "**/*/*.test-d.ts", "**/*/*.e2e.test.ts", "vitest.config.ts", "vitest.config.e2e.ts" diff --git a/aa-sdk/ethers/package.json b/aa-sdk/ethers/package.json index 8f85340d36..e433314c05 100644 --- a/aa-sdk/ethers/package.json +++ b/aa-sdk/ethers/package.json @@ -17,6 +17,7 @@ "!.env", "!dist/**/*.tsbuildinfo", "!src/**/*.test.ts", + "!src/**/*.test-d.ts", "!src/__tests__/**/*" ], "exports": { diff --git a/aa-sdk/ethers/tsconfig.build.json b/aa-sdk/ethers/tsconfig.build.json index 8f0730ac86..795defce57 100644 --- a/aa-sdk/ethers/tsconfig.build.json +++ b/aa-sdk/ethers/tsconfig.build.json @@ -5,6 +5,7 @@ "**/*/__tests__", "**/*/*.e2e.test.ts", "**/*/*.test.ts", + "**/*/*.test-d.ts", "vitest.config.ts" ], "include": ["src"], diff --git a/account-kit/core/package.json b/account-kit/core/package.json index 8b8393ded9..21b0783b37 100644 --- a/account-kit/core/package.json +++ b/account-kit/core/package.json @@ -18,6 +18,7 @@ "!vitest.config.ts", "!.env", "!src/**/*.test.ts", + "!src/**/*.test-d.ts", "!src/__tests__/**/*" ], "exports": { diff --git a/account-kit/core/tsconfig.build.json b/account-kit/core/tsconfig.build.json index 605911996a..a9532f066c 100644 --- a/account-kit/core/tsconfig.build.json +++ b/account-kit/core/tsconfig.build.json @@ -4,6 +4,7 @@ "node_modules", "**/*/__tests__", "**/*/*.test.ts", + "**/*/*.test-d.ts", "**/*/*.e2e.test.ts", "vitest.config.ts", "vitest.config.e2e.ts" diff --git a/account-kit/infra/package.json b/account-kit/infra/package.json index 2912b185b3..574dd6ec52 100644 --- a/account-kit/infra/package.json +++ b/account-kit/infra/package.json @@ -18,6 +18,7 @@ "!vitest.config.ts", "!.env", "!src/**/*.test.ts", + "!src/**/*.test-d.ts", "!src/__tests__/**/*" ], "exports": { diff --git a/account-kit/infra/tsconfig.build.json b/account-kit/infra/tsconfig.build.json index 605911996a..a9532f066c 100644 --- a/account-kit/infra/tsconfig.build.json +++ b/account-kit/infra/tsconfig.build.json @@ -4,6 +4,7 @@ "node_modules", "**/*/__tests__", "**/*/*.test.ts", + "**/*/*.test-d.ts", "**/*/*.e2e.test.ts", "vitest.config.ts", "vitest.config.e2e.ts" diff --git a/account-kit/logging/package.json b/account-kit/logging/package.json index 50e20f7578..7c07d7f1b3 100644 --- a/account-kit/logging/package.json +++ b/account-kit/logging/package.json @@ -18,6 +18,7 @@ "!vitest.config.ts", "!.env", "!src/**/*.test.ts", + "!src/**/*.test-d.ts", "!src/__tests__/**/*" ], "exports": { diff --git a/account-kit/logging/tsconfig.build.json b/account-kit/logging/tsconfig.build.json index 7bae05bd62..5de5b77262 100644 --- a/account-kit/logging/tsconfig.build.json +++ b/account-kit/logging/tsconfig.build.json @@ -4,6 +4,7 @@ "node_modules", "**/*/__tests__", "**/*/*.test.ts", + "**/*/*.test-d.ts", "**/*/*.e2e.test.ts", "vitest.config.ts", "vitest.config.e2e.ts" diff --git a/account-kit/plugingen/package.json b/account-kit/plugingen/package.json index ee59eda39a..d04ea780b1 100644 --- a/account-kit/plugingen/package.json +++ b/account-kit/plugingen/package.json @@ -17,6 +17,7 @@ "!vitest.config.ts", "!.env", "!src/**/*.test.ts", + "!src/**/*.test-d.ts", "!src/__tests__/**/*" ], "exports": { diff --git a/account-kit/plugingen/tsconfig.build.json b/account-kit/plugingen/tsconfig.build.json index 7bae05bd62..5de5b77262 100644 --- a/account-kit/plugingen/tsconfig.build.json +++ b/account-kit/plugingen/tsconfig.build.json @@ -4,6 +4,7 @@ "node_modules", "**/*/__tests__", "**/*/*.test.ts", + "**/*/*.test-d.ts", "**/*/*.e2e.test.ts", "vitest.config.ts", "vitest.config.e2e.ts" diff --git a/account-kit/react/package.json b/account-kit/react/package.json index f4c449b689..bde1192cc6 100644 --- a/account-kit/react/package.json +++ b/account-kit/react/package.json @@ -19,6 +19,7 @@ "!vitest.config.ts", "!.env", "!src/**/*.test.ts", + "!src/**/*.test-d.ts", "!src/__tests__/**/*" ], "exports": { diff --git a/account-kit/react/tsconfig.build.json b/account-kit/react/tsconfig.build.json index 96bf1023be..8c0c953a27 100644 --- a/account-kit/react/tsconfig.build.json +++ b/account-kit/react/tsconfig.build.json @@ -4,6 +4,7 @@ "node_modules", "**/*/__tests__", "**/*/*.test.ts", + "**/*/*.test-d.ts", "**/*/*.e2e.test.ts", "vitest.config.ts", "vitest.config.e2e.ts", diff --git a/account-kit/react/tsconfig.storybook.json b/account-kit/react/tsconfig.storybook.json index 7b12f187f6..76cb4c347c 100644 --- a/account-kit/react/tsconfig.storybook.json +++ b/account-kit/react/tsconfig.storybook.json @@ -9,6 +9,7 @@ "exclude": [ "src/**/*.spec.ts", "src/**/*.test.ts", + "src/**/*.test-d.ts", "src/**/*.spec.js", "src/**/*.test.js", "src/**/*.spec.tsx", diff --git a/account-kit/signer/package.json b/account-kit/signer/package.json index 911cadd005..dc5cadaca9 100644 --- a/account-kit/signer/package.json +++ b/account-kit/signer/package.json @@ -18,6 +18,7 @@ "!vitest.config.ts", "!.env", "!src/**/*.test.ts", + "!src/**/*.test-d.ts", "!src/__tests__/**/*" ], "exports": { diff --git a/account-kit/signer/tsconfig.build.json b/account-kit/signer/tsconfig.build.json index 605911996a..a9532f066c 100644 --- a/account-kit/signer/tsconfig.build.json +++ b/account-kit/signer/tsconfig.build.json @@ -4,6 +4,7 @@ "node_modules", "**/*/__tests__", "**/*/*.test.ts", + "**/*/*.test-d.ts", "**/*/*.e2e.test.ts", "vitest.config.ts", "vitest.config.e2e.ts" diff --git a/account-kit/smart-contracts/package.json b/account-kit/smart-contracts/package.json index 2f5127ff58..c5bd982a6e 100644 --- a/account-kit/smart-contracts/package.json +++ b/account-kit/smart-contracts/package.json @@ -19,6 +19,7 @@ "!vitest.config.ts", "!.env", "!src/**/*.test.ts", + "!src/**/*.test-d.ts", "!src/__tests__/**/*" ], "exports": { diff --git a/account-kit/smart-contracts/src/light-account/clients/client.test-d.ts b/account-kit/smart-contracts/src/light-account/clients/client.test-d.ts new file mode 100644 index 0000000000..5b6eb292a2 --- /dev/null +++ b/account-kit/smart-contracts/src/light-account/clients/client.test-d.ts @@ -0,0 +1,125 @@ +import { + erc7677Middleware, + LocalAccountSigner, + type SmartAccountClient, + type SmartAccountSigner, +} from "@aa-sdk/core"; +import { + custom, + type Address, + type Chain, + type Client, + type CustomTransport, +} from "viem"; +import { accounts } from "~test/constants.js"; +import { local060Instance } from "~test/instances.js"; +import type { LightAccountVersion } from "../types.js"; +import { createLightAccountClient } from "./client.js"; +import { + alchemy, + polygonMumbai, + alchemyEnhancedApiActions, + type AlchemyTransport, + type AlchemySmartAccountClient, + type AlchemyEnhancedApis, +} from "@account-kit/infra"; +import { Alchemy, Network } from "alchemy-sdk"; + +describe("Types: Light Account Tests", () => { + const instance = local060Instance; + const signer: SmartAccountSigner = new LocalAccountSigner( + accounts.fundedAccountOwner + ); + + const givenConnectedProvider = ({ + signer, + version = "v1.1.0", + accountAddress, + usePaymaster = false, + }: { + signer: SmartAccountSigner; + version?: LightAccountVersion<"LightAccount">; + usePaymaster?: boolean; + accountAddress?: Address; + }) => + createLightAccountClient({ + signer, + accountAddress, + version, + transport: custom(instance.getClient()), + chain: instance.chain, + ...(usePaymaster ? erc7677Middleware() : {}), + }); + + const givenAlchemyConnectedProvider = async ({ + signer, + chain, + }: { + signer: SmartAccountSigner; + chain: Chain; + }) => + createLightAccountClient({ + transport: alchemy({ + jwt: "test", + }), + chain, + signer, + accountAddress: "0x86f3B0211764971Ad0Fc8C8898d31f5d792faD84", + }); + it("Should have some alchemy specific types", async () => { + const alchemy = new Alchemy({ + network: Network.MATIC_MUMBAI, + apiKey: "test", + }); + const chain = polygonMumbai; + + const provider = ( + await givenAlchemyConnectedProvider({ signer, chain }) + ).extend(alchemyEnhancedApiActions(alchemy)); + + assertType>(provider); + assertType(provider); + assertType(provider); + assertType(provider); + assertType( + // @ts-expect-error + await givenAlchemyConnectedProvider({ signer, chain }) + ); + // @ts-expect-error + assertType>(provider); + }); + it("Should have some non-alchemy specific types", async () => { + const chain = polygonMumbai; + + const signer: SmartAccountSigner = new LocalAccountSigner( + accounts.fundedAccountOwner + ); + const provider = await givenConnectedProvider({ + signer, + version: "v1.0.1", + }); + + assertType(provider); + assertType>(provider); + assertType( + // @ts-expect-error + await givenAlchemyConnectedProvider({ signer, chain }) + ); + // @ts-expect-error + assertType>(provider); + // @ts-expect-error + assertType(provider); + // @ts-expect-error + assertType(provider); + + expect(() => { + const alchemy = new Alchemy({ + network: Network.MATIC_MUMBAI, + apiKey: "test", + }); + + // @ts-expect-error + provider.extend(alchemyEnhancedApiActions(alchemy)); + }).not.toBeFalsy(); + }); +}); diff --git a/account-kit/smart-contracts/src/light-account/clients/client.test.ts b/account-kit/smart-contracts/src/light-account/clients/client.test.ts index 25442a97da..0c58a7c142 100644 --- a/account-kit/smart-contracts/src/light-account/clients/client.test.ts +++ b/account-kit/smart-contracts/src/light-account/clients/client.test.ts @@ -4,21 +4,12 @@ import { erc7677Middleware, LocalAccountSigner, type BatchUserOperationCallData, - type SmartAccountClient, type SmartAccountSigner, type UserOperationCallData, type UserOperationOverrides, type UserOperationStruct, } from "@aa-sdk/core"; -import { - custom, - parseEther, - type Address, - publicActions, - type Chain, - type Client, - type CustomTransport, -} from "viem"; +import { custom, parseEther, type Address, publicActions } from "viem"; import { setBalance } from "viem/actions"; import { resetBalance } from "~test/accounts.js"; import { accounts } from "~test/constants.js"; @@ -30,15 +21,6 @@ import { getMSCAUpgradeToData } from "../../msca/utils.js"; import type { LightAccountVersion } from "../types.js"; import { AccountVersionRegistry } from "../utils.js"; import { createLightAccountClient } from "./client.js"; -import { - alchemy, - polygonMumbai, - alchemyEnhancedApiActions, - type AlchemyTransport, - type AlchemySmartAccountClient, - type AlchemyEnhancedApis, -} from "@account-kit/infra"; -import { Alchemy, Network } from "alchemy-sdk"; const versions = Object.keys( AccountVersionRegistry.LightAccount @@ -405,76 +387,4 @@ describe("Light Account Tests", () => { chain: instance.chain, ...(usePaymaster ? erc7677Middleware() : {}), }); - - const givenAlchemyConnectedProvider = async ({ - signer, - chain, - }: { - signer: SmartAccountSigner; - chain: Chain; - }) => - createLightAccountClient({ - transport: alchemy({ - jwt: "test", - }), - chain, - signer, - accountAddress: "0x86f3B0211764971Ad0Fc8C8898d31f5d792faD84", - }); - it("Should have some alchemy specific types", async () => { - const alchemy = new Alchemy({ - network: Network.MATIC_MUMBAI, - apiKey: "test", - }); - const chain = polygonMumbai; - - const provider = ( - await givenAlchemyConnectedProvider({ signer, chain }) - ).extend(alchemyEnhancedApiActions(alchemy)); - - assertType>(provider); - assertType(provider); - assertType(provider); - assertType(provider); - assertType( - // @ts-expect-error - await givenAlchemyConnectedProvider({ signer, chain }) - ); - // @ts-expect-error - assertType>(provider); - }); - it("Should have some non-alchemy specific types", async () => { - const chain = polygonMumbai; - - const signer: SmartAccountSigner = new LocalAccountSigner( - accounts.fundedAccountOwner - ); - const provider = await givenConnectedProvider({ - signer, - version: "v1.0.1", - }); - - assertType(provider); - assertType>(provider); - assertType( - // @ts-expect-error - await givenAlchemyConnectedProvider({ signer, chain }) - ); - // @ts-expect-error - assertType>(provider); - // @ts-expect-error - assertType(provider); - // @ts-expect-error - assertType(provider); - - expect(() => { - const alchemy = new Alchemy({ - network: Network.MATIC_MUMBAI, - apiKey: "test", - }); - - // @ts-expect-error - provider.extend(alchemyEnhancedApiActions(alchemy)); - }).not.toBeFalsy(); - }); }); diff --git a/account-kit/smart-contracts/tsconfig.build.json b/account-kit/smart-contracts/tsconfig.build.json index 2c54d60030..563e06f2ca 100644 --- a/account-kit/smart-contracts/tsconfig.build.json +++ b/account-kit/smart-contracts/tsconfig.build.json @@ -4,6 +4,7 @@ "node_modules", "**/*/__tests__", "**/*/*.test.ts", + "**/*/*.test-d.ts", "**/*/*.e2e.test.ts", "vitest.config.ts", "vitest.config.e2e.ts" diff --git a/doc-gen/package.json b/doc-gen/package.json index 99b37e0c35..fd0a585d77 100644 --- a/doc-gen/package.json +++ b/doc-gen/package.json @@ -17,6 +17,7 @@ "!vitest.config.ts", "!.env", "!src/**/*.test.ts", + "!src/**/*.test-d.ts", "!src/__tests__/**/*" ], "exports": { diff --git a/doc-gen/tsconfig.build.json b/doc-gen/tsconfig.build.json index 1eed8a513d..0f3429ff0a 100644 --- a/doc-gen/tsconfig.build.json +++ b/doc-gen/tsconfig.build.json @@ -4,6 +4,7 @@ "node_modules", "**/*/__tests__", "**/*/*.test.ts", + "**/*/*.test-d.ts", "**/*/*.e2e.test.ts", "vitest.config.ts", "vitest.config.e2e.ts" diff --git a/package.json b/package.json index 21d4b67145..f2d077d767 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ "docs:gen": "turbo run docs:gen", "test": "vitest dev", "test:ci": "vitest run", + "test:typecheck": "TYPECHECK=true vitest --typecheck --typecheck.only ", "lint:write": "eslint . --fix && yarn docs:gen && prettier --loglevel warn --write --ignore-unknown .", "lint:check": "eslint . && prettier --check .", "prepare": "husky install && yarn turbo prepare", diff --git a/site/pages/reference/account-kit/infra/functions/isAlchemyTransport.mdx b/site/pages/reference/account-kit/infra/functions/isAlchemyTransport.mdx deleted file mode 100644 index 8e3c9944c1..0000000000 --- a/site/pages/reference/account-kit/infra/functions/isAlchemyTransport.mdx +++ /dev/null @@ -1,36 +0,0 @@ ---- -# This file is autogenerated -title: isAlchemyTransport -description: Overview of the isAlchemyTransport method ---- - -# isAlchemyTransport - -Checks whether the given transport is an AlchemyTransport. - -## Import - -```ts -import { isAlchemyTransport } from "@account-kit/infra"; -``` - -## Usage - -```ts -import { isAlchemyTransport } from "@account-kit/infra"; -if (isAlchemyTransport(transport)) { - // do things here that are only when transport is an AlchemyTransport -} -``` - -## Parameters - -### x - -`Transport | AlchemyTransport` -The transport to check. - -## Returns - -`boolean` -True if the transport is of type AlchemyTransport, otherwise false. From fe8f14b9f1dedcb2c3430103e5928f19dc9c0526 Mon Sep 17 00:00:00 2001 From: moldy Date: Fri, 10 Jan 2025 18:47:39 -0500 Subject: [PATCH 3/4] docs: remove dead reference docs --- .../functions/createSMAV2Account.mdx | 28 -------- .../functions/createSMAV2AccountClient.mdx | 52 -------------- .../getDefaultAllowlistModuleAddress.mdx | 37 ---------- ...etDefaultNativeTokenLimitModuleAddress.mdx | 37 ---------- .../getDefaultPaymasterGuardModuleAddress.mdx | 37 ---------- ...ultSingleSignerValidationModuleAddress.mdx | 37 ---------- .../getDefaultTimeRangeModuleAddress.mdx | 37 ---------- ...DefaultWebauthnValidationModuleAddress.mdx | 37 ---------- .../functions/installValidationActions.mdx | 69 ------------------- .../functions/nativeSMASigner.mdx | 53 -------------- .../functions/serializeHookConfig.mdx | 49 ------------- .../functions/serializeModuleEntity.mdx | 43 ------------ .../functions/serializeValidationConfig.mdx | 49 ------------- 13 files changed, 565 deletions(-) delete mode 100644 site/pages/reference/account-kit/smart-contracts/functions/createSMAV2Account.mdx delete mode 100644 site/pages/reference/account-kit/smart-contracts/functions/createSMAV2AccountClient.mdx delete mode 100644 site/pages/reference/account-kit/smart-contracts/functions/getDefaultAllowlistModuleAddress.mdx delete mode 100644 site/pages/reference/account-kit/smart-contracts/functions/getDefaultNativeTokenLimitModuleAddress.mdx delete mode 100644 site/pages/reference/account-kit/smart-contracts/functions/getDefaultPaymasterGuardModuleAddress.mdx delete mode 100644 site/pages/reference/account-kit/smart-contracts/functions/getDefaultSingleSignerValidationModuleAddress.mdx delete mode 100644 site/pages/reference/account-kit/smart-contracts/functions/getDefaultTimeRangeModuleAddress.mdx delete mode 100644 site/pages/reference/account-kit/smart-contracts/functions/getDefaultWebauthnValidationModuleAddress.mdx delete mode 100644 site/pages/reference/account-kit/smart-contracts/functions/installValidationActions.mdx delete mode 100644 site/pages/reference/account-kit/smart-contracts/functions/nativeSMASigner.mdx delete mode 100644 site/pages/reference/account-kit/smart-contracts/functions/serializeHookConfig.mdx delete mode 100644 site/pages/reference/account-kit/smart-contracts/functions/serializeModuleEntity.mdx delete mode 100644 site/pages/reference/account-kit/smart-contracts/functions/serializeValidationConfig.mdx diff --git a/site/pages/reference/account-kit/smart-contracts/functions/createSMAV2Account.mdx b/site/pages/reference/account-kit/smart-contracts/functions/createSMAV2Account.mdx deleted file mode 100644 index d789f0559b..0000000000 --- a/site/pages/reference/account-kit/smart-contracts/functions/createSMAV2Account.mdx +++ /dev/null @@ -1,28 +0,0 @@ ---- -# This file is autogenerated -title: createSMAV2Account -description: Overview of the createSMAV2Account method ---- - -# createSMAV2Account - -Creates an SMAV2 account using defined parameters including chain, signer, salt, factory address, and more. -Handles account initialization code, nonce generation, transaction encoding, and more to construct a modular account with optional validation hooks. - -## Import - -```ts -import { createSMAV2Account } from "@account-kit/smart-contracts"; -``` - -## Parameters - -### config - -`CreateSMAV2AccountParams` -Configuration parameters for creating an SMAV2 account. Includes chain details, signer, salt, factory address, and more. - -## Returns - -`Promise` -A promise that resolves to an `MAV2Account` providing methods for nonce retrieval, transaction execution, and more. diff --git a/site/pages/reference/account-kit/smart-contracts/functions/createSMAV2AccountClient.mdx b/site/pages/reference/account-kit/smart-contracts/functions/createSMAV2AccountClient.mdx deleted file mode 100644 index 8b7bcd96ab..0000000000 --- a/site/pages/reference/account-kit/smart-contracts/functions/createSMAV2AccountClient.mdx +++ /dev/null @@ -1,52 +0,0 @@ ---- -# This file is autogenerated - -title: createSMAV2AccountClient -description: Overview of the createSMAV2AccountClient method ---- - -# createSMAV2AccountClient - -Creates a SMAv2 account client using the provided configuration parameters. - -## Import - -```ts -import { createSMAV2AccountClient } from "@account-kit/smart-contracts"; -``` - -## Usage - -```ts -import { http } from "viem"; -import { createSMAV2AccountClient } from "@account-kit/smart-contracts"; -import { LocalAccountSigner } from "@aa-sdk/core"; -import { sepolia } from "@account-kit/infra"; - -const MNEMONIC = "..."; -const RPC_URL = "..."; - -const signer = LocalAccountSigner.mnemonicToAccountSigner(MNEMONIC); - -const chain = sepolia; - -const transport = http(RPC_URL); - -const SMAV2SignerAccountClient = await createSMAV2AccountClient({ - chain, - signer, - transport, -}); -``` - -## Parameters - -### config - -`CreateSMAV2AccountClientParams` -The configuration parameters required to create the MAv2 account client - -## Returns - -`Promise` -A promise that resolves to a `SmartAccountClient` instance diff --git a/site/pages/reference/account-kit/smart-contracts/functions/getDefaultAllowlistModuleAddress.mdx b/site/pages/reference/account-kit/smart-contracts/functions/getDefaultAllowlistModuleAddress.mdx deleted file mode 100644 index 5522e43076..0000000000 --- a/site/pages/reference/account-kit/smart-contracts/functions/getDefaultAllowlistModuleAddress.mdx +++ /dev/null @@ -1,37 +0,0 @@ ---- -# This file is autogenerated -title: getDefaultAllowlistModuleAddress -description: Overview of the getDefaultAllowlistModuleAddress method ---- - -# getDefaultAllowlistModuleAddress - -Maps a given chain to a specific address of the allowlist module by its chain ID. If no direct mapping exists, it defaults to returning a specific address. - -## Import - -```ts -import { getDefaultAllowlistModuleAddress } from "@account-kit/smart-contracts"; -``` - -## Usage - -```ts -import { getDefaultAllowlistModuleAddress } from "@account-kit/smart-contracts"; -import { Chain, Address } from "viem"; - -const chain: Chain = ... -const allowlistModule: Address = getDefaultAllowlistModuleAddress(chain); -``` - -## Parameters - -### chain - -`Chain` -The chain object containing the chain ID to map - -## Returns - -`Address` -The allowlist module address associated with the specified chain ID or a default address if no specific mapping exists diff --git a/site/pages/reference/account-kit/smart-contracts/functions/getDefaultNativeTokenLimitModuleAddress.mdx b/site/pages/reference/account-kit/smart-contracts/functions/getDefaultNativeTokenLimitModuleAddress.mdx deleted file mode 100644 index 54dcc49268..0000000000 --- a/site/pages/reference/account-kit/smart-contracts/functions/getDefaultNativeTokenLimitModuleAddress.mdx +++ /dev/null @@ -1,37 +0,0 @@ ---- -# This file is autogenerated -title: getDefaultNativeTokenLimitModuleAddress -description: Overview of the getDefaultNativeTokenLimitModuleAddress method ---- - -# getDefaultNativeTokenLimitModuleAddress - -Maps a given chain to a specific address of the native token limit module by its chain ID. If no direct mapping exists, it defaults to returning a specific address. - -## Import - -```ts -import { getDefaultNativeTokenLimitModuleAddress } from "@account-kit/smart-contracts"; -``` - -## Usage - -```ts -import { getDefaultNativeTokenLimitModuleAddress } from "@account-kit/smart-contracts"; -import { Chain, Address } from "viem"; - -const chain: Chain = ... -const nativeTokenLimitAddress: Address = getDefaultNativeTokenLimitModuleAddress(chain); -``` - -## Parameters - -### chain - -`Chain` -The chain object containing the chain ID to map - -## Returns - -`Address` -The native token limit module address associated with the specified chain ID or a default address if no specific mapping exists diff --git a/site/pages/reference/account-kit/smart-contracts/functions/getDefaultPaymasterGuardModuleAddress.mdx b/site/pages/reference/account-kit/smart-contracts/functions/getDefaultPaymasterGuardModuleAddress.mdx deleted file mode 100644 index 11e25ca3b0..0000000000 --- a/site/pages/reference/account-kit/smart-contracts/functions/getDefaultPaymasterGuardModuleAddress.mdx +++ /dev/null @@ -1,37 +0,0 @@ ---- -# This file is autogenerated -title: getDefaultPaymasterGuardModuleAddress -description: Overview of the getDefaultPaymasterGuardModuleAddress method ---- - -# getDefaultPaymasterGuardModuleAddress - -Maps a given chain to a specific address of the paymaster guard module by its chain ID. If no direct mapping exists, it defaults to returning a specific address. - -## Import - -```ts -import { getDefaultPaymasterGuardModuleAddress } from "@account-kit/smart-contracts"; -``` - -## Usage - -```ts -import { getDefaultPaymasterGuardModuleAddress } from "@account-kit/smart-contracts"; -import { Chain, Address } from "viem"; - -const chain: Chain = ... -const paymasterGuardAddress: Address = getDefaultPaymasterGuardModuleAddress(chain); -``` - -## Parameters - -### chain - -`Chain` -The chain object containing the chain ID to map - -## Returns - -`Address` -The paymaster guard module address associated with the specified chain ID or a default address if no specific mapping exists diff --git a/site/pages/reference/account-kit/smart-contracts/functions/getDefaultSingleSignerValidationModuleAddress.mdx b/site/pages/reference/account-kit/smart-contracts/functions/getDefaultSingleSignerValidationModuleAddress.mdx deleted file mode 100644 index 04c02888cc..0000000000 --- a/site/pages/reference/account-kit/smart-contracts/functions/getDefaultSingleSignerValidationModuleAddress.mdx +++ /dev/null @@ -1,37 +0,0 @@ ---- -# This file is autogenerated -title: getDefaultSingleSignerValidationModuleAddress -description: Overview of the getDefaultSingleSignerValidationModuleAddress method ---- - -# getDefaultSingleSignerValidationModuleAddress - -Maps a given chain to a specific address of the single signer validation module by its chain ID. If no direct mapping exists, it defaults to returning a specific address. - -## Import - -```ts -import { getDefaultSingleSignerValidationModuleAddress } from "@account-kit/smart-contracts"; -``` - -## Usage - -```ts -import { getDefaultSingleSignerValidationModuleAddress } from "@account-kit/smart-contracts"; -import { Chain, Address } from "viem"; - -const chain: Chain = ... -const singleSignerValidationAddress: Address = getDefaultSingleSignerValidationModuleAddress(chain); -``` - -## Parameters - -### chain - -`Chain` -The chain object containing the chain ID to map - -## Returns - -`Address` -The single signer validation module address associated with the specified chain ID or a default address if no specific mapping exists diff --git a/site/pages/reference/account-kit/smart-contracts/functions/getDefaultTimeRangeModuleAddress.mdx b/site/pages/reference/account-kit/smart-contracts/functions/getDefaultTimeRangeModuleAddress.mdx deleted file mode 100644 index 3de832b874..0000000000 --- a/site/pages/reference/account-kit/smart-contracts/functions/getDefaultTimeRangeModuleAddress.mdx +++ /dev/null @@ -1,37 +0,0 @@ ---- -# This file is autogenerated -title: getDefaultTimeRangeModuleAddress -description: Overview of the getDefaultTimeRangeModuleAddress method ---- - -# getDefaultTimeRangeModuleAddress - -Maps a given chain to a specific address of the time range module by its chain ID. If no direct mapping exists, it defaults to returning a specific address. - -## Import - -```ts -import { getDefaultTimeRangeModuleAddress } from "@account-kit/smart-contracts"; -``` - -## Usage - -```ts -import { getDefaultTimeRangeModuleAddress } from "@account-kit/smart-contracts"; -import { Chain, Address } from "viem"; - -const chain: Chain = ... -const timeRangeModuleAddress: Address = getDefaultTimeRangeModuleAddress(chain); -``` - -## Parameters - -### chain - -`Chain` -The chain object containing the chain ID to map - -## Returns - -`Address` -The time range module address associated with the specified chain ID or a default address if no specific mapping exists diff --git a/site/pages/reference/account-kit/smart-contracts/functions/getDefaultWebauthnValidationModuleAddress.mdx b/site/pages/reference/account-kit/smart-contracts/functions/getDefaultWebauthnValidationModuleAddress.mdx deleted file mode 100644 index fd27c9dac5..0000000000 --- a/site/pages/reference/account-kit/smart-contracts/functions/getDefaultWebauthnValidationModuleAddress.mdx +++ /dev/null @@ -1,37 +0,0 @@ ---- -# This file is autogenerated -title: getDefaultWebauthnValidationModuleAddress -description: Overview of the getDefaultWebauthnValidationModuleAddress method ---- - -# getDefaultWebauthnValidationModuleAddress - -Maps a given chain to a specific address of the webauthn validation module by its chain ID. If no direct mapping exists, it defaults to returning a specific address. - -## Import - -```ts -import { getDefaultWebauthnValidationModuleAddress } from "@account-kit/smart-contracts"; -``` - -## Usage - -```ts -import { getDefaultWebauthnValidationModuleAddress } from "@account-kit/smart-contracts"; -import { Chain, Address } from "viem"; - -const chain: Chain = ... -const webauthnValidationAddress: Address = getDefaultWebauthnValidationModuleAddress(chain); -``` - -## Parameters - -### chain - -`Chain` -The chain object containing the chain ID to map - -## Returns - -`Address` -The webauthn validation module address associated with the specified chain ID or a default address if no specific mapping exists diff --git a/site/pages/reference/account-kit/smart-contracts/functions/installValidationActions.mdx b/site/pages/reference/account-kit/smart-contracts/functions/installValidationActions.mdx deleted file mode 100644 index 602162dacc..0000000000 --- a/site/pages/reference/account-kit/smart-contracts/functions/installValidationActions.mdx +++ /dev/null @@ -1,69 +0,0 @@ ---- -# This file is autogenerated - -title: installValidationActions -description: Overview of the installValidationActions method ---- - -# installValidationActions - -Provides validation installation and uninstallation functionalities for a MA v2 client, ensuring compatibility with `SmartAccountClient`. - -## Import - -```ts -import { installValidationActions } from "@account-kit/smart-contracts"; -``` - -## Usage - -```ts -import { createSMAV2AccountClient, installValidationActions, getDefaultSingleSignerValidationModuleAddress, SingleSignerValidationModule } from "@account-kit/smart-contracts"; -import { Address } from "viem"; - -const client = (await createSMAV2AccountClient({ ... })).extend(installValidationActions); -const sessionKeyAddress: Address = "0x1234"; -const sessionKeyEntityId: number = 1; - -await client.installValidation({ -validationConfig: { -moduleAddress: getDefaultSingleSignerValidationModuleAddress( - client.chain -), -entityId: sessionKeyEntityId, -isGlobal: true, -isSignatureValidation: false, -isUserOpValidation: true, -}, -selectors: [], -installData: SingleSignerValidationModule.encodeOnInstallData({ -entityId: sessionKeyEntityId, -signer: sessionKeyAddress, -}), -hooks: [], -}); - -await client.uninstallValidation({ -moduleAddress: sessionKeyAddress, -entityId: sessionKeyEntityId, -uninstallData: SingleSignerValidationModule.encodeOnUninstallData({ -entityId: sessionKeyEntityId, -}), -hookUninstallDatas: [], -}); - -``` - -## Parameters - -### client - -`object` - -- The client instance which provides account and sendUserOperation functionality. - - ## Returns - - `object` - -- An object containing two methods, `installValidation` and `uninstallValidation`. diff --git a/site/pages/reference/account-kit/smart-contracts/functions/nativeSMASigner.mdx b/site/pages/reference/account-kit/smart-contracts/functions/nativeSMASigner.mdx deleted file mode 100644 index 0052b9b056..0000000000 --- a/site/pages/reference/account-kit/smart-contracts/functions/nativeSMASigner.mdx +++ /dev/null @@ -1,53 +0,0 @@ ---- -# This file is autogenerated -title: nativeSMASigner -description: Overview of the nativeSMASigner method ---- - -# nativeSMASigner - -Creates an object with methods for generating a dummy signature, signing user operation hashes, signing messages, and signing typed data. - -## Import - -```ts -import { nativeSMASigner } from "@account-kit/smart-contracts"; -``` - -## Usage - -```ts -import { nativeSMASigner } from "@account-kit/smart-contracts"; - -import { LocalAccountSigner } from "@aa-sdk/core"; - -const MNEMONIC = "...": - -const account = createSMAV2Account({ config }); - -const signer = LocalAccountSigner.mnemonicToAccountSigner(MNEMONIC); - -const messageSigner = nativeSMASigner(signer, chain, account.address); -``` - -## Parameters - -### signer - -`SmartAccountSigner` -Signer to use for signing operations - -### chain - -`Chain` -Chain object for the signer - -### accountAddress - -`Address` -address of the smart account using this signer - -## Returns - -`object` -an object with methods for signing operations and managing signatures diff --git a/site/pages/reference/account-kit/smart-contracts/functions/serializeHookConfig.mdx b/site/pages/reference/account-kit/smart-contracts/functions/serializeHookConfig.mdx deleted file mode 100644 index 94b6f1f3b1..0000000000 --- a/site/pages/reference/account-kit/smart-contracts/functions/serializeHookConfig.mdx +++ /dev/null @@ -1,49 +0,0 @@ ---- -# This file is autogenerated - -title: serializeHookConfig -description: Overview of the serializeHookConfig method ---- - -# serializeHookConfig - -Serializes a `HookConfig` object into a `Hex` format by encoding the hook type, presence of post/pre hooks, address, and entity ID. - -## Import - -```ts -import { serializeHookConfig } from "@account-kit/smart-contracts"; -``` - -## Usage - -```ts -import { type HookType, serializeHookConfig } from "@account-kit/smart-contracts"; -import { Address } from "viem"; - -const moduleAddress: Address = "0x1234"; -const entityId: number = 1234; -const hookType: HookType = HookType.Validation; -const hasPostHooks: boolean = false; -const hasPreHooks: boolean = true; - -const hookConfigHex = serializeHookConfig({ -moduleAddress, -entityId -hookType, -hasPostHooks, -hasPreHooks -}); -``` - -## Parameters - -### config - -`HookConfig` -The hook configuration containing address, entity ID, hook type, and post/pre hook indicators - -## Returns - -`Hex` -The serialized hook configuration in hexadecimal format diff --git a/site/pages/reference/account-kit/smart-contracts/functions/serializeModuleEntity.mdx b/site/pages/reference/account-kit/smart-contracts/functions/serializeModuleEntity.mdx deleted file mode 100644 index a95495eaa9..0000000000 --- a/site/pages/reference/account-kit/smart-contracts/functions/serializeModuleEntity.mdx +++ /dev/null @@ -1,43 +0,0 @@ ---- -# This file is autogenerated - -title: serializeModuleEntity -description: Overview of the serializeModuleEntity method ---- - -# serializeModuleEntity - -Serializes a module entity into a hexadecimal format by concatenating the module address and entity ID. - -## Import - -```ts -import { serializeModuleEntity } from "@account-kit/smart-contracts"; -``` - -## Usage - -```ts -import { serializeModuleEntity } from "@account-kit/smart-contracts"; -import { Address } from "viem"; - -const moduleAddress: Address = "0x1234"; -const entityId: number = 1234; - -const moduleEntityHex = serializeModuleEntity({ - moduleAddress, - entityId, -}); -``` - -## Parameters - -### config - -`ModuleEntity` -The module entity configuration containing the module address and entity ID - -## Returns - -`Hex` -A hexadecimal string representation of the serialized module entity diff --git a/site/pages/reference/account-kit/smart-contracts/functions/serializeValidationConfig.mdx b/site/pages/reference/account-kit/smart-contracts/functions/serializeValidationConfig.mdx deleted file mode 100644 index f66a26e095..0000000000 --- a/site/pages/reference/account-kit/smart-contracts/functions/serializeValidationConfig.mdx +++ /dev/null @@ -1,49 +0,0 @@ ---- -# This file is autogenerated - -title: serializeValidationConfig -description: Overview of the serializeValidationConfig method ---- - -# serializeValidationConfig - -Serializes a validation configuration into a hexadecimal string representation. This involves converting boolean flags into bitwise representation and combining them with serialized module entity data. - -## Import - -```ts -import { serializeValidationConfig } from "@account-kit/smart-contracts"; -``` - -## Usage - -```ts -import { serializeValidationConfig } from "@account-kit/smart-contracts"; -import { Address } from "viem"; - -const moduleAddress: Address = "0x1234"; -const entityId: number = 1234; -const isGlobal: boolean = true; -const isSignatureValidation: boolean = false; -const isUserOpValidation: boolean = true; - -const validationConfigHex = serializeValidationConfig({ -moduleAddress, -entityId -isGlobal, -isSignatureValidation, -isUserOpValidation -}); -``` - -## Parameters - -### config - -`ValidationConfig` -The validation configuration object containing details to serialize - -## Returns - -`Hex` -A hexadecimal string representing the serialized configuration From 18a922830f5cfcfbed4bf12d064bdf4699e29c6c Mon Sep 17 00:00:00 2001 From: Blu-J <2364004+Blu-J@users.noreply.github.com> Date: Sat, 11 Jan 2025 00:39:14 +0000 Subject: [PATCH 4/4] feat(client): multi account light and alchemy consolidation (#1264) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Pull Request Checklist - [x] Did you add new tests and confirm existing tests pass? (`yarn test`) - [x] Did you update relevant docs? (docs are found in the `site` folder, and guidelines for updating/adding docs can be found in the [contribution guide](https://github.com/alchemyplatform/aa-sdk/blob/main/CONTRIBUTING.md)) - [x] Do your commits follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) standard? - [x] Does your PR title also follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) standard? - [x] If you have a breaking change, is it [correctly reflected in your commit message](https://www.conventionalcommits.org/en/v1.0.0/#examples)? (e.g. `feat!: breaking change`) - [x] Did you run lint (`yarn lint:check`) and fix any issues? (`yarn lint:write`) - [x] Did you follow the [contribution guidelines](https://github.com/alchemyplatform/aa-sdk/blob/main/CONTRIBUTING.md)? --- ## PR-Codex overview This PR focuses on enhancing the functionality of the `alchemyTransport` in the `account-kit` library. It introduces type guards, refactors client creation methods, and updates documentation to streamline the use of Alchemy transport across various account types. ### Detailed summary - Added `isAlchemyTransport` type guard in `alchemyTransport.js`. - Modified exports in `index.ts` to include `isAlchemyTransport`. - Refactored client creation functions to support dynamic transport. - Updated documentation for `isAlchemyTransport` and other functions. - Replaced deprecated client creation methods with new ones. - Enhanced test cases for multi-owner and light account clients. - Adjusted package scripts for type checking. - Improved sidebar references in documentation files. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` --- .vitest/vitest.shared.ts | 4 +- account-kit/infra/src/alchemyTransport.ts | 17 ++ account-kit/infra/src/index.ts | 2 +- .../clients/alchemyClient.test.ts | 3 +- .../light-account/clients/alchemyClient.ts | 19 +-- .../src/light-account/clients/client.ts | 44 ++--- .../clients/multiOwnerAlchemyClient.test.ts | 3 +- .../clients/multiOwnerAlchemyClient.ts | 18 +- .../clients/multiOwnerLightAccount.test-d.ts | 141 ++++++++++++++++ .../clients/multiOwnerLightAccount.ts | 67 +++++++- .../src/msca/client/alchemyClient.ts | 25 +-- .../smart-contracts/src/msca/client/client.ts | 157 ++++++++++++++++-- .../src/msca/client/multiSigAlchemyClient.ts | 35 +--- package.json | 2 +- .../infra/functions/isAlchemyTransport.mdx | 34 ++++ .../createMultiOwnerLightAccountClient.mdx | 4 +- site/pages/third-party/paymasters.mdx | 7 +- site/sidebar/reference/aa-sdk/core.ts | 27 +++ site/sidebar/reference/account-kit/infra.ts | 4 + 19 files changed, 486 insertions(+), 127 deletions(-) create mode 100644 account-kit/smart-contracts/src/light-account/clients/multiOwnerLightAccount.test-d.ts create mode 100644 site/pages/reference/account-kit/infra/functions/isAlchemyTransport.mdx diff --git a/.vitest/vitest.shared.ts b/.vitest/vitest.shared.ts index 50c85b8d64..2e2e1feb99 100644 --- a/.vitest/vitest.shared.ts +++ b/.vitest/vitest.shared.ts @@ -1,9 +1,11 @@ import { join } from "node:path"; import { configDefaults, defineConfig } from "vitest/config"; - +const typechecking = process.env["TYPECHECK"] === "true"; export const sharedConfig = defineConfig({ test: { typecheck: { + enabled: typechecking, + only: typechecking, ignoreSourceErrors: true, }, alias: { diff --git a/account-kit/infra/src/alchemyTransport.ts b/account-kit/infra/src/alchemyTransport.ts index cf3cf94d67..a48196bf59 100644 --- a/account-kit/infra/src/alchemyTransport.ts +++ b/account-kit/infra/src/alchemyTransport.ts @@ -8,6 +8,7 @@ import { import { createTransport, http, + type Chain, type EIP1193RequestFn, type HttpTransportConfig, type PublicRpcSchema, @@ -65,6 +66,22 @@ export type AlchemyTransport = AlchemyTransportBase & { config: AlchemyTransportConfig; }; +/** + * A type guard for the transport to determine if it is an Alchemy transport. + * Used in cases where we would like to do switching depending on the transport, where there used + * to be two clients for a alchemy and a non alchemy, and with this switch we don't need the two seperate clients. * + * + * @param {Transport} transport The transport to check + * @param {Chain} chain Chain for the transport to run its function to return the transport config + * @returns {boolean} `true` if the transport is an Alchemy transport, otherwise `false` + */ +export function isAlchemyTransport( + transport: Transport, + chain: Chain +): transport is AlchemyTransport { + return transport({ chain }).config.type === "alchemy"; +} + /** * Creates an Alchemy transport with the specified configuration options. * When sending all traffic to Alchemy, you must pass in one of rpcUrl, apiKey, or jwt. diff --git a/account-kit/infra/src/index.ts b/account-kit/infra/src/index.ts index d0f4b43ae8..264971748d 100644 --- a/account-kit/infra/src/index.ts +++ b/account-kit/infra/src/index.ts @@ -2,7 +2,7 @@ export type * from "./actions/simulateUserOperationChanges.js"; export { simulateUserOperationChanges } from "./actions/simulateUserOperationChanges.js"; export type * from "./actions/types.js"; export type * from "./alchemyTransport.js"; -export { alchemy } from "./alchemyTransport.js"; +export { alchemy, isAlchemyTransport } from "./alchemyTransport.js"; export type * from "./chains.js"; export { arbitrum, diff --git a/account-kit/smart-contracts/src/light-account/clients/alchemyClient.test.ts b/account-kit/smart-contracts/src/light-account/clients/alchemyClient.test.ts index 22d6247169..b28be01efa 100644 --- a/account-kit/smart-contracts/src/light-account/clients/alchemyClient.test.ts +++ b/account-kit/smart-contracts/src/light-account/clients/alchemyClient.test.ts @@ -13,6 +13,7 @@ import { import { Alchemy, Network } from "alchemy-sdk"; import { avalanche, type Chain } from "viem/chains"; import { createLightAccountAlchemyClient } from "./alchemyClient.js"; +import { createLightAccountClient } from "./client.js"; describe("Light Account Client Tests", () => { const dummyMnemonic = @@ -136,7 +137,7 @@ describe("Light Account Client Tests", () => { signer: SmartAccountSigner; chain: Chain; }) => - createLightAccountAlchemyClient({ + createLightAccountClient({ transport: alchemy({ jwt: "test", }), diff --git a/account-kit/smart-contracts/src/light-account/clients/alchemyClient.ts b/account-kit/smart-contracts/src/light-account/clients/alchemyClient.ts index 12b7b8a19f..b94af6f5e8 100644 --- a/account-kit/smart-contracts/src/light-account/clients/alchemyClient.ts +++ b/account-kit/smart-contracts/src/light-account/clients/alchemyClient.ts @@ -1,12 +1,10 @@ import type { HttpTransport, SmartAccountSigner } from "@aa-sdk/core"; import { - createAlchemySmartAccountClient, type AlchemySmartAccountClient, type AlchemySmartAccountClientConfig, } from "@account-kit/infra"; import { - createLightAccount, - lightAccountClientActions, + createLightAccountClient, type CreateLightAccountParams, type LightAccount, type LightAccountClientActions, @@ -49,7 +47,7 @@ export async function createLightAccountAlchemyClient< * signer: LocalAccountSigner.privateKeyToAccountSigner(generatePrivateKey()) * }); * ``` - * + * @deprecated Use createLightAccountClient instead now, it should switch depending on the transport * @param {AlchemyLightAccountClientConfig} config The configuration for setting up the Alchemy Light Account Client * @returns {Promise} A promise that resolves to an `AlchemySmartAccountClient` object containing the created client */ @@ -59,17 +57,10 @@ export async function createLightAccountAlchemyClient({ chain, ...config }: AlchemyLightAccountClientConfig): Promise { - const account = await createLightAccount({ - ...config, + return createLightAccountClient({ + opts, transport, chain, - }); - - return createAlchemySmartAccountClient({ ...config, - transport, - chain, - account, - opts, - }).extend(lightAccountClientActions); + }); } diff --git a/account-kit/smart-contracts/src/light-account/clients/client.ts b/account-kit/smart-contracts/src/light-account/clients/client.ts index b700030efc..af83979ab2 100644 --- a/account-kit/smart-contracts/src/light-account/clients/client.ts +++ b/account-kit/smart-contracts/src/light-account/clients/client.ts @@ -11,19 +11,18 @@ import { createLightAccount, type CreateLightAccountParams, type LightAccount, -} from "../accounts/account.js"; +} from "@account-kit/smart-contracts"; import { lightAccountClientActions, type LightAccountClientActions, } from "../decorators/lightAccount.js"; import { + isAlchemyTransport, + createAlchemySmartAccountClient, type AlchemySmartAccountClient, type AlchemyTransport, } from "@account-kit/infra"; -import { - createLightAccountAlchemyClient, - type AlchemyLightAccountClientConfig, -} from "./alchemyClient.js"; +import { type AlchemyLightAccountClientConfig } from "./alchemyClient.js"; export type CreateLightAccountClientParams< TTransport extends Transport | AlchemyTransport = Transport, @@ -85,6 +84,19 @@ export function createLightAccountClient< * signer: LocalAccountSigner.privateKeyToAccountSigner(generatePrivateKey()) * }); * ``` + * @example + * ```ts + * import { createLightAccountClient } from "@account-kit/smart-contracts"; + * import { sepolia, alchemy } from "@account-kit/infra"; + * import { LocalAccountSigner } from "@aa-sdk/core"; + * import { generatePrivateKey } from "viem" + * + * const lightAlchemyAccountClient = await createLightAccountClient({ + * transport: alchemy({ apiKey: "your-api-key" }), + * chain: sepolia, + * signer: LocalAccountSigner.privateKeyToAccountSigner(generatePrivateKey()) + * }); + * ``` * * @param {CreateLightAccountClientParams} params The parameters for creating a light account client * @returns {Promise} A promise that resolves to a `SmartAccountClient` object containing the created account information and methods @@ -94,18 +106,19 @@ export async function createLightAccountClient( ): Promise { const { transport, chain } = params; - if (isAlchemyTransport(transport, chain)) { - return await createLightAccountAlchemyClient({ - ...params, - transport, - }); - } - const lightAccount = await createLightAccount({ ...params, transport, chain, }); + if (isAlchemyTransport(transport, chain)) { + return createAlchemySmartAccountClient({ + ...params, + transport, + chain, + account: lightAccount, + }).extend(lightAccountClientActions); + } return createSmartAccountClient({ ...params, @@ -114,10 +127,3 @@ export async function createLightAccountClient( account: lightAccount, }).extend(lightAccountClientActions); } - -function isAlchemyTransport( - transport: Transport, - chain: Chain -): transport is AlchemyTransport { - return transport({ chain }).config.type === "alchemy"; -} diff --git a/account-kit/smart-contracts/src/light-account/clients/multiOwnerAlchemyClient.test.ts b/account-kit/smart-contracts/src/light-account/clients/multiOwnerAlchemyClient.test.ts index 4faff104ab..93ca19dda4 100644 --- a/account-kit/smart-contracts/src/light-account/clients/multiOwnerAlchemyClient.test.ts +++ b/account-kit/smart-contracts/src/light-account/clients/multiOwnerAlchemyClient.test.ts @@ -13,6 +13,7 @@ import { import { Alchemy, Network } from "alchemy-sdk"; import { avalanche, type Chain } from "viem/chains"; import { createMultiOwnerLightAccountAlchemyClient } from "./multiOwnerAlchemyClient.js"; +import { createMultiOwnerLightAccountClient } from "./multiOwnerLightAccount.js"; describe("MultiOwnerLightAccount Client Tests", () => { const dummyMnemonic = @@ -138,7 +139,7 @@ describe("MultiOwnerLightAccount Client Tests", () => { signer: SmartAccountSigner; chain: Chain; }) => - createMultiOwnerLightAccountAlchemyClient({ + createMultiOwnerLightAccountClient({ transport: alchemy({ jwt: "test", }), diff --git a/account-kit/smart-contracts/src/light-account/clients/multiOwnerAlchemyClient.ts b/account-kit/smart-contracts/src/light-account/clients/multiOwnerAlchemyClient.ts index 86c11ec7f0..05477bfb86 100644 --- a/account-kit/smart-contracts/src/light-account/clients/multiOwnerAlchemyClient.ts +++ b/account-kit/smart-contracts/src/light-account/clients/multiOwnerAlchemyClient.ts @@ -1,12 +1,10 @@ import type { HttpTransport, SmartAccountSigner } from "@aa-sdk/core"; import { - createAlchemySmartAccountClient, type AlchemySmartAccountClient, type AlchemySmartAccountClientConfig, } from "@account-kit/infra"; import { - createMultiOwnerLightAccount, - multiOwnerLightAccountClientActions, + createMultiOwnerLightAccountClient, type CreateMultiOwnerLightAccountParams, type MultiOwnerLightAccount, type MultiOwnerLightAccountClientActions, @@ -55,6 +53,7 @@ export async function createMultiOwnerLightAccountAlchemyClient< * }); * ``` * + * @deprecated Use createMultiOwnerLightAccountAlchemyClient instead now, it should switch depending on the transport * @param {AlchemyMultiOwnerLightAccountClientConfig} config The configuration for creating the Alchemy client * @returns {Promise} A promise that resolves to an `AlchemySmartAccountClient` object containing the created account information and methods */ @@ -64,17 +63,10 @@ export async function createMultiOwnerLightAccountAlchemyClient({ chain, ...config }: AlchemyMultiOwnerLightAccountClientConfig): Promise { - const account = await createMultiOwnerLightAccount({ - ...config, + return createMultiOwnerLightAccountClient({ + opts, transport, chain, - }); - - return createAlchemySmartAccountClient({ ...config, - transport, - chain, - account, - opts, - }).extend(multiOwnerLightAccountClientActions); + }); } diff --git a/account-kit/smart-contracts/src/light-account/clients/multiOwnerLightAccount.test-d.ts b/account-kit/smart-contracts/src/light-account/clients/multiOwnerLightAccount.test-d.ts new file mode 100644 index 0000000000..c4219892d2 --- /dev/null +++ b/account-kit/smart-contracts/src/light-account/clients/multiOwnerLightAccount.test-d.ts @@ -0,0 +1,141 @@ +import { + createBundlerClient, + createSmartAccountClientFromExisting, + erc7677Middleware, + LocalAccountSigner, + type Address, + type SmartAccountSigner, +} from "@aa-sdk/core"; +import { custom, type Chain } from "viem"; +import { generatePrivateKey } from "viem/accounts"; +import { setBalance } from "viem/actions"; +import { accounts } from "~test/constants.js"; +import { local070Instance } from "~test/instances.js"; +import { multiOwnerPluginActions } from "../../msca/plugins/multi-owner/index.js"; +import { getMSCAUpgradeToData } from "../../msca/utils.js"; +import type { LightAccountVersion } from "../types"; +import { createMultiOwnerLightAccountClient } from "./multiOwnerLightAccount.js"; +import { + alchemy, + alchemyEnhancedApiActions, + arbitrumSepolia, +} from "@account-kit/infra"; +import { Alchemy, Network } from "alchemy-sdk"; + +describe("Types: MultiOwner Light Account Tests", () => { + const instance = local070Instance; + let client: ReturnType; + + beforeAll(async () => { + client = instance.getClient(); + }); + + const signer: SmartAccountSigner = new LocalAccountSigner( + accounts.fundedAccountOwner + ); + + it("should upgrade a deployed multi owner light account to msca successfully", async () => { + // create a owner signer to create the account + const throwawaySigner = LocalAccountSigner.privateKeyToAccountSigner( + generatePrivateKey() + ); + const throwawayClient = await givenConnectedProvider({ + signer: throwawaySigner, + }); + + const accountAddress = throwawayClient.getAddress(); + const ownerAddress = await throwawaySigner.getAddress(); + + // fund + deploy the throwaway address + await setBalance(client, { + address: accountAddress, + value: 200000000000000000n, + }); + + const { createMAAccount, ...upgradeToData } = await getMSCAUpgradeToData( + throwawayClient, + { + account: throwawayClient.account, + multiOwnerPluginAddress: "0xcE0000007B008F50d762D155002600004cD6c647", + } + ); + + await throwawayClient.upgradeAccount({ + upgradeTo: upgradeToData, + waitForTx: true, + }); + + const upgradedClient = createSmartAccountClientFromExisting({ + client: createBundlerClient({ + chain: instance.chain, + transport: custom(client), + }), + account: await createMAAccount(), + }).extend(multiOwnerPluginActions); + + const upgradedAccountAddress = upgradedClient.getAddress(); + + const owners = await upgradedClient.readOwners({ + account: upgradedClient.account, + pluginAddress: "0xcE0000007B008F50d762D155002600004cD6c647", + }); + + expect(upgradedAccountAddress).toBe(accountAddress); + expect(owners).toContain(ownerAddress); + }, 200000); + + it("should have enhanced api properties on the provider", async () => { + const chain = arbitrumSepolia; + const alchemy = new Alchemy({ + network: Network.MATIC_MUMBAI, + apiKey: "test", + }); + + const provider = ( + await givenAlchemyConnectedProvider({ signer, chain }) + ).extend(alchemyEnhancedApiActions(alchemy)); + + expect(provider.account).toBeDefined(); + expect(provider.waitForUserOperationTransaction).toBeDefined(); + expect(provider.sendUserOperation).toBeDefined(); + expect(provider.core).toBeDefined(); + }); + const givenAlchemyConnectedProvider = async ({ + signer, + chain, + }: { + signer: SmartAccountSigner; + chain: Chain; + }) => + createMultiOwnerLightAccountClient({ + transport: alchemy({ + jwt: "test", + }), + chain, + signer, + accountAddress: "0x86f3B0211764971Ad0Fc8C8898d31f5d792faD84", + }); + + const givenConnectedProvider = ({ + signer, + version = "v2.0.0", + accountAddress, + usePaymaster = false, + accountIndex, + }: { + signer: SmartAccountSigner; + version?: LightAccountVersion<"MultiOwnerLightAccount">; + usePaymaster?: boolean; + accountAddress?: Address; + accountIndex?: bigint; + }) => + createMultiOwnerLightAccountClient({ + signer, + accountAddress, + version, + transport: custom(client), + chain: instance.chain, + salt: accountIndex, + ...(usePaymaster ? erc7677Middleware() : {}), + }); +}); diff --git a/account-kit/smart-contracts/src/light-account/clients/multiOwnerLightAccount.ts b/account-kit/smart-contracts/src/light-account/clients/multiOwnerLightAccount.ts index d6004852b6..1da98a1597 100644 --- a/account-kit/smart-contracts/src/light-account/clients/multiOwnerLightAccount.ts +++ b/account-kit/smart-contracts/src/light-account/clients/multiOwnerLightAccount.ts @@ -8,14 +8,19 @@ import { } from "@aa-sdk/core"; import { type Chain, type CustomTransport, type Transport } from "viem"; import { + multiOwnerLightAccountClientActions, createMultiOwnerLightAccount, type CreateMultiOwnerLightAccountParams, type MultiOwnerLightAccount, -} from "../accounts/multiOwner.js"; -import { - multiOwnerLightAccountClientActions, type MultiOwnerLightAccountClientActions, -} from "../decorators/multiOwnerLightAccount.js"; + type AlchemyMultiOwnerLightAccountClientConfig, +} from "@account-kit/smart-contracts"; +import { + isAlchemyTransport, + createAlchemySmartAccountClient, + type AlchemySmartAccountClient, + type AlchemyTransport, +} from "@account-kit/infra"; export type CreateMultiOwnerLightAccountClientParams< TTransport extends Transport = Transport, @@ -36,6 +41,30 @@ export type CreateMultiOwnerLightAccountClientParams< "transport" | "account" | "chain" >; +export type CreateMultiOwnerLightAccountClientDynamicTransportParams< + TTransport extends Transport = Transport, + TChain extends Chain | undefined = Chain | undefined, + TSigner extends SmartAccountSigner = SmartAccountSigner +> = + | (AlchemyMultiOwnerLightAccountClientConfig & { + transport: AlchemyTransport; + }) + | CreateMultiOwnerLightAccountClientParams; + +export async function createMultiOwnerLightAccountClient< + TSigner extends SmartAccountSigner = SmartAccountSigner +>( + params: AlchemyMultiOwnerLightAccountClientConfig & { + transport: AlchemyTransport; + } +): Promise< + AlchemySmartAccountClient< + Chain | undefined, + MultiOwnerLightAccount, + MultiOwnerLightAccountClientActions + > +>; + export function createMultiOwnerLightAccountClient< TChain extends Chain | undefined = Chain | undefined, TSigner extends SmartAccountSigner = SmartAccountSigner @@ -71,12 +100,28 @@ export function createMultiOwnerLightAccountClient< * }); * ``` * - * @param {CreateMultiOwnerLightAccountClientParams} params the configuration for creating the multi-owner light account client + * @example + * ```ts + * import { createMultiOwnerLightAccountClient } from "@account-kit/smart-contracts"; + * import { sepolia, alchemy } from "@account-kit/infra"; + * import { LocalAccountSigner } from "@aa-sdk/core"; + * import { generatePrivateKey } from "viem" + * + * const lightAccountClient = await createMultiOwnerLightAccountClient({ + * transport: alchemy({ + * apiKey: "your-api-key", + * }), + * chain: sepolia + * signer: LocalAccountSigner.privateKeyToAccountSigner(generatePrivateKey()) + * }); + * ``` + * + * @param {CreateMultiOwnerLightAccountClientDynamicTransportParams} params the configuration for creating the multi-owner light / alchemy account client with the provided parameters transport * @returns {Promise} a promise that resolves to a `SmartAccountClient` containing the created account client and relevant methods */ export async function createMultiOwnerLightAccountClient( - params: CreateMultiOwnerLightAccountClientParams -): Promise { + params: CreateMultiOwnerLightAccountClientDynamicTransportParams +): Promise { const { transport, chain } = params; const lightAccount = await createMultiOwnerLightAccount({ @@ -84,6 +129,14 @@ export async function createMultiOwnerLightAccountClient( transport, chain, }); + if (isAlchemyTransport(transport, chain)) { + return createAlchemySmartAccountClient({ + ...params, + transport, + chain, + account: lightAccount, + }).extend(multiOwnerLightAccountClientActions); + } return createSmartAccountClient({ ...params, diff --git a/account-kit/smart-contracts/src/msca/client/alchemyClient.ts b/account-kit/smart-contracts/src/msca/client/alchemyClient.ts index ef47b8b6a7..20e37eadf4 100644 --- a/account-kit/smart-contracts/src/msca/client/alchemyClient.ts +++ b/account-kit/smart-contracts/src/msca/client/alchemyClient.ts @@ -1,14 +1,10 @@ import type { SmartAccountSigner } from "@aa-sdk/core"; import { - createAlchemySmartAccountClient, type AlchemySmartAccountClient, type AlchemySmartAccountClientConfig, } from "@account-kit/infra"; import { - accountLoupeActions, - createMultiOwnerModularAccount, - multiOwnerPluginActions, - pluginManagerActions, + createMultiOwnerModularAccountClient, type AccountLoupeActions, type CreateMultiOwnerModularAccountParams, type LightAccount, @@ -59,27 +55,12 @@ export function createModularAccountAlchemyClient< * signer: LocalAccountSigner.privateKeyToAccountSigner(generatePrivateKey()) * }); * ``` - * + * @deprecated Use createModularAccountClient instead of this function, we are switching based on the transport * @param {AlchemyModularAccountClientConfig} config The configuration for creating the Alchemy client * @returns {Promise} A promise that resolves to an `AlchemySmartAccountClient` configured with the desired plugins and actions */ export async function createModularAccountAlchemyClient( config: AlchemyModularAccountClientConfig ): Promise { - const { transport, chain, opts } = config; - - const account = await createMultiOwnerModularAccount({ - ...config, - transport, - chain, - }); - - return createAlchemySmartAccountClient({ - ...config, - account, - opts, - }) - .extend(multiOwnerPluginActions) - .extend(pluginManagerActions) - .extend(accountLoupeActions); + return createMultiOwnerModularAccountClient(config); } diff --git a/account-kit/smart-contracts/src/msca/client/client.ts b/account-kit/smart-contracts/src/msca/client/client.ts index b5be02561f..65e61d01b9 100644 --- a/account-kit/smart-contracts/src/msca/client/client.ts +++ b/account-kit/smart-contracts/src/msca/client/client.ts @@ -35,8 +35,16 @@ import { type MultisigUserOperationContext, } from "../plugins/multisig/index.js"; import { multisigSignatureMiddleware } from "../plugins/multisig/middleware.js"; +import type { AlchemyModularAccountClientConfig } from "./alchemyClient.js"; +import { + createAlchemySmartAccountClient, + isAlchemyTransport, + type AlchemySmartAccountClient, + type AlchemyTransport, +} from "@account-kit/infra"; +import type { AlchemyMultisigAccountClientConfig } from "./multiSigAlchemyClient.js"; -export type CreateMultiOwnerModularAccountClientParams< +export type CreateMultiOwnerModularAccountClientWithoutAlchemyParams< TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TSigner extends SmartAccountSigner = SmartAccountSigner @@ -45,8 +53,19 @@ export type CreateMultiOwnerModularAccountClientParams< "transport" | "chain" > & Omit, "account">; +export type CreateMultiOwnerModularAccountClientParams< + TTransport extends Transport = Transport, + TChain extends Chain | undefined = Chain | undefined, + TSigner extends SmartAccountSigner = SmartAccountSigner +> = + | CreateMultiOwnerModularAccountClientWithoutAlchemyParams< + TTransport, + TChain, + TSigner + > + | AlchemyModularAccountClientConfig; -export type CreateMultisigModularAccountClientParams< +export type CreateMultisigModularAccountClientWithoutAlchemyParams< TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TSigner extends SmartAccountSigner = SmartAccountSigner @@ -56,6 +75,34 @@ export type CreateMultisigModularAccountClientParams< > & Omit, "account">; +export type CreateMultisigModularAccountClientParams< + TTransport extends Transport = Transport, + TChain extends Chain | undefined = Chain | undefined, + TSigner extends SmartAccountSigner = SmartAccountSigner +> = + | CreateMultisigModularAccountClientWithoutAlchemyParams< + TTransport, + TChain, + TSigner + > + | AlchemyMultisigAccountClientConfig; + +export function createMultiOwnerModularAccountClient< + TSigner extends SmartAccountSigner = SmartAccountSigner +>( + params: AlchemyModularAccountClientConfig & { + transport: AlchemyTransport; + } +): Promise< + AlchemySmartAccountClient< + Chain | undefined, + MultiOwnerModularAccount, + MultiOwnerPluginActions> & + PluginManagerActions> & + AccountLoupeActions> + > +>; + export function createMultiOwnerModularAccountClient< TChain extends Chain | undefined = Chain | undefined, TSigner extends SmartAccountSigner = SmartAccountSigner @@ -89,6 +136,19 @@ export function createMultiOwnerModularAccountClient< * signer: LocalAccountSigner.privateKeyToAccountSigner(generatePrivateKey()) * }); * ``` + * @example + * ```ts + * import { createMultiOwnerModularAccountClient } from "@account-kit/smart-contracts"; + * import { sepolia, alchemy } from "@account-kit/infra"; + * import { LocalAccountSigner } from "@aa-sdk/core"; + * import { generatePrivateKey } from "viem" + * + * const alchemyAccountClient = await createMultiOwnerModularAccountClient({ + * transport: alchemy({ apiKey: "your-api-key" }), + * chain: sepolia, + * signer: LocalAccountSigner.privateKeyToAccountSigner(generatePrivateKey()) + * }); + * ``` * * @param {CreateMultiOwnerModularAccountClientParams} config The parameters for creating the multi-owner modular account client * @returns {Promise} A promise that resolves to a `SmartAccountClient` instance with extended plugin actions @@ -97,12 +157,28 @@ export async function createMultiOwnerModularAccountClient({ transport, chain, ...params -}: CreateMultiOwnerModularAccountClientParams): Promise { +}: CreateMultiOwnerModularAccountClientParams): Promise< + SmartAccountClient | AlchemySmartAccountClient +> { const modularAccount = await createMultiOwnerModularAccount({ ...params, transport, chain, }); + if (isAlchemyTransport(transport, chain)) { + const { opts } = params; + + return createAlchemySmartAccountClient({ + ...params, + account: modularAccount, + transport, + chain, + opts, + }) + .extend(multiOwnerPluginActions) + .extend(pluginManagerActions) + .extend(accountLoupeActions); + } return createSmartAccountClient({ ...params, @@ -115,6 +191,21 @@ export async function createMultiOwnerModularAccountClient({ .extend(accountLoupeActions); } +export function createMultisigModularAccountClient< + TSigner extends SmartAccountSigner = SmartAccountSigner +>( + params: AlchemyMultisigAccountClientConfig +): Promise< + AlchemySmartAccountClient< + Chain | undefined, + MultisigModularAccount, + MultisigPluginActions> & + PluginManagerActions> & + AccountLoupeActions>, + MultisigUserOperationContext + > +>; + export function createMultisigModularAccountClient< TChain extends Chain | undefined = Chain | undefined, TSigner extends SmartAccountSigner = SmartAccountSigner @@ -152,6 +243,21 @@ export function createMultisigModularAccountClient< * threshold: 2, // 2 of N signatures * }); * ``` + * @example + * ```ts + * import { createMultisigModularAccountClient } from "@account-kit/smart-contracts"; + * import { sepolia } from "@account-kit/infra"; + * import { LocalAccountSigner } from "@aa-sdk/core"; + * import { generatePrivateKey } from "viem" + * + * const alchemyAccountClient = await createMultisigModularAccountClient({ + * transport: alchemy({ apiKey: "your-api-key" }), + * chain: sepolia, + * signer: LocalAccountSigner.privateKeyToAccountSigner(generatePrivateKey()), + * owners: [...], // other owners on the account + * threshold: 2, // 2 of N signatures + * }); + * ``` * * @param {CreateMultisigModularAccountClientParams} config the parameters for configuring the multisig modular account client * @returns {Promise, {}, SmartAccountClientRpcSchema, MultisigUserOperationContext>>} a promise that resolves to a `SmartAccountClient` object extended with the multisig modular account and additional actions @@ -161,20 +267,49 @@ export async function createMultisigModularAccountClient({ chain, ...params }: CreateMultisigModularAccountClientParams): Promise< - SmartAccountClient< - Transport, - Chain, - MultisigModularAccount, - {}, - SmartAccountClientRpcSchema, - MultisigUserOperationContext - > + | SmartAccountClient< + Transport, + Chain, + MultisigModularAccount, + {}, + SmartAccountClientRpcSchema, + MultisigUserOperationContext + > + | AlchemySmartAccountClient< + Chain | undefined, + MultisigModularAccount, + MultisigPluginActions> & + PluginManagerActions> & + AccountLoupeActions>, + MultisigUserOperationContext + > > { const modularAccount = await createMultisigModularAccount({ ...params, transport, chain, }); + if (isAlchemyTransport(transport, chain)) { + // Need to fit the type into this since the previous multiSigAlchemyClient had it at this point, but without an Value as Type should be safe + // And the createAlchemySmartAccountClient signUserOperation could not infer without this + let config: AlchemyMultisigAccountClientConfig = { + ...params, + chain, + transport, + }; + const { opts } = config; + + return createAlchemySmartAccountClient({ + ...config, + account: modularAccount, + opts, + signUserOperation: multisigSignatureMiddleware, + }) + .extend(smartAccountClientActions) + .extend(multisigPluginActions) + .extend(pluginManagerActions) + .extend(accountLoupeActions); + } const client = createSmartAccountClient({ ...params, diff --git a/account-kit/smart-contracts/src/msca/client/multiSigAlchemyClient.ts b/account-kit/smart-contracts/src/msca/client/multiSigAlchemyClient.ts index 96c3cfb465..1914ad2c17 100644 --- a/account-kit/smart-contracts/src/msca/client/multiSigAlchemyClient.ts +++ b/account-kit/smart-contracts/src/msca/client/multiSigAlchemyClient.ts @@ -1,18 +1,11 @@ +import { type SmartAccountSigner } from "@aa-sdk/core"; import { - smartAccountClientActions, - type SmartAccountSigner, -} from "@aa-sdk/core"; -import { - createAlchemySmartAccountClient, type AlchemySmartAccountClient, type AlchemySmartAccountClientConfig, + type AlchemyTransport, } from "@account-kit/infra"; import { - accountLoupeActions, - createMultisigModularAccount, - multisigPluginActions, - multisigSignatureMiddleware, - pluginManagerActions, + createMultisigModularAccountClient, type AccountLoupeActions, type CreateMultisigModularAccountParams, type LightAccount, @@ -38,7 +31,7 @@ export type AlchemyMultisigAccountClientConfig< MultisigUserOperationContext >, "account" - >; + > & { transport: AlchemyTransport }; export function createMultisigAccountAlchemyClient< TSigner extends SmartAccountSigner = SmartAccountSigner @@ -74,6 +67,7 @@ export function createMultisigAccountAlchemyClient< * }); * ``` * + * @deprecated Use createModularAccountClient instead of this function, we are switching based on the transport * @param {AlchemyMultisigAccountClientConfig} config The configuration for the Alchemy multisig account client * @returns {Promise, MultisigPluginActions> & PluginManagerActions> & AccountLoupeActions>, MultisigUserOperationContext>>} A promise that resolves to an Alchemy Smart Account Client for multisig accounts with extended functionalities. */ @@ -89,22 +83,5 @@ export async function createMultisigAccountAlchemyClient( MultisigUserOperationContext > > { - const { transport, opts, chain } = config; - - const account = await createMultisigModularAccount({ - ...config, - transport, - chain, - }); - - return createAlchemySmartAccountClient({ - ...config, - account, - opts, - signUserOperation: multisigSignatureMiddleware, - }) - .extend(smartAccountClientActions) - .extend(multisigPluginActions) - .extend(pluginManagerActions) - .extend(accountLoupeActions); + return createMultisigModularAccountClient(config); } diff --git a/package.json b/package.json index f2d077d767..6731d72f40 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "docs:gen": "turbo run docs:gen", "test": "vitest dev", "test:ci": "vitest run", - "test:typecheck": "TYPECHECK=true vitest --typecheck --typecheck.only ", + "test:typecheck": "TYPECHECK=true vitest --typecheck --typecheck.only run", "lint:write": "eslint . --fix && yarn docs:gen && prettier --loglevel warn --write --ignore-unknown .", "lint:check": "eslint . && prettier --check .", "prepare": "husky install && yarn turbo prepare", diff --git a/site/pages/reference/account-kit/infra/functions/isAlchemyTransport.mdx b/site/pages/reference/account-kit/infra/functions/isAlchemyTransport.mdx new file mode 100644 index 0000000000..3e60873e3c --- /dev/null +++ b/site/pages/reference/account-kit/infra/functions/isAlchemyTransport.mdx @@ -0,0 +1,34 @@ +--- +# This file is autogenerated +title: isAlchemyTransport +description: Overview of the isAlchemyTransport method +--- + +# isAlchemyTransport + +A type guard for the transport to determine if it is an Alchemy transport. +Used in cases where we would like to do switching depending on the transport, where there used +to be two clients for a alchemy and a non alchemy, and with this switch we don't need the two seperate clients. \* + +## Import + +```ts +import { isAlchemyTransport } from "@account-kit/infra"; +``` + +## Parameters + +### transport + +`Transport` +The transport to check + +### chain + +`Chain` +Chain for the transport to run its function to return the transport config + +## Returns + +`boolean` +`true` if the transport is an Alchemy transport, otherwise `false` diff --git a/site/pages/reference/account-kit/smart-contracts/functions/createMultiOwnerLightAccountClient.mdx b/site/pages/reference/account-kit/smart-contracts/functions/createMultiOwnerLightAccountClient.mdx index a04c44cda3..afdf2d1c40 100644 --- a/site/pages/reference/account-kit/smart-contracts/functions/createMultiOwnerLightAccountClient.mdx +++ b/site/pages/reference/account-kit/smart-contracts/functions/createMultiOwnerLightAccountClient.mdx @@ -34,8 +34,8 @@ const account = await createMultiOwnerLightAccountClient({ ### params -`CreateMultiOwnerLightAccountClientParams` -the configuration for creating the multi-owner light account client +`CreateMultiOwnerLightAccountClientDynamicTransportParams` +the configuration for creating the multi-owner light / alchemy account client with the provided parameters transport ## Returns diff --git a/site/pages/third-party/paymasters.mdx b/site/pages/third-party/paymasters.mdx index aa89d1e9d3..20617c704e 100644 --- a/site/pages/third-party/paymasters.mdx +++ b/site/pages/third-party/paymasters.mdx @@ -118,15 +118,12 @@ const stackupClient = createClient({ transport: http("https://api.stackup.sh/v1/paymaster/STACKUP_API_KEY"), }); -const alchemyTransport = alchemy({ - // TODO: Replace with your Alchemy API key (https://dashboard.alchemypreview.com/apps) - apiKey: "ALCHEMY_API_KEY", -}); +const alchemyTransport = http("ALCHEMY_RPC_URL"); const alchemyClient = await createMultiOwnerModularAccountClient({ chain, signer, - transport: alchemyTransport, + transport: http("ALCHEMY_RPC_URL"), // Bypasses alchemy gas estimation and instead uses Stackup for gas estimation gasEstimator: async (userOp) => ({ ...userOp, diff --git a/site/sidebar/reference/aa-sdk/core.ts b/site/sidebar/reference/aa-sdk/core.ts index 26adf0f0e7..dec87e6814 100644 --- a/site/sidebar/reference/aa-sdk/core.ts +++ b/site/sidebar/reference/aa-sdk/core.ts @@ -232,6 +232,15 @@ export const aaSdkCoreReferenceSidebar: SidebarItem[] = [ }, ], }, + { + text: "EntityIdOverrideError", + items: [ + { + text: "constructor", + link: "/reference/aa-sdk/core/classes/EntityIdOverrideError/constructor", + }, + ], + }, { text: "EntryPointNotFoundError", items: [ @@ -286,6 +295,15 @@ export const aaSdkCoreReferenceSidebar: SidebarItem[] = [ }, ], }, + { + text: "InvalidEntityIdError", + items: [ + { + text: "constructor", + link: "/reference/aa-sdk/core/classes/InvalidEntityIdError/constructor", + }, + ], + }, { text: "InvalidEntryPointError", items: [ @@ -295,6 +313,15 @@ export const aaSdkCoreReferenceSidebar: SidebarItem[] = [ }, ], }, + { + text: "InvalidNonceKeyError", + items: [ + { + text: "constructor", + link: "/reference/aa-sdk/core/classes/InvalidNonceKeyError/constructor", + }, + ], + }, { text: "InvalidRpcUrlError", items: [ diff --git a/site/sidebar/reference/account-kit/infra.ts b/site/sidebar/reference/account-kit/infra.ts index ebfae00503..cdee18d72f 100644 --- a/site/sidebar/reference/account-kit/infra.ts +++ b/site/sidebar/reference/account-kit/infra.ts @@ -62,6 +62,10 @@ export const accountKitInfraReferenceSidebar: SidebarItem[] = [ text: "isAlchemySmartAccountClient", link: "/reference/account-kit/infra/functions/isAlchemySmartAccountClient", }, + { + text: "isAlchemyTransport", + link: "/reference/account-kit/infra/functions/isAlchemyTransport", + }, { text: "simulateUserOperationChanges", link: "/reference/account-kit/infra/functions/simulateUserOperationChanges",