Base's Denim upgrade cuts block time from 2 seconds to 200 milliseconds. That gives you 10x the blocks, and any service that does work on every block makes 10x the RPC calls. That holds on every provider, because the chain sets the count, not your provider.
Provider prices stay the same. Your call count goes up 10x, and on per-call or compute-unit pricing the bill follows it. A production tip-of-chain stack on Base that costs $640 a month on Alchemy today costs $6,396 after Denim. The same stack on Dwellir goes from $112 to $977.
Denim is scheduled for Base Sepolia on October 21, 2026 and targets mainnet in November 2026. That leaves a few weeks to measure your own multiplier and choose where you want to pay for it.
10x the calls on every provider
The chart below takes one production stack on Base and runs it at both block times. Per block it handles a newHeads event, fetches the block and its receipts, traces the block with debug_traceBlockByNumber, runs eth_getLogs for 5 contracts and makes 20 eth_call reads. That is 29 billable calls per block, or 14.5 RPS today and 145 RPS after Denim. The code, contracts and transaction volume do not change. Only the block count does.

| Provider | Weight per block | 2s blocks | 200ms blocks | Change |
|---|---|---|---|---|
| Alchemy PAYG ($0.525/1M CU) | 940 CU | 1,218.2M CU = $639.58 | 12,182.4M CU = $6,395.76 | 10x |
| QuickNode | 600 credits | 777.6M: Accelerate $249 + 327.6M x $0.56 = $432.46 | 7,776M: Business $999 + 5,776M x $0.50 = $3,887 | 9x |
| Infura | 5,005 credits | 216M credits/day, ~2.9x Team's 75M/day cap | 2,162M credits/day | Enterprise only, before and after |
| Chainstack | 30 RU | 38.9M RU: Pro $199 | 388.8M RU: Enterprise $990 | 5x |
| Dwellir | 29 credits | 37.58M: Developer $49 + 12.58M x $5 = $111.92 | 375.84M: Growth $299 + 225.84M x $3 = $976.52 | 8.7x |
The weights come from each provider's published tables: on Alchemy the block is 940 CU (40 newHeads + 20 block + 20 receipts + 40 trace + 5 x 60 eth_getLogs + 20 x 26 eth_call), on QuickNode 600 credits (20 per call, 40 for the trace), and on Infura 5,005 credits, where receipts and the block trace cost 1,000 credits each. Sources: Alchemy compute units, QuickNode Base credits, Infura credit costs.
Every bill rises. Each provider starts from a different price per call, so 10x lands at a different number. On Alchemy, 10x is $6,396 a month. On Dwellir, 10x is $977. Chainstack's flat request units land in the same range as Dwellir; the large gap is with the compute-unit providers. If you are going to pay for 10x the calls, the starting rate is the part you control.
This post covers which workloads scale with block count, the bill for three common Base workloads, why compute-unit pricing makes the jump worse, and how to cut calls before mainnet activation. For code migration steps, read the Base Denim migration guide. For confirmation policy, read Base Flashblocks, pending and finality.
What is Base block time after Denim?
As of October 14, 2026, Base mainnet block time is 2 seconds. After Denim, Base produces five canonical blocks per second (200ms). Each block has its own number, hash, state root, receipts and unsafe/safe/finalized lifecycle. Denim replaces both the 2-second blocks and Flashblocks. Base Sepolia is scheduled to activate on October 21, 2026 at 18:00 UTC, and mainnet is targeting November 2026.
| Cadence | Block time | Blocks per day | Blocks per 30 days | newHeads events per second |
|---|---|---|---|---|
| Base today | 2s | 43,200 | 1,296,000 | 0.5 |
| Base after Denim | 200ms | 432,000 | 12,960,000 | 5 |
The arithmetic is 86,400 seconds / 2 = 43,200 and 86,400 / 0.2 = 432,000, multiplied by 30 for the month.
We measured mainnet.base.org on October 14, 2026: average block time 2.0 seconds, a 400M gas limit, and blocks about 7% full. Base Vibenet (chain ID 84538453, rpc.vibes.base.org) already runs Denim and measured an average block time of 0.2 seconds.
Flashblocks vs Denim
Flashblocks, live on Base since July 2025, were 200ms preconfirmations streamed inside a 2-second canonical block. You subscribed to newFlashblocks or pendingLogs, or read the pending tag. Denim removes all three. The 200ms unit becomes a canonical block, and Base's migration guide tells apps to subscribe to newHeads and "fetch transactions for each canonical block", which works out to five fetches per second.
Denim changes latency, not capacity
The gas limit per block drops by the same factor (DENIM_GAS_PARAMETER_SCALING_FACTOR = 10), from about 400M per 2-second block to about 40M per 200ms block. Throughput stays around 200 Mgas/s. Transaction demand does not change, so logs per second and transactions per second stay flat. Each block holds roughly a tenth of the data it holds today.
That is the root of the cost problem: the volume of chain data you consume stays the same, but it arrives spread across 10 times as many blocks.
Which workloads scale with block count
Whether your bill moves depends on what triggers your calls. Sort your RPC traffic into work that runs per block and work that runs per user, per timer or per transaction.

