diff --git a/aa-sdk/core/src/utils/index.ts b/aa-sdk/core/src/utils/index.ts index b1bbbc73b1..7157c0d2db 100644 --- a/aa-sdk/core/src/utils/index.ts +++ b/aa-sdk/core/src/utils/index.ts @@ -23,6 +23,11 @@ export type Deferrable = { [K in keyof T]: PromiseOrValue; }; +/** + * Used to ensure type doesn't extend another, for use in & chaining of properties + */ +export type NotType = A extends B ? never : unknown; + /** * Await all of the properties of a Deferrable object * 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 b28be01efa..e4ee1b1768 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 @@ -12,7 +12,6 @@ import { } from "@account-kit/infra"; 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", () => { 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 af83979ab2..032a8ee187 100644 --- a/account-kit/smart-contracts/src/light-account/clients/client.ts +++ b/account-kit/smart-contracts/src/light-account/clients/client.ts @@ -1,5 +1,6 @@ import { createSmartAccountClient, + type NotType, type SmartAccountClient, type SmartAccountClientActions, type SmartAccountClientConfig, @@ -55,7 +56,8 @@ export function createLightAccountClient< TSigner extends SmartAccountSigner = SmartAccountSigner, TTransport extends Transport = Transport >( - args: CreateLightAccountClientParams + args: CreateLightAccountClientParams & + NotType ): Promise< SmartAccountClient< CustomTransport, 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 93ca19dda4..5c7185a55c 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 @@ -12,7 +12,6 @@ import { } from "@account-kit/infra"; 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", () => { 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 1da98a1597..7fc383456c 100644 --- a/account-kit/smart-contracts/src/light-account/clients/multiOwnerLightAccount.ts +++ b/account-kit/smart-contracts/src/light-account/clients/multiOwnerLightAccount.ts @@ -1,5 +1,6 @@ import { createSmartAccountClient, + type NotType, type SmartAccountClient, type SmartAccountClientActions, type SmartAccountClientConfig, @@ -66,10 +67,12 @@ export async function createMultiOwnerLightAccountClient< >; export function createMultiOwnerLightAccountClient< + TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TSigner extends SmartAccountSigner = SmartAccountSigner >( - args: CreateMultiOwnerLightAccountClientParams + args: CreateMultiOwnerLightAccountClientParams & + NotType ): Promise< SmartAccountClient< CustomTransport, diff --git a/account-kit/smart-contracts/src/ma-v2/client/client.test-d.ts b/account-kit/smart-contracts/src/ma-v2/client/client.test-d.ts new file mode 100644 index 0000000000..88fe11a7b6 --- /dev/null +++ b/account-kit/smart-contracts/src/ma-v2/client/client.test-d.ts @@ -0,0 +1,62 @@ +import { + erc7677Middleware, + LocalAccountSigner, + type SmartAccountSigner, +} from "@aa-sdk/core"; +import { custom } from "viem"; +import { createSMAV2AccountClient } from "@account-kit/smart-contracts/experimental"; +import { local070Instance } from "~test/instances.js"; +import { accounts } from "~test/constants.js"; +import { alchemy } from "@account-kit/infra"; + +// TODO: Include a snapshot to reset to in afterEach. +describe("MA v2 Tests: Types", async () => { + const instance = local070Instance; + + const signer: SmartAccountSigner = new LocalAccountSigner( + accounts.fundedAccountOwner + ); + + it("alchemy client instantiated can specify policy id but not for others ", async () => { + createSMAV2AccountClient({ + chain: instance.chain, + signer, + transport: alchemy({ apiKey: "AN_API_KEY" }), + policyId: "test-policy-id", + }); + // @ts-expect-error // A custom should not be able to specify an policy id + createSMAV2AccountClient({ + chain: instance.chain, + signer, + transport: custom(instance.getClient()), + policyId: "test-policy-id", + }); + }); + + it("alchemy client instantiated cannot specify paymaster", async () => { + const { paymasterAndData } = erc7677Middleware(); + createSMAV2AccountClient({ + chain: instance.chain, + signer, + transport: alchemy({ apiKey: "AN_API_KEY" }), + }); + // @ts-expect-error Should not be able to pass paymasterAndData + createSMAV2AccountClient({ + chain: instance.chain, + signer, + transport: alchemy({ apiKey: "AN_API_KEY" }), + paymasterAndData, + }); + createSMAV2AccountClient({ + chain: instance.chain, + signer, + transport: custom(instance.getClient()), + }); + createSMAV2AccountClient({ + chain: instance.chain, + signer, + transport: custom(instance.getClient()), + paymasterAndData, + }); + }); +}); diff --git a/account-kit/smart-contracts/src/ma-v2/client/client.test.ts b/account-kit/smart-contracts/src/ma-v2/client/client.test.ts index d98a23e652..1d0a5780cb 100644 --- a/account-kit/smart-contracts/src/ma-v2/client/client.test.ts +++ b/account-kit/smart-contracts/src/ma-v2/client/client.test.ts @@ -1,3 +1,5 @@ +import * as AAInfraModule from "@account-kit/infra"; +import * as AACoreModule from "@aa-sdk/core"; import { erc7677Middleware, LocalAccountSigner, @@ -32,10 +34,12 @@ import { local070Instance } from "~test/instances.js"; import { setBalance } from "viem/actions"; import { accounts } from "~test/constants.js"; import { paymaster070 } from "~test/paymaster/paymaster070.js"; +import { alchemy, arbitrumSepolia } from "@account-kit/infra"; // TODO: Include a snapshot to reset to in afterEach. describe("MA v2 Tests", async () => { const instance = local070Instance; + let client: ReturnType & ReturnType; @@ -214,7 +218,7 @@ describe("MA v2 Tests", async () => { }, contents: "Hello, Bob!", }, - }; + } as const; const hashedMessageTypedData = hashTypedData(typedData); let signature = await provider.signTypedData({ typedData }); @@ -860,4 +864,42 @@ describe("MA v2 Tests", async () => { transport: custom(instance.getClient()), ...(usePaymaster ? erc7677Middleware() : {}), }); + + it("alchemy client calls the createAlchmeySmartAccountClient", async () => { + const alchemyClientSpy = vi + .spyOn(AAInfraModule, "createAlchemySmartAccountClient") + .mockImplementation(() => "fakedAlchemy" as any); + const notAlcmeyClientSpy = vi + .spyOn(AACoreModule, "createSmartAccountClient") + .mockImplementation(() => "faked" as any); + expect( + await createSMAV2AccountClient({ + chain: arbitrumSepolia, + signer, + transport: alchemy({ jwt: "AN_API_KEY" }), + accountAddress: "0x86f3B0211764971Ad0Fc8C8898d31f5d792faD84", + }) + ).toMatch("fakedAlchemy"); + + expect(alchemyClientSpy).toHaveBeenCalled(); + expect(notAlcmeyClientSpy).not.toHaveBeenCalled(); + }); + it("custom client calls the createAlchmeySmartAccountClient", async () => { + const alchemyClientSpy = vi + .spyOn(AAInfraModule, "createAlchemySmartAccountClient") + .mockImplementation(() => "fakedAlchemy" as any); + const notAlcmeyClientSpy = vi + .spyOn(AACoreModule, "createSmartAccountClient") + .mockImplementation(() => "faked" as any); + expect( + await createSMAV2AccountClient({ + chain: instance.chain, + signer, + transport: custom(instance.getClient()), + }) + ).toMatch("faked"); + + expect(alchemyClientSpy).not.toHaveBeenCalled(); + expect(notAlcmeyClientSpy).toHaveBeenCalled(); + }); }); diff --git a/account-kit/smart-contracts/src/ma-v2/client/client.ts b/account-kit/smart-contracts/src/ma-v2/client/client.ts index 58bf4f3dc6..38727fb6e3 100644 --- a/account-kit/smart-contracts/src/ma-v2/client/client.ts +++ b/account-kit/smart-contracts/src/ma-v2/client/client.ts @@ -1,8 +1,9 @@ import { - createSmartAccountClient, type SmartAccountClient, type SmartAccountSigner, type SmartAccountClientConfig, + type NotType, + createSmartAccountClient, } from "@aa-sdk/core"; import { type Chain, type Transport } from "viem"; @@ -11,10 +12,18 @@ import { type CreateSMAV2AccountParams, type MAV2Account, } from "../account/semiModularAccountV2.js"; - +import { + createAlchemySmartAccountClient, + isAlchemyTransport, + type AlchemySmartAccountClientConfig, + type AlchemyTransport, +} from "@account-kit/infra"; +import type { LightAccount } from "../../light-account/accounts/account.js"; export type SMAV2AccountClient< - TSigner extends SmartAccountSigner = SmartAccountSigner -> = SmartAccountClient>; + TSigner extends SmartAccountSigner = SmartAccountSigner, + TChain extends Chain = Chain, + TTransport extends Transport | AlchemyTransport = Transport +> = SmartAccountClient>; export type CreateSMAV2AccountClientParams< TTransport extends Transport = Transport, @@ -25,13 +34,34 @@ export type CreateSMAV2AccountClientParams< SmartAccountClientConfig, "transport" | "account" | "chain" >; +export type CreateSMAV2AlchemyAccountClientParams< + TTransport extends Transport = Transport, + TChain extends Chain = Chain, + TSigner extends SmartAccountSigner = SmartAccountSigner +> = Omit< + CreateSMAV2AccountClientParams, + "transport" +> & + Omit< + AlchemySmartAccountClientConfig>, + "account" + > & { paymasterAndData?: never; dummyPaymasterAndData?: never }; export function createSMAV2AccountClient< TChain extends Chain = Chain, TSigner extends SmartAccountSigner = SmartAccountSigner >( - args: CreateSMAV2AccountClientParams -): Promise>; + args: CreateSMAV2AlchemyAccountClientParams +): Promise>; + +export function createSMAV2AccountClient< + TTransport extends Transport = Transport, + TChain extends Chain = Chain, + TSigner extends SmartAccountSigner = SmartAccountSigner +>( + args: CreateSMAV2AccountClientParams & + NotType +): Promise>; /** * Creates a SMAv2 account client using the provided configuration parameters. @@ -65,7 +95,20 @@ export function createSMAV2AccountClient< export async function createSMAV2AccountClient( config: CreateSMAV2AccountClientParams ): Promise { - const smaV2Account = await createSMAV2Account(config); + const { transport, chain } = config; + const smaV2Account = await createSMAV2Account({ + ...config, + transport, + chain, + }); + if (isAlchemyTransport(transport, chain)) { + return createAlchemySmartAccountClient({ + ...config, + transport, + chain, + account: smaV2Account, + }); + } return createSmartAccountClient({ ...config, diff --git a/account-kit/smart-contracts/src/msca/client/client.ts b/account-kit/smart-contracts/src/msca/client/client.ts index 65e61d01b9..12776c0c91 100644 --- a/account-kit/smart-contracts/src/msca/client/client.ts +++ b/account-kit/smart-contracts/src/msca/client/client.ts @@ -1,6 +1,7 @@ import { createSmartAccountClient, smartAccountClientActions, + type NotType, type SmartAccountClient, type SmartAccountClientRpcSchema, type SmartAccountSigner, @@ -104,10 +105,16 @@ export function createMultiOwnerModularAccountClient< >; export function createMultiOwnerModularAccountClient< + TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TSigner extends SmartAccountSigner = SmartAccountSigner >( - args: CreateMultiOwnerModularAccountClientParams + args: CreateMultiOwnerModularAccountClientParams< + TTransport, + TChain, + TSigner + > & + NotType ): Promise< SmartAccountClient< CustomTransport, @@ -207,10 +214,12 @@ export function createMultisigModularAccountClient< >; export function createMultisigModularAccountClient< + TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TSigner extends SmartAccountSigner = SmartAccountSigner >( - args: CreateMultisigModularAccountClientParams + args: CreateMultisigModularAccountClientParams & + NotType ): Promise< SmartAccountClient< CustomTransport,