Skip to content

Unfold an array into rows ​

Expand an array a call returned into one row per element, then call the contract again with each element.

Lido's staking router keeps its modules as a list of ids. One call returns the list; expand makes a row of each id, and the calls that follow use the row's id as their argument.

cql
let router = ethereum:0xFdDf38947aFB03C621C71b06C9C70bce73f12999;

from router as r
| expand r.getStakingModuleIds() as moduleId index i
| project { i, moduleId, active: r.getStakingModuleIsActive(moduleId), validators: r.getStakingModuleActiveValidatorsCount(moduleId) }

Open in workbench →

imoduleIdactivevalidators
01true258795
12true5000
23true25246
34true4609

Four rows, one per module: its position i in the list, the moduleId, whether it is active, and how many validators it runs.

How it reads ​

getStakingModuleIds() returns uint256[]; without expand it would be one array cell in one row. expand … as moduleId turns each element into a row of its own, repeating every other column, and index i numbers them from zero — a column worth keeping when the position in the list means something.

After the expand, moduleId is an ordinary column, and r.getStakingModuleIsActive(moduleId) calls the router once per row with that row's value. Both calls in the project are answered at the block of the source row — the newest, since there is no at — so the four rows describe one moment.

Variations ​

  • Only the active ones. | where active after the project.
  • Total the validators. | summarize validators = sum(validators) after the project; the router's whole validator count in one row.
  • Over time. from router at latest-50400..latest every 7200 as r, and each sampled block contributes as many rows as the router had modules then; add block: $block to the projection to tell them apart.

See also ​