Skip to content
Merged
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
5 changes: 5 additions & 0 deletions .changeset/four-zoos-smile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@latticexyz/entrykit": patch
---

Fees for Redstone, Pyrope and Garnet are now cached for 10 seconds instead of fetched before every user operation.
26 changes: 26 additions & 0 deletions packages/entrykit/src/actions/cachedFeesPerGas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Client, EstimateFeesPerGasReturnType } from "viem";
import { estimateFeesPerGas } from "viem/actions";

type CachedFeesPerGasOptions = {
refreshInterval?: number;
};

export function cachedFeesPerGas(
client: Client,
options: CachedFeesPerGasOptions = { refreshInterval: 10_000 },
): () => Promise<EstimateFeesPerGasReturnType<"eip1559">> {
let fees: EstimateFeesPerGasReturnType<"eip1559"> | null = null;

async function refreshFees() {
fees = await estimateFeesPerGas(client);
}

refreshFees();
setInterval(refreshFees, options.refreshInterval);

return async () => {
if (fees) return fees;
fees = await estimateFeesPerGas(client);
return fees;
};
}
10 changes: 4 additions & 6 deletions packages/entrykit/src/createBundlerClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ import {
} from "viem/account-abstraction";
import { defaultClientConfig } from "./common";
import { getPaymaster } from "./getPaymaster";
import { getAction } from "viem/utils";
import { estimateFeesPerGas } from "viem/actions";
import { cachedFeesPerGas } from "./actions/cachedFeesPerGas";

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

// do our own fee calculation for redstone, garnet, pyrope chains
// because viem sets fees way too high by default
// https://github.com/wevm/viem/blob/253b1072ad9fe36a0e0491e173c85a6d69209ada/src/account-abstraction/actions/bundler/prepareUserOperation.ts#L436-L457
// to avoid the default RPC call to `eth_getBlockByNumber`
// https://github.com/wevm/viem/blob/3aa882692d2c4af3f5e9cc152099e07cde28e551/src/actions/public/estimateFeesPerGas.ts#L132
if ([690, 17069, 695569].includes(client.chain.id)) {
// TODO: move to fee ref or similar approach
return () => getAction(client, estimateFeesPerGas, "estimateFeesPerGas")({ chain: client.chain });
return cachedFeesPerGas(client);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

viem prioritizes this method over the chain's estimateFeesPerGas config: https://github.com/wevm/viem/blob/3aa882692d2c4af3f5e9cc152099e07cde28e551/src/account-abstraction/actions/bundler/prepareUserOperation.ts#L447. If we override only the estimateFeesPerGas config, we still have one unnecessary call for getBlock: https://github.com/wevm/viem/blob/3aa882692d2c4af3f5e9cc152099e07cde28e551/src/actions/public/estimateFeesPerGas.ts#L132

@frolic frolic Jul 10, 2025

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

apparently viem no longer does this "3 gwei minimum" thing like it used to

previous: https://github.com/wevm/viem/blob/253b1072ad9fe36a0e0491e173c85a6d69209ada/src/account-abstraction/actions/bundler/prepareUserOperation.ts#L436-L457

now: https://github.com/wevm/viem/blob/main/src/account-abstraction/actions/bundler/prepareUserOperation.ts#L469-L483

which landed here and is now in mud: wevm/viem@9a7e864

so maybe we update the comment to say "we override this here to avoid an unnecessary getBlock call"?

}
}
1 change: 1 addition & 0 deletions packages/entrykit/src/exports/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export { AccountButton } from "../AccountButton";
export { useAccountModal } from "../useAccountModal";
export { useSessionClientReady as useSessionClient } from "../useSessionClientReady";
export { createWagmiConfig, type CreateWagmiConfigOptions } from "../createWagmiConfig";
export { withFeeCache } from "../utils/withFeeCache";

// And some additional internal things
export * from "../validateSigner";
Expand Down
1 change: 0 additions & 1 deletion packages/entrykit/src/getSessionClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ export async function getSessionClient({
publicClient: client,
}),
)

// TODO: add observer once we conditionally fetch receipts while bridge is open
.extend(() => ({ userAddress, worldAddress, internal_signer: sessionSigner }));

Expand Down
28 changes: 28 additions & 0 deletions packages/entrykit/src/utils/withFeeCache.ts
Comment thread
frolic marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Chain, createClient, http } from "viem";
import { cachedFeesPerGas } from "../actions/cachedFeesPerGas";

type WithFeeCacheOptions = {
refreshInterval?: number;
};

export function withFeeCache<chain extends Chain>(
chain: chain,
options: WithFeeCacheOptions = { refreshInterval: 10_000 },
): chain {
if (chain.fees?.estimateFeesPerGas) {
throw new Error("withFeeCache: estimateFeesPerGas already defined in chain config");
}

const client = createClient({
chain,
transport: http(),
});

return {
...chain,
fees: {
...chain.fees,
estimateFeesPerGas: cachedFeesPerGas(client, options),
},
};
}
Loading