Skip to content

Commit

Permalink
feat: msca plugingen to accept multichain address format
Browse files Browse the repository at this point in the history
  • Loading branch information
denniswon committed Dec 11, 2023
1 parent 76cc55f commit 756e61f
Show file tree
Hide file tree
Showing 12 changed files with 87 additions and 46 deletions.
4 changes: 3 additions & 1 deletion packages/accounts/plugindefs/multi-owner/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { MultiOwnerPluginAbi } from "./abi.js";
export const MultiOwnerPluginGenConfig: PluginGenConfig = {
name: "MultiOwnerPlugin",
abi: MultiOwnerPluginAbi,
address: "0x56bC629F342821FBe91C5273880792dFECBE7920",
address: {
[sepolia.id]: "0x56bC629F342821FBe91C5273880792dFECBE7920",
},
chain: sepolia,
};
5 changes: 3 additions & 2 deletions packages/accounts/plugindefs/types.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import type { Abi, Address, Chain } from "viem";
import type { ContractConfig } from "@wagmi/cli";
import type { Abi, Chain } from "viem";

export type PluginGenConfig = {
abi: Abi;
address: Address;
address: ContractConfig["address"];
chain: Chain;
name: string;
// TODO: need to make this configurable to run in CI without requiring this
Expand Down
49 changes: 37 additions & 12 deletions packages/accounts/scripts/plugingen.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { RequiredBy } from "@alchemy/aa-core";
import type { ConnectionConfig, RequiredBy } from "@alchemy/aa-core";
import { type Plugin } from "@wagmi/cli";
import { camelCase, pascalCase } from "change-case";
import dedent from "dedent";
Expand All @@ -14,10 +14,10 @@ import { IPluginAbi } from "../src/msca/abis/IPlugin.js";

export function plugingen({
chain,
rpcUrl,
connectionConfig,
}: {
chain: Chain;
rpcUrl?: string;
connectionConfig: ConnectionConfig;
}): RequiredBy<Plugin, "run"> {
return {
name: "ERC6900PluginGen: This file is auto-generated by plugingen",
Expand All @@ -28,26 +28,46 @@ export function plugingen({
);
}

// TODO: move this out of here and have the plugin accept the connection params for where
// to pull this data from
const httpUrl =
rpcUrl ?? `${chain.rpcUrls.alchemy.http[0]}/${process.env.API_KEY}`;
const rpcUrl =
connectionConfig.rpcUrl == null
? `${chain.rpcUrls.alchemy.http[0]}/${
connectionConfig.apiKey ?? process.env.API_KEY
}`
: connectionConfig.rpcUrl;

const client = createPublicClient({
chain,
transport: http(httpUrl),
transport: http(rpcUrl, {
fetchOptions: {
headers: {
Authorization: `Bearer ${connectionConfig.jwt}`,
},
},
}),
});

const content: string[] = [];
for (const contract of contracts) {
// This is done to clear out the ABI generated by wagmi
contract.content = "";

if (contract.address == null || typeof contract.address !== "string") {
throw new Error("contract must have an address and only one address");
if (contract.address == null) {
throw new Error("contract must have at least one address");
}

const address =
typeof contract.address === "string"
? { [chain.id]: contract.address }
: contract.address;

if (!(chain.id in address)) {
throw new Error(
`contract address missing for the reference chain ${chain.id}`
);
}

const plugin = getContract({
address: contract.address,
address: address[chain.id],
abi: IPluginAbi,
publicClient: client,
});
Expand Down Expand Up @@ -135,6 +155,11 @@ export function plugingen({
meta: {
name: "${name}",
version: "${version}",
address: {${Object.entries(address).reduce(
(prev, [chainId, addr]) =>
(prev += `${chainId}: "${addr}" as Address, `),
""
)}},
},
accountMethods: (account: IMSCA<any, any>) => ({ ${accountFunctions.join(
",\n\n"
Expand Down Expand Up @@ -163,7 +188,7 @@ export function plugingen({
}

const imports = dedent`
import { type GetFunctionArgs, encodeFunctionData } from "viem";
import { type Address, type GetFunctionArgs, encodeFunctionData } from "viem";
import type { Plugin } from "./types";
import type { IMSCA } from "../builder";
import type { ISmartAccountProvider, SupportedTransports } from "@alchemy/aa-core";
Expand Down
5 changes: 4 additions & 1 deletion packages/accounts/src/msca/plugins/multi-owner.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type GetFunctionArgs, encodeFunctionData } from "viem";
import { type Address, type GetFunctionArgs, encodeFunctionData } from "viem";
import type { Plugin } from "./types";
import type { IMSCA } from "../builder";
import type {
Expand All @@ -14,6 +14,9 @@ const MultiOwnerPlugin_ = {
meta: {
name: "Multi Owner Plugin",
version: "1.0.0",
address: {
11155111: "0x56bC629F342821FBe91C5273880792dFECBE7920" as Address,
},
},
accountMethods: (account: IMSCA<any, any>) => ({
encodeUpdateOwnersData: ({
Expand Down
3 changes: 2 additions & 1 deletion packages/accounts/src/msca/plugins/types.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import type {
Address,
ISmartAccountProvider,
SupportedTransports,
} from "@alchemy/aa-core";
import type { IMSCA } from "../builder";

export interface Plugin<AD, PD> {
meta: { name: string; version: string };
meta: { name: string; version: string; address: Record<number, Address> };
/**
* Decorator functions that can be used to read data from an MSCA contract instance
* These methods can be used on their own or with the `account.extend` method to add them to the account instance
Expand Down
7 changes: 6 additions & 1 deletion packages/accounts/wagmi.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ export default defineConfig(
address: config.address,
},
],
plugins: [plugingen({ chain: config.chain, rpcUrl: config.rpcUrl })],
plugins: [
plugingen({
chain: config.chain,
connectionConfig: { rpcUrl: config.rpcUrl! },
}),
],
}))
);
28 changes: 4 additions & 24 deletions packages/alchemy/src/schema.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,11 @@
import { LightAccountFactoryConfigSchema } from "@alchemy/aa-accounts";
import { createSmartAccountProviderConfigSchema } from "@alchemy/aa-core";
import {
ConnectionConfigSchema,
createSmartAccountProviderConfigSchema,
} from "@alchemy/aa-core";
import { Alchemy } from "alchemy-sdk";
import z from "zod";

export const ConnectionConfigSchema = z.union([
z.object({
rpcUrl: z.never().optional(),
apiKey: z.string(),
jwt: z.never().optional(),
}),
z.object({
rpcUrl: z.never().optional(),
apiKey: z.never().optional(),
jwt: z.string(),
}),
z.object({
rpcUrl: z.string(),
apiKey: z.never().optional(),
jwt: z.never().optional(),
}),
z.object({
rpcUrl: z.string(),
apiKey: z.never().optional(),
jwt: z.string(),
}),
]);

export const AlchemyProviderConfigSchema =
createSmartAccountProviderConfigSchema()
.omit({ rpcProvider: true })
Expand Down
3 changes: 0 additions & 3 deletions packages/alchemy/src/type.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import { z } from "zod";
import type {
AlchemyProviderConfigSchema,
ConnectionConfigSchema,
LightAccountAlchemyProviderConfigSchema,
} from "./schema.js";

export type ConnectionConfig = z.input<typeof ConnectionConfigSchema>;

export type AlchemyProviderConfig = z.input<typeof AlchemyProviderConfigSchema>;

export type LightAccountAlchemyProviderConfig = z.input<
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export {

export { SmartAccountProvider, noOpMiddleware } from "./provider/base.js";
export {
ConnectionConfigSchema,
SmartAccountProviderOptsSchema,
createSmartAccountProviderConfigSchema,
} from "./provider/schema.js";
Expand Down
23 changes: 23 additions & 0 deletions packages/core/src/provider/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,29 @@ import {
PercentageSchema,
} from "../utils/index.js";

export const ConnectionConfigSchema = z.union([
z.object({
rpcUrl: z.never().optional(),
apiKey: z.string(),
jwt: z.never().optional(),
}),
z.object({
rpcUrl: z.never().optional(),
apiKey: z.never().optional(),
jwt: z.string(),
}),
z.object({
rpcUrl: z.string(),
apiKey: z.never().optional(),
jwt: z.never().optional(),
}),
z.object({
rpcUrl: z.string(),
apiKey: z.never().optional(),
jwt: z.string(),
}),
]);

export const UserOperationFeeOptionsFieldSchema =
BigNumberishRangeSchema.merge(PercentageSchema).partial();

Expand Down
3 changes: 3 additions & 0 deletions packages/core/src/provider/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import type {
import type { Deferrable } from "../utils";
import type { IsUndefined, NoUndefined } from "../utils/types.js";
import type {
ConnectionConfigSchema,
SmartAccountProviderOptsSchema,
createSmartAccountProviderConfigSchema,
} from "./schema.js";
Expand All @@ -40,6 +41,8 @@ export type ConnectorData = {
chainId?: Hex;
};

export type ConnectionConfig = z.input<typeof ConnectionConfigSchema>;

export interface ProviderEvents {
chainChanged(chainId: Hex): void;
accountsChanged(accounts: Address[]): void;
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Address, Hash } from "viem";
import { type Address, type Hash } from "viem";
import type { z } from "zod";
import type {
UserOperationFeeOptionsFieldSchema,
Expand Down

0 comments on commit 756e61f

Please sign in to comment.