# read_contract_at

Calls a contract function at an explicit block number and returns ABI-decoded SQL values.

Canonical HTML: <https://determica.com/docs/functions/read_contract_at>

- Kind: scalar function
- Category: [Chain reads](/docs/category/chain-reads.md)
- Tags: RPC

Calls a contract function at an explicit block number and returns ABI-decoded SQL values.

## Overload 1: read_contract_at(CLIENT, ADDRESS, JSON, VARCHAR, BIGINT, ...args)

```sql
read_contract_at(CLIENT, ADDRESS, JSON, VARCHAR, BIGINT, ...args)
```

The non-negative BIGINT block number may vary by row. ABI and function_name must be literal or foldable. Pinned and retained execution CLIENT values reject the explicit selector.

- Kind: scalar
- Execution context: Live RPC
- Behavior: Immediate Read
- Execution modes: Live Client, Pinned Client, Execution Client
- Input shape: Scalar Arguments
- Planning contract: Bind Time Schema
- Cardinality: One Per Input
- Determinism: External State
- Return shape: Scalar
- Schema stability: Abi Dependent
- Stability: Stable
- Side effects: network_io

### Requirements

- client_state_context
- rpc

### Risks

- provider_limits
- chain_reorganization

### Inputs

- `client` (CLIENT; required; positional) — Live, pinned, or retained execution CLIENT. Pinned and execution state require the resolved block selector to be latest and reject other selectors.
- `to` (ADDRESS; required; positional) — Contract address to call.
- `abi` (JSON; required; positional) — Literal or foldable JSON ABI used for argument encoding and output types.
- `function_name` (VARCHAR; required; positional) — Literal or foldable ABI function name.
- `block_number` (BIGINT; required; positional) — Non-negative BIGINT block number. NULL produces NULL without issuing an RPC call.
- `function_args` (ANY; positional; variadic) — Pass one SQL value per ABI input. The ABI determines how many values are accepted and how each value is cast. The ABI and function name must be literal or foldable so the return type can be inferred during planning.

### Returns

ABI-derived scalar or STRUCT

A function with one output returns that value directly. A function with multiple outputs returns a STRUCT with fields named from ABI outputs, or field_0, field_1, and so on for unnamed outputs.

- `result` (ABI-derived scalar or STRUCT; dynamic) — A function with one output returns that value directly. A function with multiple outputs returns a STRUCT with fields named from ABI outputs, or field_0, field_1, and so on for unnamed outputs.

ABI-derived scalar or STRUCT. A function with one output returns that value directly. A function with multiple outputs returns a STRUCT with fields named from ABI outputs, or field_0, field_1, and so on for unnamed outputs.

### Examples

_Named parameters · Needs RPC · RPC required_

```sql
-- Chainlink ETH/USD at one block per day
WITH as_of(day) AS (
  SELECT day
  FROM generate_series('2024-01-01'::DATE, '2024-01-07'::DATE, INTERVAL 1 DAY) AS t(day)
)
SELECT
  day,
  format_units(
    (read_contract_at(
      $client,
      '0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419'::ADDRESS,
      '[{"type":"function","name":"latestRoundData","inputs":[],"outputs":[{"name":"roundId","type":"uint80"},{"name":"answer","type":"int256"},{"name":"startedAt","type":"uint256"},{"name":"updatedAt","type":"uint256"},{"name":"answeredInRound","type":"uint80"}]}]'::JSON,
      'latestRoundData',
      block_at($client, day::TIMESTAMPTZ)
    )).answer,
    8
  )::DOUBLE AS eth_usd
FROM as_of;
```

## Guidance

### Historical contract reads

Use read_contract_at when the block number is already a typed BIGINT value or comes from block_at.

The ABI and function name remain planning-time constants so the exact scalar or STRUCT return type can be inferred.

- NULL block numbers return NULL without an RPC request.
- Negative block numbers are rejected locally.
- Use read_contract options instead when you need a block tag, on_error, or a dynamic return schema.

## Related functions

- [read_contract](/docs/functions/read_contract.md) — Alternative
- [block_at](/docs/functions/block_at.md) — Usually Before
- [raw_call](/docs/functions/raw_call.md) — Alternative
- [read_contract_multicall](/docs/functions/read_contract_multicall.md) — See Also
