Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions packages/entrykit/src/EntryKitConfigProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { createContext, useContext, type ReactNode } from "react";
import { RainbowKitProvider, midnightTheme } from "@rainbow-me/rainbowkit";
import { EntryKitConfig } from "./config/output";
import { Chain } from "viem";
import { useChains } from "wagmi";
import { useChains, useClient } from "wagmi";
import { getBundlerTransport } from "./getBundlerTransport";

type ContextValue = EntryKitConfig & {
Expand All @@ -29,7 +29,9 @@ export function EntryKitConfigProvider({ config, children }: Props) {
if (!chain) throw new Error(`Could not find configured chain for chain ID ${config.chainId}.`);

// This throws when no we can't find a bundler to talk to, so use it to validate the chain.
getBundlerTransport(chain);
const client = useClient({ chainId: config.chainId });
if (!client) throw new Error(`Could not get client for chain ID ${config.chainId}.`);
getBundlerTransport(client);

return (
<RainbowKitProvider
Expand Down
5 changes: 4 additions & 1 deletion packages/entrykit/src/createWagmiConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { Chain, Transport } from "viem";
import { connectorsForWallets } from "@rainbow-me/rainbowkit";
import { Config, CreateConfigParameters, createConfig } from "wagmi";
import { getWallets } from "./getWallets";
import { mapObject } from "@latticexyz/common/utils";
import { wiresaw } from "./quarry/transports/wiresaw";

export type CreateWagmiConfigOptions<
chains extends readonly [Chain, ...Chain[]] = readonly [Chain, ...Chain[]],
Expand All @@ -27,11 +29,12 @@ export function createWagmiConfig<
appName: config.appName,
projectId: config.walletConnectProjectId,
});
const transports = mapObject(config.transports, (transport) => wiresaw(transport));

return createConfig({
connectors,
chains: config.chains,
transports: config.transports,
transports,
pollingInterval: config.pollingInterval,
}) as never;
}
53 changes: 45 additions & 8 deletions packages/entrykit/src/getBundlerTransport.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,62 @@
import { transactionQueue } from "@latticexyz/common/actions";
import { Chain, createClient, fallback, http, keccak256, stringToHex, webSocket } from "viem";
import { Chain, Client, Transport, createClient, http, keccak256, stringToHex } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { userOpExecutor } from "./quarry/transports/userOpExecutor";
import { wiresaw } from "./quarry/transports/wiresaw";

export function getBundlerTransport(chain: Chain) {
const bundlerHttpUrl = chain.rpcUrls.bundler?.http[0];
export function getBundlerTransport(client: Client<Transport, Chain>) {
const bundlerHttpUrl = client.chain.rpcUrls.bundler?.http[0];
// TODO: bundler websocket
// TODO: do chain checks/conditionals inside the transports
const bundlerTransport = bundlerHttpUrl
? http(bundlerHttpUrl)
: chain.id === 31337
? client.chain.id === 17420
? wiresaw(http(bundlerHttpUrl))
: client.chain.id === 690 || client.chain.id === 17069
? alto(http(bundlerHttpUrl))
: http(bundlerHttpUrl)
: client.chain.id === 31337
? userOpExecutor({
executor: createClient({
chain,
transport: fallback([webSocket(), http()]),
chain: client.chain,
transport: () => ({ config: client.transport, request: client.request }),
account: privateKeyToAccount(keccak256(stringToHex("local user op executor"))),
pollingInterval: 10,
}).extend(transactionQueue()),
})
: null;
if (!bundlerTransport) {
throw new Error(`Chain ${chain.id} config did not include a bundler RPC URL.`);
throw new Error(`Chain ${client.chain.id} config did not include a bundler RPC URL.`);
}
return bundlerTransport;
}

function alto<transport extends Transport>(createTransport: transport): transport {
return ((opts) => {
const transport = createTransport(opts);
const request: typeof transport.request = async (req) => {
if (req.method === "eth_sendUserOperation") {
const { transactionHash, userOpHash } = await transport.request({

Check failure on line 38 in packages/entrykit/src/getBundlerTransport.ts

View workflow job for this annotation

GitHub Actions / Run lint

'transactionHash' is assigned a value but never used. Allowed unused vars must match /^_/u
...req,
method: "pimlico_sendUserOperationNow",
});
return userOpHash;
}

if (req.method === "eth_estimateUserOperationGas") {
try {
return await transport.request(req);
} catch (error) {
// fill in missing error data from alto so viem can parse the error
error.data ??= error.details;
throw error;
}
}

return transport.request(req);
};
return {
...transport,
request,
};
}) as transport;
}
2 changes: 1 addition & 1 deletion packages/entrykit/src/getSessionClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export async function getSessionClient({
}

const bundlerClient = createBundlerClient({
transport: getBundlerTransport(client.chain),
transport: getBundlerTransport(client),
client,
account: sessionAccount,
});
Expand Down
Loading
Loading