Skip to content

Commit 7cd553a

Browse files
authored
feat(entrykit): non-blocking fee estimation (#3784)
1 parent c4447b1 commit 7cd553a

6 files changed

Lines changed: 64 additions & 7 deletions

File tree

.changeset/four-zoos-smile.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+
Fees for Redstone, Pyrope and Garnet are now cached for 10 seconds instead of fetched before every user operation.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { Client, EstimateFeesPerGasReturnType } from "viem";
2+
import { estimateFeesPerGas } from "viem/actions";
3+
4+
type CachedFeesPerGasOptions = {
5+
refreshInterval?: number;
6+
};
7+
8+
export function cachedFeesPerGas(
9+
client: Client,
10+
options: CachedFeesPerGasOptions = { refreshInterval: 10_000 },
11+
): () => Promise<EstimateFeesPerGasReturnType<"eip1559">> {
12+
let fees: EstimateFeesPerGasReturnType<"eip1559"> | null = null;
13+
14+
async function refreshFees() {
15+
fees = await estimateFeesPerGas(client);
16+
}
17+
18+
refreshFees();
19+
setInterval(refreshFees, options.refreshInterval);
20+
21+
return async () => {
22+
if (fees) return fees;
23+
fees = await estimateFeesPerGas(client);
24+
return fees;
25+
};
26+
}

packages/entrykit/src/createBundlerClient.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@ import {
77
} from "viem/account-abstraction";
88
import { defaultClientConfig } from "./common";
99
import { getPaymaster } from "./getPaymaster";
10-
import { getAction } from "viem/utils";
11-
import { estimateFeesPerGas } from "viem/actions";
10+
import { cachedFeesPerGas } from "./actions/cachedFeesPerGas";
1211

1312
export function createBundlerClient<
1413
transport extends Transport,
@@ -56,10 +55,9 @@ function createFeeEstimator(client: Client): undefined | (() => Promise<Estimate
5655
}
5756

5857
// do our own fee calculation for redstone, garnet, pyrope 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
58+
// to avoid the default RPC call to `eth_getBlockByNumber`
59+
// https://github.com/wevm/viem/blob/3aa882692d2c4af3f5e9cc152099e07cde28e551/src/actions/public/estimateFeesPerGas.ts#L132
6160
if ([690, 17069, 695569].includes(client.chain.id)) {
62-
// TODO: move to fee ref or similar approach
63-
return () => getAction(client, estimateFeesPerGas, "estimateFeesPerGas")({ chain: client.chain });
61+
return cachedFeesPerGas(client);
6462
}
6563
}

packages/entrykit/src/exports/internal.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export { AccountButton } from "../AccountButton";
1111
export { useAccountModal } from "../useAccountModal";
1212
export { useSessionClientReady as useSessionClient } from "../useSessionClientReady";
1313
export { createWagmiConfig, type CreateWagmiConfigOptions } from "../createWagmiConfig";
14+
export { withFeeCache } from "../utils/withFeeCache";
1415

1516
// And some additional internal things
1617
export * from "../validateSigner";

packages/entrykit/src/getSessionClient.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ export async function getSessionClient({
4444
publicClient: client,
4545
}),
4646
)
47-
4847
// TODO: add observer once we conditionally fetch receipts while bridge is open
4948
.extend(() => ({ userAddress, worldAddress, internal_signer: sessionSigner }));
5049

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { Chain, createClient, http } from "viem";
2+
import { cachedFeesPerGas } from "../actions/cachedFeesPerGas";
3+
4+
type WithFeeCacheOptions = {
5+
refreshInterval?: number;
6+
};
7+
8+
export function withFeeCache<chain extends Chain>(
9+
chain: chain,
10+
options: WithFeeCacheOptions = { refreshInterval: 10_000 },
11+
): chain {
12+
if (chain.fees?.estimateFeesPerGas) {
13+
throw new Error("withFeeCache: estimateFeesPerGas already defined in chain config");
14+
}
15+
16+
const client = createClient({
17+
chain,
18+
transport: http(),
19+
});
20+
21+
return {
22+
...chain,
23+
fees: {
24+
...chain.fees,
25+
estimateFeesPerGas: cachedFeesPerGas(client, options),
26+
},
27+
};
28+
}

0 commit comments

Comments
 (0)