Skip to content

Commit

Permalink
feat: add split transport (#590)
Browse files Browse the repository at this point in the history
  • Loading branch information
moldy530 committed Apr 22, 2024
1 parent 9b84660 commit 2d3687f
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 32 deletions.
1 change: 1 addition & 0 deletions packages/core/src/index.ts
Expand Up @@ -128,6 +128,7 @@ export {
wrapSignatureWith6492,
} from "./signer/utils.js";
export { WalletClientSigner } from "./signer/wallet-client.js";
export { split, type SplitTransportParams } from "./transport/split.js";
export type * from "./types.js";
export type * from "./utils/index.js";
export {
Expand Down
69 changes: 69 additions & 0 deletions packages/core/src/transport/split.ts
@@ -0,0 +1,69 @@
import { custom, type CustomTransport, type Transport } from "viem";

export interface SplitTransportParams {
overrides: {
methods: string[];
transport: Transport;
}[];
fallback: Transport;
}

/**
* The Split Transport allows you to split RPC traffic for specific methods across
* different RPC providers. This is done by specifying the methods you want handled
* specially as overrides and providing a fallback transport for all other methods.
*
* @example
* ```ts
* import { createPublicClient, http } from "viem";
* import { split } from "@alchemy/aa-core";
*
* const bundlerMethods = [
* "eth_sendUserOperation",
* "eth_estimateUserOperationGas",
* "eth_getUserOperationReceipt",
* "eth_getUserOperationByHash",
* "eth_supportedEntryPoints"
* ];
*
* const clientWithSplit = createPublicClient({
* transport: split({
* overrides: [{
* methods: bundlerMethods,
* transport: http(BUNDLER_RPC_URL)
* }]
* fallback: http(OTHER_RPC_URL)
* }),
* });
* ```
*
* @param params {@link SplitTransportParams} split transport configuration containing the methods overrides and fallback transport
* @returns a {@link CustomTransport} that splits traffic
*/
export const split = (params: SplitTransportParams): CustomTransport => {
const overrideMap = params.overrides.reduce((accum, curr) => {
curr.methods.forEach((method) => {
if (accum.has(method) && accum.get(method) !== curr.transport) {
throw new Error(
"A method cannot be handled by more than one transport"
);
}

accum.set(method, curr.transport);
});

return accum;
}, new Map<string, Transport>());

return (opts) =>
custom({
request: async (args) => {
const transportOverride = overrideMap.get(args.method);
if (transportOverride != null) {
return transportOverride(opts).request(args);
}

return params.fallback(opts).request(args);
},
})(opts);
};
1 change: 1 addition & 0 deletions site/.vitepress/sidebar/packages/aa-core.ts
Expand Up @@ -174,6 +174,7 @@ export const aaCoreSidebar: DefaultTheme.SidebarItem = {
},
],
},
{ text: "Split Transport", link: "/split-transport" },
{
text: "Utils",
base: "/packages/aa-core/utils",
Expand Down
55 changes: 55 additions & 0 deletions site/packages/aa-core/split-transport.md
@@ -0,0 +1,55 @@
---
outline: deep
head:
- - meta
- property: og:title
content: Split Transport
- - meta
- name: description
content: Learn how to use a different RPC provider for your bundler traffic and node traffic
- - meta
- property: og:description
content: Learn how to use a different RPC provider for your bundler traffic and node traffic
next:
text: SmartAccountClient
---

# split

The split transport allows you to provide overrides for specific RPC methods. This is useful, for example, if you want to send bundler traffic to one provider and node traffic to another.

## Import

```ts
import { split } from "@alchemy/aa-core";
```

## Usage

<<< @/snippets/aa-core/splitTransport.ts

## Parameters

```ts
import { type SplitTransportProps } from "@alchemy/aa-core";
```

### overrides

`{transport: Transport, methods: string[]}[]`

The overrides param is an array of objects containing a `transport` param of type `Transport` from viem (eg. `http`) and an array of `methods` that this transport should handle

### fallback

`Transport`

This is the `Transport` to use for all other methods

## Return Type

```ts
import { type CustomTransport } from "viem";
```

Returns a `CustomTransport` that can be passed to any compatible `viem` Client. This includes any `SmartAccountClient` instance.
25 changes: 25 additions & 0 deletions site/snippets/aa-core/splitTransport.ts
@@ -0,0 +1,25 @@
import { createSmartAccountClient, sepolia, split } from "@alchemy/aa-core";
import { http } from "viem";

const bundlerMethods = [
"eth_sendUserOperation",
"eth_estimateUserOperationGas",
"eth_getUserOperationReceipt",
"eth_getUserOperationByHash",
"eth_supportedEntryPoints",
];

const splitTransport = split({
overrides: [
{
methods: bundlerMethods,
transport: http("BUNDLER_RPC_URL"),
},
],
fallback: http("OTHER_RPC_URL"),
});

export const client = createSmartAccountClient({
chain: sepolia,
transport: splitTransport,
});
34 changes: 2 additions & 32 deletions site/third-party/bundlers.md
Expand Up @@ -38,36 +38,6 @@ with your provider on what the correct logic is.

## Splitting Bundler traffic and Node RPC traffic

It might be the case that you want to use a different RPC provider for your bundler traffic and your node traffic. This is a common use case, and you can do this by passing in a custom transport function to your `createSmartAccountClient` call. For example:
It might be the case that you want to use a different RPC provider for your bundler traffic and your node traffic. This is a common use case, and you can do this by leveraging the [`split`](/packages/aa-core/split-transport) transport and passing it to your `createSmartAccountClient` call. For example:

```ts
import { createSmartAccountClient } from "@alchemy/aa-core";
import { sepolia } from "viem";

const chain = sepolia;
const client = createSmartAccountClient({
chain,
transport: (opts) => {
const bundlerRpc = http("BUNDLER_RPC_URL")(opts);
const publicRpc = http("OTHER_RPC_URL")(opts);

return custom({
request: async (args) => {
const bundlerMethods = new Set([
"eth_sendUserOperation",
"eth_estimateUserOperationGas",
"eth_getUserOperationReceipt",
"eth_getUserOperationByHash",
"eth_supportedEntryPoints",
]);

if (bundlerMethods.has(args.method)) {
return bundlerRpc.request(args);
} else {
return publicRpc.request(args);
}
},
})(opts);
},
});
```
<<< @/snippets/aa-core/splitTransport.ts

0 comments on commit 2d3687f

Please sign in to comment.