Per-transaction work stays flat in total because transaction volume does not change. It is still the most expensive pattern you can run, since a block-level call like eth_getBlockReceipts returns every receipt in one response.
Teams that already consume Flashblocks see little change. A newFlashblocks subscriber already handles about 432,000 events per day, and moving to newHeads keeps that volume. If that describes you, the migration guide matters more than this post.
The left-hand column is where the 10x lands. The next three sections price the most common of those workloads. All prices were checked on October 14, 2026.
Indexers
An indexer follows the head and pulls everything it needs for each block. Per block, it receives one newHeads event, calls eth_getBlockByNumber(n, true) and eth_getBlockReceipts, traces the block with debug_traceBlockByNumber for internal transfers, and runs a filtered eth_getLogs for each of 5 contracts. That is 9 billable calls per block: 11.66M a month today and 116.64M after Denim, or 4.5 RPS sustained becoming 45.

| Provider | Weight per block | 2s blocks | 200ms blocks | Change |
|---|---|---|---|---|
| Alchemy PAYG | 40 + 20 + 20 + 40 + 5 x 60 = 420 CU | 544.3M CU = $285.77 | 5,443.2M CU = $2,857.68 | 10x |
| QuickNode | 7 x 20 + 40 + 20 = 200 credits | 259.2M: Build $49 + 179.2M x $0.62 = $160.10 | 2,592M: Business $999 + 592M x $0.50 = $1,295 | 8.1x |
| Infura | 50 + 80 + 1,000 + 1,000 + 5 x 255 = 3,405 credits | 147M credits/day, ~2x Team's 75M/day cap | 1,471M credits/day | Enterprise only, before and after |
| Chainstack | 10 RU (trace counts 2) | 13.0M RU: Growth $49 | 129.6M RU: Business $499 | 10.2x |
| Dwellir | 9 credits | 11.66M: Developer $49 | 116.64M: Growth $299 | 6.1x |
Dwellir's bill rises too: metered plans charge per response, and 10x the blocks means 10x the responses. The gap comes from the weights. Each block costs 9 credits on Dwellir instead of 200, 420 or 3,405, and debug_traceBlockByNumber is one credit like any other call. At 45 RPS, the Developer plan with overage would cost $507, so Growth's 150M allowance is the cheaper fit.
Trading and liquidation bots
A trading or liquidation bot re-evaluates its positions on every block. Per block, it receives newHeads and runs 20 eth_call simulations across its markets. That is 21 calls per block: 27.22M a month today and 272.16M after Denim, or 10.5 RPS sustained becoming 105.

