Skip to content

Commit

Permalink
feat: add multi-chain config
Browse files Browse the repository at this point in the history
  • Loading branch information
jstinhw committed May 9, 2024
1 parent 17eca5c commit 151e77a
Show file tree
Hide file tree
Showing 12 changed files with 151 additions and 56 deletions.
Binary file modified bun.lockb
Binary file not shown.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
"@zerodev/defi": "0.0.8-alpha.8",
"@zerodev/ecdsa-validator": "^5.2.3",
"@zerodev/permissions": "^5.2.5",
"@zerodev/sdk": "^5.2.5",
"@zerodev/sdk": "^5.2.11",
"@zerodev/session-key": "^5.2.2",
"@zerodev/waas": "0.1.6",
"@zerodev/waas": "0.1.11-alpha.0",
"encoding": "^0.1.13",
"next": "14.1.4",
"permissionless": "^0.1.16",
Expand Down
6 changes: 3 additions & 3 deletions src/components/Button/CreateCustomizedKernelButton.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ZERODEV_BUNDLER_URL, ZERODEV_PAYMASTER_URL } from "@/utils/constants";
import { getBundler, getPaymaster } from "@/utils/constants";
import { Button } from "@mantine/core";
import { signerToEcdsaValidator } from "@zerodev/ecdsa-validator";
import {
Expand Down Expand Up @@ -49,14 +49,14 @@ export function CreateCustomizedKernelButton() {
const kernelClient = createKernelAccountClient({
account: kernelAccount,
chain: chain,
bundlerTransport: http(`${ZERODEV_BUNDLER_URL}`),
bundlerTransport: http(getBundler(chain.id)),
entryPoint: entryPoint,
middleware: {
sponsorUserOperation: async ({ userOperation }) => {
const kernelPaymaster = createZeroDevPaymasterClient({
entryPoint: entryPoint,
chain: chain,
transport: http(`${ZERODEV_PAYMASTER_URL}`),
transport: http(getPaymaster(chain.id)),
});
return kernelPaymaster.sponsorUserOperation({
userOperation,
Expand Down
68 changes: 68 additions & 0 deletions src/components/Button/SelectChainButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { Button, Flex, Menu } from "@mantine/core";
import { useChainId, useChains, useSwitchChain } from "@zerodev/waas";
import { useState } from "react";

export const CustomChevronDown = () => (
<svg fill="none" height="7" width="14" xmlns="http://www.w3.org/2000/svg">
<path
d="M12.75 1.54001L8.51647 5.0038C7.77974 5.60658 6.72026 5.60658 5.98352 5.0038L1.75 1.54001"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.3"
xmlns="http://www.w3.org/2000/svg"
></path>
</svg>
);

export function SelectChainButton() {
const chainId = useChainId();
const chains = useChains();
const [chainSwitching, setChainSwitching] = useState();
const { switchChain, isPending } = useSwitchChain();

return (
<Menu>
<Menu.Target>
<Button miw={78} px="12px">
<Flex gap="sm" align="center" mah={24} pr="2px">
<div
style={{
display: "block",
}}
>
{chains.filter((c) => c.id === chainId)[0].name}
</div>
<Flex miw={14}>
<CustomChevronDown />
</Flex>
</Flex>
</Button>
</Menu.Target>
<Menu.Dropdown>
<Flex direction="column" gap={4}>
{chains.map((chn: any, idx: number) => {
const isSelected = chainId === chn.id;
return (
<Button
loading={isPending && chainSwitching === chn.id}
key={idx}
onClick={() => {
setChainSwitching(chn.id);
switchChain({ chainId: chn.id });
}}
disabled={isSelected}
>
<Flex w="100%" justify="space-between" align="center">
<Flex align="center" gap="xs">
<Flex>{chn.name}</Flex>
</Flex>
</Flex>
</Button>
);
})}
</Flex>
</Menu.Dropdown>
</Menu>
);
}
2 changes: 2 additions & 0 deletions src/components/Button/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ export { ParallelMintButton } from "./ParallelMintButton";
export { OnboardingButton } from "./OnboardingButton";

export { WithdrawAllButton } from "./WithdrawAllButton";

export { SelectChainButton } from "./SelectChainButton";
43 changes: 19 additions & 24 deletions src/components/Modal/SessionModal.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Button, Loader, Modal } from "@mantine/core";
import { Button, Modal } from "@mantine/core";
import { type Policy } from "@zerodev/permissions";
import { ParamOperator } from "@zerodev/session-key";
import {
Expand All @@ -7,7 +7,6 @@ import {
useKernelClient,
} from "@zerodev/waas";
import { ENTRYPOINT_ADDRESS_V06 } from "permissionless";
import { useEffect, useState } from "react";
import { parseAbi } from "viem";

export interface SessionModalProps {
Expand All @@ -20,14 +19,13 @@ interface CreateBasicSessionModalProps

function CreateSessionModal({ onClose, open, policies }: SessionModalProps) {
const titleId = "Session";
const [isLoading, setIsLoading] = useState(false);
const { kernelAccount } = useKernelClient();
const { write, data, error } = useCreateSession();

useEffect(() => {
if (data) onClose();
setIsLoading(false);
}, [data, error, onClose]);
const { write, isPending } = useCreateSession({
mutation: {
onSuccess: () => {
onClose();
},
},
});

return (
<Modal
Expand All @@ -41,17 +39,16 @@ function CreateSessionModal({ onClose, open, policies }: SessionModalProps) {
<h1>Permission Approval</h1>
<Button
variant="outline"
disabled={isLoading || !write || !kernelAccount}
loading={isPending}
disabled={!write}
onClick={() => {
setIsLoading(true);
write({
policies,
});
}}
>
Approve
</Button>
{isLoading && <Loader />}
</div>
</Modal>
);
Expand All @@ -62,20 +59,20 @@ function CreateBasicSessionModal({
open,
}: CreateBasicSessionModalProps) {
const titleId = "Session";
const [isLoading, setIsLoading] = useState(false);
const { address } = useKernelClient();
const { write, data, error } = useCreateBasicSession();
const { write, data, error, isPending } = useCreateBasicSession({
mutation: {
onSuccess: () => {
onClose();
},
},
});

const contractAddress = "0x3870419Ba2BBf0127060bCB37f69A1b1C090992B";
const contractABI = parseAbi([
"function mint(address _to, uint256 amount) public",
]);

useEffect(() => {
if (data) onClose();
setIsLoading(false);
}, [data, error, onClose]);

return (
<Modal
opened={open}
Expand All @@ -88,10 +85,9 @@ function CreateBasicSessionModal({
<h1>Permission Approval</h1>
<Button
variant="outline"
disabled={isLoading || !write || !address}
loading={isPending}
disabled={!write || !address}
onClick={() => {
setIsLoading(true);

write?.({
permissions: [
{
Expand Down Expand Up @@ -124,7 +120,6 @@ function CreateBasicSessionModal({
>
Approve
</Button>
{isLoading && <Loader />}
</div>
</Modal>
);
Expand Down
9 changes: 8 additions & 1 deletion src/components/Navbar.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
"use client";
import { Flex } from "@mantine/core";
import { useKernelClient } from "@zerodev/waas";
import { ConnectButton, OnboardingButton, PaymasterButton } from "./Button";
import {
ConnectButton,
OnboardingButton,
PaymasterButton,
SelectChainButton,
} from "./Button";

export default function Navbar() {
const { isConnected } = useKernelClient();
Expand All @@ -19,6 +25,7 @@ export default function Navbar() {
<>
<OnboardingButton />
<PaymasterButton />
<SelectChainButton />
<ConnectButton version="v3" />
</>
)}
Expand Down
38 changes: 18 additions & 20 deletions src/components/Provider/Providers.tsx
Original file line number Diff line number Diff line change
@@ -1,45 +1,43 @@
"use client";
import { ZERODEV_APP_ID, ZERODEV_BUNDLER_URL } from "@/utils/constants";
import { ZERODEV_ARB_APP_ID, getBundler } from "@/utils/constants";
import { MantineProvider } from "@mantine/core";
import "@mantine/core/styles.css";
import { Notifications } from "@mantine/notifications";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ZeroDevProvider } from "@zerodev/waas";
import { ZeroDevProvider, createConfig as createZdConfig } from "@zerodev/waas";
import { ReactNode } from "react";
import { WagmiProvider, createConfig, http } from "wagmi";
import {
arbitrum,
base,
mainnet,
optimism,
polygon,
sepolia,
} from "wagmi/chains";
import { injected } from "wagmi/connectors";
import { arbitrum, sepolia } from "wagmi/chains";
import { ModalProvider } from "./ModalProvider";
import { PaymasterProvider } from "./PaymasterProvider";

export default function Providers({ children }: { children: ReactNode }) {
const config = createConfig({
chains: [sepolia, polygon, arbitrum, optimism, base, mainnet],
connectors: [injected()],
chains: [sepolia, arbitrum],
transports: {
[mainnet.id]: http(),
[sepolia.id]: http(),
[polygon.id]: http(),
[arbitrum.id]: http(ZERODEV_BUNDLER_URL),
[optimism.id]: http(),
[base.id]: http(),
[sepolia.id]: http(getBundler(sepolia.id)),
[arbitrum.id]: http(getBundler(arbitrum.id)),
},
});
const queryClient = new QueryClient();
const zdConfig = createZdConfig({
chains: [arbitrum, sepolia],
projectIds: {
[arbitrum.id]: process.env.NEXT_PUBLIC_ZERODEV_APP_ARBITRUM_ID || "",
[sepolia.id]: process.env.NEXT_PUBLIC_ZERODEV_APP_SEPOLIA_ID || "",
},
});

return (
<MantineProvider>
<Notifications />
<WagmiProvider config={config}>
<QueryClientProvider client={queryClient}>
<ZeroDevProvider appId={ZERODEV_APP_ID} chain={arbitrum}>
<ZeroDevProvider
appId={ZERODEV_ARB_APP_ID}
chain={arbitrum}
config={zdConfig}
>
<PaymasterProvider>
<ModalProvider>{children}</ModalProvider>
</PaymasterProvider>
Expand Down
4 changes: 2 additions & 2 deletions src/components/SessionBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ function SessionInfo({ sessionId }: { sessionId: `0x${string}` }) {
const abi = parseAbi(["function mint(address _to, uint256 amount) public"]);
const { paymasterConfig } = usePaymasterConfig({ sessionId });

const { data, write, isDisabled, isPending, error } =
const { data, write, isPending, error, isLoading } =
useSendUserOperationWithSession({
sessionId,
paymaster: paymasterConfig,
Expand All @@ -37,7 +37,7 @@ function SessionInfo({ sessionId }: { sessionId: `0x${string}` }) {
{sessionId && <p>{`Permission ID: ${sessionId}`}</p>}
<Button
variant="outline"
disabled={isDisabled}
disabled={isLoading}
loading={isPending}
onClick={() => {
write([
Expand Down
6 changes: 4 additions & 2 deletions src/components/SmartAccountBlock.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use client";
import { WithdrawAllButton } from "@/components/Button";
import { usePaymasterConfig } from "@/hooks";
import { useModal, usePaymasterConfig } from "@/hooks";
import { Button, Title } from "@mantine/core";
import { notifications } from "@mantine/notifications";
import {
Expand All @@ -12,6 +12,7 @@ import { useEffect } from "react";
import { parseAbi } from "viem";

export default function SmartAccountBlock() {
useModal();
const { address } = useKernelClient();
const { paymasterConfig } = usePaymasterConfig();

Expand All @@ -20,6 +21,7 @@ export default function SmartAccountBlock() {
write,
error,
isPending,
isLoading,
} = useSendUserOperation({
paymaster: paymasterConfig,
});
Expand Down Expand Up @@ -49,7 +51,7 @@ export default function SmartAccountBlock() {
<div className="flex flex-row justify-center items-center space-x-4 mt-4">
<Button
variant="outline"
disabled={isPending}
disabled={isLoading}
loading={isPending}
onClick={() => {
write([
Expand Down
6 changes: 4 additions & 2 deletions src/hooks/useMockPolicy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@ export function useMockPolicy() {
const sudoPolicy = toSudoPolicy({});
const firstPolicies = {
maxGasAllowedInWei: gasPolicyMeta[0],
policy: [firstGasPolicy, sudoPolicy],
policy: [sudoPolicy],
// policy: [firstGasPolicy, sudoPolicy],
};
const secondPolicies = {
maxGasAllowedInWei: gasPolicyMeta[1],
policy: [secondGasPolicy, sudoPolicy],
policy: [sudoPolicy],
// policy: [secondGasPolicy, sudoPolicy],
};

setPolicies([firstPolicies, secondPolicies]);
Expand Down
21 changes: 21 additions & 0 deletions src/utils/constants.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,26 @@
export const ZERODEV_APP_ID = process.env.NEXT_PUBLIC_ZERODEV_APP_ID || "";

export const ZERODEV_ARB_APP_ID =
process.env.NEXT_PUBLIC_ZERODEV_APP_ARBITRUM_ID || "";

export const ZERODEV_SEP_APP_ID =
process.env.NEXT_PUBLIC_ZERODEV_APP_SEPOLIA_ID || "";

export const ZERODEV_BUNDLER_URL = `https://rpc.zerodev.app/api/v2/bundler/${ZERODEV_APP_ID}`;

export const ZERODEV_PAYMASTER_URL = `https://rpc.zerodev.app/api/v2/paymaster/${ZERODEV_APP_ID}`;

export const getBundler = (chainId: number) => {
if (chainId === 42161) {
return `https://rpc.zerodev.app/api/v2/bundler/${ZERODEV_ARB_APP_ID}`;
} else return `https://rpc.zerodev.app/api/v2/bundler/${ZERODEV_SEP_APP_ID}`;
};

export const getPaymaster = (chainId: number) => {
if (chainId === 42161) {
return `https://rpc.zerodev.app/api/v2/paymaster/${ZERODEV_ARB_APP_ID}`;
} else if (chainId === 11155111) {
return `https://rpc.zerodev.app/api/v2/paymaster/${ZERODEV_SEP_APP_ID}`;
}
return "";
};

0 comments on commit 151e77a

Please sign in to comment.