Skip to content

Commit

Permalink
feat: add zod runtime validation for ethers adapter provider (#188)
Browse files Browse the repository at this point in the history
  • Loading branch information
avasisht23 committed Nov 3, 2023
1 parent 8a7c4fb commit 6bbbc12
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 11 deletions.
25 changes: 25 additions & 0 deletions packages/ethers/src/__tests__/provider-adapter.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import {
SimpleSmartContractAccount,
SmartAccountProvider,
getChain,
getDefaultSimpleAccountFactoryAddress,
} from "@alchemy/aa-core";
import { Wallet } from "@ethersproject/wallet";
import { Alchemy, Network, type AlchemyProvider } from "alchemy-sdk";
import { type Chain } from "viem/chains";
import { EthersProviderAdapter } from "../../src/provider-adapter.js";
import { convertWalletToAccountSigner } from "../utils.js";

Expand All @@ -29,6 +31,29 @@ describe("Simple Account Tests", async () => {
"0xbfe07c95623df55ae939ddf4757563286472ef8c0ebe4b84d5e774a653b7eb67735cb5b63d15bb18510d64a97e6e3001a5f9818f89f2f7f076e559248a7ccf7d1c"
);
});

it("should correctly do runtime validation when entryPoint is invalid", async () => {
expect(
() =>
new EthersProviderAdapter({
accountProvider: new SmartAccountProvider({
rpcProvider: alchemyProvider.connection.url,
chain: 1 as unknown as Chain,
}),
})
).toThrowErrorMatchingInlineSnapshot(`
"[
{
\\"code\\": \\"custom\\",
\\"fatal\\": true,
\\"path\\": [
\\"chain\\"
],
\\"message\\": \\"Invalid input\\"
}
]"
`);
});
});

const givenConnectedProvider = ({
Expand Down
15 changes: 4 additions & 11 deletions packages/ethers/src/provider-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import {
SmartAccountProvider,
getChain,
type AccountMiddlewareFn,
type Address,
type FeeDataMiddleware,
type GasEstimatorMiddleware,
type HttpTransport,
Expand All @@ -13,22 +12,16 @@ import {
import { defineReadOnly } from "@ethersproject/properties";
import { JsonRpcProvider } from "@ethersproject/providers";
import { AccountSigner } from "./account-signer.js";

export type EthersProviderAdapterOpts = { entryPointAddress?: Address } & (
| {
rpcProvider: string | PublicErc4337Client<HttpTransport>;
chainId: number;
}
| {
accountProvider: SmartAccountProvider<HttpTransport>;
}
);
import { EthersProviderAdapterOptsSchema } from "./schema.js";
import type { EthersProviderAdapterOpts } from "./types.js";

/** Lightweight Adapter for SmartAccountProvider to enable Signer Creation */
export class EthersProviderAdapter extends JsonRpcProvider {
readonly accountProvider: SmartAccountProvider<HttpTransport>;

constructor(opts: EthersProviderAdapterOpts) {
EthersProviderAdapterOptsSchema.parse(opts);

super();
if ("accountProvider" in opts) {
this.accountProvider = opts.accountProvider;
Expand Down
27 changes: 27 additions & 0 deletions packages/ethers/src/schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import {
SmartAccountProvider,
createPublicErc4337ClientSchema,
} from "@alchemy/aa-core";
import { Address as zAddress } from "abitype/zod";
import type { HttpTransport } from "viem";
import z from "zod";

export const EthersProviderAdapterOptsSchema = z
.object({
entryPointAddress: zAddress.optional(),
})
.and(
z
.object({
rpcProvider: z.union([
z.string(),
createPublicErc4337ClientSchema<HttpTransport>(),
]),
chainId: z.number(),
})
.or(
z.object({
accountProvider: z.instanceof(SmartAccountProvider<HttpTransport>),
})
)
);
6 changes: 6 additions & 0 deletions packages/ethers/src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { z } from "zod";
import type { EthersProviderAdapterOptsSchema } from "./schema";

export type EthersProviderAdapterOpts = z.infer<
typeof EthersProviderAdapterOptsSchema
>;

0 comments on commit 6bbbc12

Please sign in to comment.