| Provider | Weight per block | 2s blocks | 200ms blocks | Change |
|---|---|---|---|---|
| Alchemy PAYG | 40 + 20 x 26 = 560 CU | $381.02 | $3,810.24 | 10x |
| QuickNode | 21 x 20 = 420 credits | Accelerate $249 + 94.3M x $0.56 = $301.82 | Business $999 + 3,443.2M x $0.50 = $2,720.60 | 9x |
| Dwellir | 21 credits | Developer $49 + 2.22M x $5 = $60.08 | Growth $299 + 122.16M x $3 = $665.48 | 11x |
Here Dwellir's multiplier is the full 10x, because the bot already runs slightly past the Developer allowance today. The multiplier matters less than where it lands: $665 against $2,721 to $3,810 for the same calls. Bots also care about latency at 5 heads per second, which is covered in MEV and arbitrage bot infrastructure. For simulation-heavy pricing, see eth_call pricing compared.
Oracles and keepers
A keeper checks its trigger conditions on every block: read the oracle prices, read the health of the positions it watches, decide whether to act. Per block, it receives newHeads and makes 10 eth_call reads: 2 oracle prices and 8 position health checks. That is 11 calls per block: 14.26M a month today and 142.56M after Denim, or 5.5 RPS sustained becoming 55.

