Skip to content

Read a proxy ​

Call a contract whose functions live in another contract, and see which ABI answered.

cql
let stETH = ethereum:0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84;

from stETH as s
| project {
    block:        $block,
    ethPerShare:  format(s.getPooledEthByShares(1e18), 18),
    pooledEther:  format(s.getTotalPooledEther(), 18),
    totalShares:  format(s.getTotalShares(), 18)
  }

Open in workbench →

blockethPerSharepooledEthertotalShares
260427071.2447109157008669029761717.1353650365619361337842557.667190094063001578

One row: the share rate, the pooled ether and the total shares, decoded by an ABI the address itself does not declare.

How it reads ​

stETH is an Aragon app proxy. Its own verified source declares five functions — implementation, kernel, appId, proxyType and isDepositable — and no getPooledEthByShares; it forwards every other call to an implementation whose address it keeps in a known slot. CQL reads that slot, follows it to ethereum:0x028271e30a695c0527a0c50ca30603fed004cdb0, and decodes your calls with the implementation's ABI. You write the query as if the proxy were the token, because to a caller it is.

Press the ⓘ beside the address in the grid and the Contract tab shows what happened: a registry line naming where the ABI came from and a borrowed from line naming the implementation. The run's diagnostics say the same, as CQL3904. The five functions the proxy declares describe its upgrade machinery, not the token; implementation among them returns the address the tab names.

Over a range ​

stETH has been upgraded more than once since it launched, and a range that crosses an upgrade is decoded interval by interval — each stretch of blocks with the implementation that was live then. A function the newer implementation has and the older lacks is null on the older rows, and CQL3911 counts them.

When it goes wrong ​

Two things can look like a proxy and not resolve. An implementation slot that is still empty — the proxy was deployed and never initialised — is reported as CQL3906. A proxy whose implementation is itself unverified ends in CQL3008 at the call; the usual answers apply: Read a contract nobody has verified.

See also ​