Skip to content

Sample a long range ​

Read stETH's share rate once a day across two hundred thousand blocks, and watch it step up with every rebase.

cql
let stETH = ethereum:0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84;

from stETH at 25_800_000..26_000_000 every 7200 as s
| project { block: $block, time: $timestamp, ethPerShare: format(s.getPooledEthByShares(1e18), 18) }

Open in workbench →

29 rows; the first six:

blocktimeethPerShare
258048002026-08-21T16:46:59Z1.24219014278314575
258120002026-08-22T16:52:23Z1.242271090726486053
258192002026-08-23T16:57:47Z1.242346440645230173
258264002026-08-24T17:01:23Z1.242424181709375761
258336002026-08-25T17:07:35Z1.24250107943967682
258408002026-08-26T17:11:47Z1.242575976401495391

How it reads ​

at 25_800_000..26_000_000 every 7200 reads the contract at every block divisible by 7 200 inside the range — 28 of them — plus the range's end. On Ethereum 7 200 blocks is about a day. The grid is absolute, so the sampled blocks are 25_804_800, 25_812_000, … whatever the range's start; that is why the first row is not block 25 800 000.

ethPerShare rises a little from each row to the next because stETH rebases once a day, when Lido's oracle reports, and a sample a day catches each step once. Sample twice a day and every value appears twice; sample once a week and you skip six steps. $timestamp is the time of the block that answered, which drifts a few minutes later each day because 7 200 blocks is not quite 24 hours.

Leave every out and CQL picks a step itself to keep the source under 10 000 rows, and tells you which as CQL3900. Long ranges and limits has the rule.

Variations ​

  • A summary instead of a list. | summarize lo = min(ethPerShare), hi = max(ethPerShare) after the project, or the first and last — Average daily change and annualised rate.
  • Ending at the head. at latest-21600..latest every 7200 is the last three days, and the rows move with the head each time you run it.

By time instead of block count ​

at time … every 1d samples at midnight UTC. $sampleAt holds the exact day, and $block the last block before it, except on the first row, which is where the range starts: the first block at or after its midnight.

cql
let stETH = ethereum:0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84;

from stETH at time '2026-09-20'..'2026-09-23' every 1d as s
| project { day: $sampleAt, block: $block, ethPerShare: format(s.getPooledEthByShares(1e18), 18) }

Open in workbench →

dayblockethPerShare
2026-09-20T00:00:00Z260149981.244406447835658845
2026-09-21T00:00:00Z260221691.244482479264728163
2026-09-22T00:00:00Z260293151.24455806764908769
2026-09-23T00:00:00Z260364631.244633419602089156

See also ​