Skip to content

Commit 900ac35

Browse files
authored
fix(entrykit): improve fee handling (#3577)
1 parent 3d58450 commit 900ac35

File tree

5 files changed

+43
-30
lines changed

5 files changed

+43
-30
lines changed

.changeset/clean-mugs-admire.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@latticexyz/entrykit": patch
3+
---
4+
5+
Improved fee handling for known chains.
Lines changed: 34 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Transport, Chain, Client, RpcSchema } from "viem";
1+
import { Transport, Chain, Client, RpcSchema, EstimateFeesPerGasReturnType } from "viem";
22
import {
33
BundlerClient,
44
BundlerClientConfig,
@@ -7,31 +7,26 @@ import {
77
} from "viem/account-abstraction";
88
import { defaultClientConfig } from "./common";
99
import { getPaymaster } from "./getPaymaster";
10-
11-
const knownChainFees = new Set([
12-
// anvil hardcodes fee returned by `eth_maxPriorityFeePerGas`
13-
// so we have to override it here
14-
// https://github.com/foundry-rs/foundry/pull/8081#issuecomment-2402002485
15-
31337,
16-
// rhodolite
17-
17420,
18-
// garnet
19-
17069,
20-
// redstone
21-
690,
22-
]);
10+
import { getAction } from "viem/utils";
11+
import { estimateFeesPerGas } from "viem/actions";
2312

2413
export function createBundlerClient<
2514
transport extends Transport,
26-
chain extends Chain | undefined = undefined,
27-
account extends SmartAccount | undefined = undefined,
28-
client extends Client | undefined = undefined,
15+
chain extends Chain = Chain,
16+
account extends SmartAccount = SmartAccount,
17+
client extends Client = Client,
2918
rpcSchema extends RpcSchema | undefined = undefined,
3019
>(
3120
config: BundlerClientConfig<transport, chain, account, client, rpcSchema>,
3221
): BundlerClient<transport, chain, account, client, rpcSchema> {
33-
const chain = config.chain ?? config.client?.chain;
22+
// our generics above enforce this, but `BundlerClientConfig` makes it optional again
23+
const client = config.client;
24+
if (!client) throw new Error("No `client` provided to `createBundlerClient`.");
25+
26+
const chain = config.chain ?? client.chain;
3427
const paymaster = chain ? getPaymaster(chain) : undefined;
28+
29+
// TODO: lift this out to make `createBundlerClient` configurable?
3530
return viem_createBundlerClient({
3631
...defaultClientConfig,
3732
paymaster: paymaster
@@ -42,17 +37,29 @@ export function createBundlerClient<
4237
}),
4338
}
4439
: undefined,
45-
// TODO: figure out why viem isn't falling back to `chain.fees.estimateFeesPerGas` when this isn't set
4640
userOperation: {
47-
estimateFeesPerGas:
48-
// TODO: move this to gas estimator transport?
49-
chain && knownChainFees.has(chain.id)
50-
? async () => ({
51-
maxFeePerGas: 100_000n,
52-
maxPriorityFeePerGas: 0n,
53-
})
54-
: undefined,
41+
estimateFeesPerGas: createFeeEstimator(client),
5542
},
5643
...config,
5744
});
5845
}
46+
47+
function createFeeEstimator(client: Client): undefined | (() => Promise<EstimateFeesPerGasReturnType<"eip1559">>) {
48+
if (!client.chain) return;
49+
50+
// anvil hardcodes fee returned by `eth_maxPriorityFeePerGas`
51+
// so we override it here to mimick our chains
52+
// https://github.com/foundry-rs/foundry/pull/8081#issuecomment-2402002485
53+
// TODO: move this to user op executor transport?
54+
if (client.chain.id === 31337) {
55+
return async () => ({ maxFeePerGas: 100_000n, maxPriorityFeePerGas: 0n });
56+
}
57+
58+
// do our own fee calculation for redstone, garnet, rhodolite chains
59+
// because viem sets fees way too high by default
60+
// https://github.com/wevm/viem/blob/253b1072ad9fe36a0e0491e173c85a6d69209ada/src/account-abstraction/actions/bundler/prepareUserOperation.ts#L436-L457
61+
if ([690, 17069, 17420].includes(client.chain.id)) {
62+
// TODO: move to fee ref or similar approach
63+
return () => getAction(client, estimateFeesPerGas, "estimateFeesPerGas")({ chain: client.chain });
64+
}
65+
}

packages/entrykit/src/getSessionClient.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,8 @@ export async function getSessionClient({
2020
throw new Error("Session account client had no associated chain.");
2121
}
2222

23-
const bundlerTransport = getBundlerTransport(client.chain);
2423
const bundlerClient = createBundlerClient({
25-
transport: bundlerTransport,
24+
transport: getBundlerTransport(client.chain),
2625
client,
2726
account: sessionAccount,
2827
});

packages/entrykit/src/onboarding/common.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export type Step = {
77
content: (props: { isActive: boolean; isExpanded: boolean }) => ReactNode;
88
};
99

10+
// TODO: move to chain config?
1011
export const minGasBalance = parseEther("0.01");
1112

1213
export type RelayChain = {

packages/entrykit/src/onboarding/usePrerequisites.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ export function getPrequisitesQueryOptions({
5858
isSpender,
5959
hasGasBalance,
6060
hasDelegation,
61-
complete: hasAllowance && isSpender && hasDelegation,
61+
// we intentionally don't enforce an allowance/gas balance here
62+
complete: isSpender && hasDelegation,
6263
};
6364
},
6465
retry: false,

0 commit comments

Comments
 (0)