| Provider | Weight per block | 2s blocks | 200ms blocks | Change |
|---|---|---|---|---|
| Alchemy PAYG | 40 + 10 x 26 = 300 CU | $204.12 | $2,041.20 | 10x |
| QuickNode | 11 x 20 = 220 credits | Build $49 + 205.1M x $0.62 = $176.17 | Business $999 + 851.2M x $0.50 = $1,424.60 | 8.1x |
| Dwellir | 11 credits | Developer $49 | Growth $299 | 6.1x |
Most keepers act on a small fraction of blocks, so nearly all of this spend is reads that find nothing to do. If your trigger can be expressed as an event, a logs subscription filtered to the oracle or position contract replaces the per-block polling and takes the keeper off the 10x curve.
All of these tables pick the cheapest self-serve plan that covers both the monthly volume and the sustained RPS (QuickNode's Build, Accelerate, Scale and Business plans allow 50, 125, 250 and 500 RPS). They use Alchemy's own ~1KB average for a newHeads notification (Denim adds timestampMs, so headers may be slightly larger) and do not net out free-tier allowances. QuickNode does not publish a per-notification credit cost for subscriptions, so we assumed 20 credits. Prices were checked on October 14, 2026.
Why compute-unit pricing makes it worse
The spread in those tables comes from how each provider weights a call. Compute-unit and credit weights bill per call, regardless of how much chain data the call returns. After Denim, an eth_getBlockReceipts call returns about a tenth of the receipts it returns today, and it still costs 20 CU on Alchemy and 1,000 credits on Infura. You pay for block count, not data.
That breaks the usual assumption that cost tracks usage. Your indexer stores the same number of logs per day and your database grows at the same rate, while the RPC line item goes up 10x.
Forecasting is already hard on these models. Alchemy's own blog says CU usage "can be difficult to predict... can vary by as much as 100x" (source). A cadence change on the chain adds a variable that has nothing to do with your product.
WebSocket subscriptions follow the same pattern. Alchemy bills subscription traffic at 0.04 CU per byte, Infura charges 50 credits per newHeads block and 300 per logs block, and QuickNode's support documentation warns of high eth_subscribe usage "particularly when subscribing to events like newHeads and on fast blockchains" (source). QuickNode suggests polling instead, which at 200ms has its own problems, covered below.
Dwellir counts each notification as one response. For the full breakdown, see eth_subscribe reconnect, backpressure and costs.
eth_getLogs windows and backfills
Billing is one side of the change. The other is every limit expressed in blocks, which now covers 10x less time.
eth_getLogs range | Time covered at 2s | Time covered at 200ms |
|---|---|---|
| 500 blocks | 16.7 min | 100 s |
| 2,000 blocks | 67 min | 6.7 min |
| 10,000 blocks | 5.6 h | ~33 min |
A backfill that scanned one day of history (43,200 blocks) in 5 calls of 10,000 blocks now needs 44 calls for 432,000 blocks. Recovering a 6-hour outage goes from 2 calls to 11. If your provider caps ranges by block count, plan chunk sizes in time and convert to blocks.
Dwellir's eth_getLogs caps are 500 blocks on Developer and 10,000 on Growth and above, with no eth_getLogs on Free. For other traps, see eth_getLogs archive cost traps.
If you self-host, check pruning. A --full node keeps 13,392,000 blocks. That is about 310 days at 2-second blocks and about 31 days at 200ms.
WebSockets at five heads per second
newHeads goes from 0.5 to 5 events per second. Base's Vibenet documentation warns that a 250-1000ms poll can miss multiple blocks and recommends WebSocket push. Base runs no free public WebSocket endpoint on mainnet, so head-following needs a provider endpoint.
Per-block rate limits also reset five times per second. Any request budget you define per block, in your own middleware or a provider's, now covers 200ms instead of 2 seconds. See RPC provider rate limits compared for how RPS caps differ across providers.
Ways to cut calls
The chain sets the block count. You control how many calls you make per block, and that is where the savings are.
Measure your own multiplier
Start with numbers from your own workload. This script estimates block time from two blocks N apart, then projects monthly calls and units from a calls-per-block profile. Run it against mainnet now and against Vibenet to compare.
// block-cost.mts - run with: npx tsx block-cost.mts
// Set RPC_URL to your Base endpoint, or https://rpc.vibes.base.org for Vibenet.
const RPC_URL = process.env.RPC_URL ?? "https://mainnet.base.org";
const N = 1_000; // sample span; a large N smooths out whole-second timestamps
async function rpc<T>(method: string, params: unknown[]): Promise<T> {
const res = await fetch(RPC_URL, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ jsonrpc: "2.0", id: 1, method, params }),
});
const body = await res.json();
if (body.error) throw new Error(body.error.message);
return body.result as T;
}
type Block = { number: string; timestamp: string; timestampMs?: string };
// Prefer Denim's millisecond timestamp, fall back to whole seconds.
const tsMs = (b: Block) =>
b.timestampMs != null ? Number(BigInt(b.timestampMs)) : Number(BigInt(b.timestamp)) * 1000;
// Your per-block call profile. Edit to match what your service does each block.
const profile: Record<string, number> = {
newHeads: 1,
eth_getBlockByNumber: 1,
eth_getBlockReceipts: 1,
debug_traceBlockByNumber: 1,
eth_getLogs: 5,
eth_call: 20,
};
// Published weights checked 2026-10-14. Alchemy newHeads assumes ~1KB at 0.04 CU/byte.
const weights: Record<string, Record<string, number>> = {
alchemyCU: { newHeads: 40, eth_getBlockByNumber: 20, eth_getBlockReceipts: 20, debug_traceBlockByNumber: 40, eth_getLogs: 60, eth_call: 26 },
infuraCredits: { newHeads: 50, eth_getBlockByNumber: 80, eth_getBlockReceipts: 1000, debug_traceBlockByNumber: 1000, eth_getLogs: 255, eth_call: 80 },
quicknodeCredits: { newHeads: 20, eth_getBlockByNumber: 20, eth_getBlockReceipts: 20, debug_traceBlockByNumber: 40, eth_getLogs: 20, eth_call: 20 },
dwellirCredits: { newHeads: 1, eth_getBlockByNumber: 1, eth_getBlockReceipts: 1, debug_traceBlockByNumber: 1, eth_getLogs: 1, eth_call: 1 },
};
const latest = await rpc<Block>("eth_getBlockByNumber", ["latest", false]);
const head = BigInt(latest.number);
const past = await rpc<Block>("eth_getBlockByNumber", ["0x" + (head - BigInt(N)).toString(16), false]);
const measured = (tsMs(latest) - tsMs(past)) / N / 1000; // seconds per block
const callsPerBlock = Object.values(profile).reduce((a, b) => a + b, 0);
const scenarios: [string, number][] = [["measured", measured], ["denim", 0.2]];
for (const [label, blockTime] of scenarios) {
const blocksPerMonth = (86_400 / blockTime) * 30;
console.log(`\n${label}: ${blockTime.toFixed(3)}s/block, ${Math.round(blocksPerMonth).toLocaleString()} blocks/30d`);
console.log(` calls/month: ${((callsPerBlock * blocksPerMonth) / 1e6).toFixed(2)}M, ` +
`sustained ${(callsPerBlock / blockTime).toFixed(1)} RPS`);
for (const [provider, w] of Object.entries(weights)) {
const unitsPerBlock = Object.entries(profile).reduce((sum, [m, n]) => sum + n * (w[m] ?? 0), 0);
const units = unitsPerBlock * blocksPerMonth;
const usd = provider === "alchemyCU" ? ` = $${((units / 1e6) * 0.525).toFixed(2)} PAYG` : "";
console.log(` ${provider}: ${(units / 1e6).toFixed(1)}M units/month${usd}`);
}
}
// Apply your own plan tiers and overage rates for the non-PAYG providers.With the default profile, the Denim line reproduces the production stack above: 375.84M calls, 145 RPS and 12,182.4M Alchemy CU ($6,395.76). Add every per-block call your service makes, including the ones hidden in SDKs and health checks.
One WebSocket, block-level calls, batched
The cheapest per-block pattern is one long-lived WebSocket that receives newHeads and fetches the whole block plus all receipts in a single batch. Keying both calls by hash ties them to the header you saw, so a newer block cannot slip in. This example uses the WebSocket client built into Node.js 22.
// head-follower.mts - Node.js 22+ (global WebSocket). npx tsx head-follower.mts
const WSS_URL = process.env.BASE_WSS_URL!; // e.g. your Dwellir Base WSS endpoint
const ws = new WebSocket(WSS_URL);
let nextId = 1;
let lastSeen: bigint | null = null;
const pending = new Map<number, (r: any) => void>();
ws.onopen = () => {
// One subscription for the life of the connection.
ws.send(JSON.stringify({ jsonrpc: "2.0", id: nextId++, method: "eth_subscribe", params: ["newHeads"] }));
};
ws.onmessage = async (msg) => {
const data = JSON.parse(String(msg.data));
// Batch responses arrive as arrays; resolve each entry by id.
if (Array.isArray(data)) return data.forEach((r) => pending.get(r.id)?.(r));
if (data.id && pending.has(data.id)) return pending.get(data.id)!(data);
if (data.method !== "eth_subscription") return; // e.g. the subscribe ack
const header = data.params.result;
const number = BigInt(header.number);
if (lastSeen !== null && number > lastSeen + 1n) {
// Gap detected: hand the missing range to an HTTP backfill job, not this socket.
console.warn(`gap ${lastSeen + 1n}..${number - 1n}`);
}
lastSeen = number;
// Two calls per block, sent as one JSON-RPC batch over the same socket.
try {
const [block, receipts] = await batch([
["eth_getBlockByHash", [header.hash, true]],
["eth_getBlockReceipts", [header.hash]],
]);
const ms = header.timestampMs ? BigInt(header.timestampMs) : BigInt(header.timestamp) * 1000n;
console.log(`block ${number} @${ms}ms: ${block.transactions.length} txs, ${receipts.length} receipts`);
} catch (err) {
// An RPC error must not crash the follower; queue this block for HTTP gap-fill instead.
console.error(`block ${number} fetch failed:`, err);
}
};
function batch(calls: [string, unknown[]][]): Promise<any[]> {
const reqs = calls.map(([method, params]) => ({ jsonrpc: "2.0", id: nextId++, method, params }));
const results = reqs.map(
(r) =>
new Promise((resolve, reject) =>
pending.set(r.id, (res) => {
pending.delete(r.id);
res.error ? reject(new Error(res.error.message)) : resolve(res.result);
}),
),
);
ws.send(JSON.stringify(reqs));
return Promise.all(results);
}That is 3 billable units per block: the notification plus two calls. Batching cuts round trips, but most providers, Dwellir included, still count each call inside a batch. The billing savings come from replacing per-transaction receipt calls with one eth_getBlockReceipts.
If you only need specific contract events, a logs subscription with address and topic filters can replace both fetches. Keep HTTP for gap-fill and backfills.
If you use Rust with Alloy, the plain AnyRpcHeader type drops timestampMs. Use WithOtherFields<AnyRpcHeader> to keep it.
Re-tune everything counted in blocks
Search your config for numbers that mean "blocks":
- Confirmation counts. 10 blocks used to be 20 seconds and is now 2 seconds.
eth_getLogschunk sizes. Size them in minutes, then convert.- Cache TTLs expressed in blocks.
- "N blocks behind" alerts. A 30-block lag alert now fires at 6 seconds.
- Polling loops that call
eth_getBalanceto detect changes. Replace them with alogsfilter on the token'sTransferevents.
Use timestampMs where it exists and fall back to whole-second timestamp, since up to five 200ms blocks share the same seconds value.
Pricing a 10x workload
With calls per block measured and trimmed, choosing a plan comes down to three questions.
- Is your usage dominated by heavy methods? If
eth_getBlockReceipts,eth_getLogsor subscriptions make up most of your traffic, CU and credit weights multiply the Denim effect. On Infura, receipts alone are 1,000 credits per block, so 432,000 blocks a day is 432M credits before anything else runs. - What is your sustained RPS after Denim? Multiply calls per block by 5. Check it against your plan's sustained limit, not just the monthly allowance. Dwellir's Developer, Growth and Scale plans run 100, 500 and 5,000 RPS.
- Is the load steady? Head-following workloads run flat 24 hours a day, which suits a flat-rate node. Dwellir's Unlimited Node tiers run from $119 at 25 RPS to $4,799 at 1,000 RPS with no metering, and a dedicated Base archive cluster costs $3,366/month.
Teams that already run Flashblocks consumers, or whose traffic is mostly user-driven reads, can skip the re-pricing. For everyone else, compare your own profile across providers in the best Base RPC providers and RPC providers without compute units. If you are moving off a CU model, switching from Alchemy and switching from QuickNode cover the endpoint and method changes.
Checklist before mainnet activation
Use the window between Sepolia activation on October 21 and mainnet, targeted for November, to re-price. If you wait until after mainnet activation, you pay the new rate while you measure.
- List every call your services make per block, including SDK and monitoring traffic
- Run the block-cost script against Vibenet, and against Base Sepolia after October 21
- Replace per-transaction receipt calls with
eth_getBlockReceipts - Move head-following to one long-lived WebSocket, with HTTP only for gap-fill
- Convert confirmation counts, getLogs chunks, cache TTLs and lag alerts from blocks to time
- Check sustained RPS (calls per block x 5) against your plan limits
- Model next month's bill on your current plan and one alternative
- Keep finality rules unchanged: 200ms blocks are not 200ms finality
Conclusion
Denim gives Base 432,000 blocks a day and leaves transaction volume where it is. Every indexer, bot and keeper that works per block makes 10x the calls, on every provider. What changes between providers is where 10x lands.
For the 29-call production stack, 10x is $6,396 a month on Alchemy PAYG and $3,887 on QuickNode, and Infura needs an Enterprise contract at either block time. On Dwellir the same 10x is $977 on the Growth plan, with debug and trace calls billed at one credit like everything else.
Run the block-cost script with your real call profile before mainnet activation. If the numbers point to a switch, Dwellir's Base RPC serves HTTPS and WebSocket endpoints, the Base docs list the methods, and the pricing page shows the plan and Unlimited Node tiers. For a dedicated cluster quote, contact the Dwellir team.


