---
title: "Reading from Intelligent Contracts"
description: "Reading from Intelligent Contracts uses view functions to query state with GenLayerJS without transactions, gas, or state changes."
source: https://docs.genlayer.com/developers/decentralized-applications/reading-data
last_updated: 2026-07-20
---

# Reading from Intelligent Contracts

Reading from Intelligent Contracts means querying contract state or executing view functions without modifying blockchain state. These read-only operations are free, require no fees, and provide immediate access to contract data.

## Understanding View Operations

In GenLayer, functions marked with the `@gl.public.view` decorator are read-only operations that:
- Don't modify the contract's state
- Can be executed without requiring a transaction
- Return data immediately
- Don't consume gas
- Can be called by any account

## Basic Contract Reading

Here's how to read from an Intelligent Contract:

```typescript
import { simulator } from 'genlayer-js/chains';
import { createClient, createAccount } from 'genlayer-js';

const account = createAccount();
const client = createClient({
  chain: simulator,
  account: account,
});

const result = await client.readContract({
  address: contractAddress,
  functionName: 'get_complete_storage',
  args: [],
});
```

### Parameters Explained

- `address`: The deployed contract's address on the GenLayer network
- `functionName`: The name of the view function you want to call
- `args`: An array of arguments that the function accepts (empty if none required)

## Common View Operations

Intelligent Contracts typically include several types of view functions:

### State Queries
```typescript
// Reading a single value
const balance = await client.readContract({
  address: contractAddress,
  functionName: 'get_balance',
  args: [accountAddress],
});

// Reading multiple values
const userInfo = await client.readContract({
  address: contractAddress,
  functionName: 'get_user_info',
  args: [userId],
});
```

### Computed Values
```typescript
// Getting calculated results
const totalSupply = await client.readContract({
  address: contractAddress,
  functionName: 'calculate_total_supply',
  args: [],
});
```

### Validation Checks
```typescript
// Checking permissions
const hasAccess = await client.readContract({
  address: contractAddress,
  functionName: 'check_user_permission',
  args: [userId, 'ADMIN_ROLE'],
});
```

## Error Handling

When reading from contracts, you should handle potential errors:

```typescript
try {
  const result = await client.readContract({
    address: contractAddress,
    functionName: 'get_data',
    args: [],
  });
  console.log('Data retrieved:', result);
} catch (error) {
  if (error.message.includes('Contract not found')) {
    console.error('Invalid contract address');
  } else if (error.message.includes('Function not found')) {
    console.error('Invalid function name');
  } else {
    console.error('Error reading contract:', error);
  }
}
```

## Best Practices

1. **Batch Readings**: When possible, use functions that return multiple values instead of making many separate calls.
2. **Type Safety**: Use TypeScript interfaces to ensure type safety when handling returned data.
3. **Cache Shared Reads**: Treat public RPC endpoints as shared infrastructure. Browser traffic can multiply `gen_call` requests quickly, so production DApps should avoid polling the chain independently from every tab or visitor.

## Building Read-Heavy DApps

`readContract` calls are convenient for account pages, dashboards, and dispute views, but they still consume RPC capacity. If a frontend calls `gen_call` repeatedly from every browser session, the app can hit rate limits even though the operation is read-only and gasless.

For read-heavy DApps, use a layered pattern:

- **On-chain source of truth**: keep the Intelligent Contract as the authoritative state machine.
- **Backend cache or sidecar**: poll the contract at a controlled interval and serve many frontend users from the cached response.
- **Batch view functions**: expose view methods that return the full page state needed by the UI, instead of requiring many small reads.
- **HTTP cache semantics**: use `ETag`, `Cache-Control`, or stale-while-revalidate behavior so clients do not refetch unchanged data.
- **Verify-on-chain fallback**: keep a UI path that can re-read the contract directly for users who need to verify the cached value.

A minimal backend route can centralize reads like this:

```typescript
let cachedPageState: unknown;
let cachedAt = 0;
const CACHE_TTL_MS = 12_000;

export async function getPageState() {
  const now = Date.now();

  if (cachedPageState && now - cachedAt < CACHE_TTL_MS) {
    return cachedPageState;
  }

  cachedPageState = await client.readContract({
    address: contractAddress,
    functionName: 'get_page_state',
    args: [],
  });
  cachedAt = now;

  return cachedPageState;
}
```

This does not replace on-chain verification. It reduces duplicate read load for normal browsing while preserving GenLayer as the source of truth.
