---
title: read
sidebar_position: 4
description: "Typed contract.read namespace executes view/pure functions via triggerConstantContract off-chain, free of charge, resolving to the decoded return value."
keywords: ["read", "contract", "view", "pure", "constant call", "triggerconstantcontract"]
---
# read
> Added in **6.4.0**.
`contract.read` is a typed, ergonomic namespace that exposes a contract's
[`view` / `pure`](https://docs.soliditylang.org/en/latest/contracts.html#state-mutability)
(and legacy `constant`) functions. A read is executed through `triggerConstantContract`,
does **not** modify the chain, costs nothing, and resolves directly to the **decoded
result**.
State-changing functions live in the [`write`](./write.md) namespace instead. When the
ABI is declared `as const`, function names and argument types are checked at **compile
time**. This is the recommended alternative to the flat [`.call()`](./method.call.md)
surface.
:::note
Every namespace method is **async**. All validation (argument count, call value, …)
surfaces as a **promise rejection**, never a synchronous throw — always `await` the call.
:::
## Usage
```ts
// Signature (each method on the namespace)
contract.read.(args: unknown[], options?: ReadOptions): Promise
contract.read.(options?: ReadOptions): Promise // for a no-argument method
type ReadOptions = { from?: string; value?: number | bigint };
```
```ts
const abi = [...] as const;
const contract = tronWeb.contract(abi, 'contractAddress');
// resolves to the decoded return value
const result = await contract.read.methodName([arg0, arg1, ...], options);
```
The first positional argument is the **array of method arguments**. For a method that
takes no arguments you may pass nothing, or pass the options object directly:
```ts
await contract.read.totalSupply(); // no args
await contract.read.totalSupply(options); // no args, with options
await contract.read.balanceOf([owner]); // one arg
```
## Parameters
| Parameter | Description | Type |
| --------- | ----------- | ---- |
| args | Array of the method's arguments, in ABI order. Addresses may be base58 or hex. Omit for a no-arg method. | `unknown[]` |
| options | Optional. Call options (see below). | `object` |
**`read` options**
| Option | Description | Type |
| ------ | ----------- | ---- |
| from | The caller (issuer) address for the constant call (base58 or hex). Falls back to the instance's default address. | string |
| value | TRX (in **sun**) attached to the call (`callValue`). | number \| bigint |
A caller address is **required**: pass `from`, or set a default address on the TronWeb instance — if neither is set the call rejects (it is not issued from a zero address). To issue/sign as a specific account, use the [`write`](./write.md) namespace's `account` (private key) option; `account` is **write-only** and is not accepted by `read`.
## Returns
The decoded output. A single output is collapsed to the bare value (e.g. a `uint256`
resolves to a `bigint`); multiple outputs resolve to an array. A function that declares
**no outputs** resolves to `undefined`; a function that declares outputs but returns no
data rejects with `Failed to execute`.
## Selector form (overloads)
Each function is additionally exposed under its **full selector**, e.g.
`contract.read['balanceOf(address)']`. The selector form pins that exact overload, so
same-arity overloads can be addressed unambiguously:
```ts
const balance = await contract.read['balanceOf(address)'](['TXXX...']);
```
When two overloads share the same arity, the bare name cannot pick one and the call
rejects with `Ambiguous overloaded function "" ...` — use the selector key to
disambiguate.
:::tip
The selector key is a function's **canonical signature** — its name followed by the
parenthesized input types in canonical form (bare `uint` / `int` widen to
`uint256` / `int256`, tuples flatten to `(type,…)`; `trcToken` is kept as-is per the TVM
convention). Rather than hand-writing it, derive it from an ABI fragment with
`tronWeb.utils.abi.buildFunctionSelector` — it returns this exact string, the same value
the namespace registers internally:
```ts
const fragment = abi.find((f) => f.name === 'balanceOf');
const key = tronWeb.utils.abi.buildFunctionSelector(fragment); // 'balanceOf(address)'
await contract.read[key](['TXXX...']);
```
:::
:::note
Namespaces enumerate each method under **both** its bare name **and** its selector, so
`Object.keys(contract.read)` returns two entries per function:
```ts
Object.keys(contract.read); // ['balanceOf', 'balanceOf(address)']
```
:::
## Functions named `read`
If the ABI literally defines a function called `read`, it stays callable through the
legacy flat surface, and the namespace is served from the **same** object — so both work:
```ts
await contract.read().call(); // legacy flat call → triggerSmartContract
await contract.read.read(); // namespace entry → triggerConstantContract
```
## Validation & errors
All of the following reject the returned promise:
| Condition | Error message |
| --------- | ------------- |
| Wrong number of arguments | `Contract function "" expects argument(s) but received .` |
| Ambiguous same-arity overload (bare name) | `Ambiguous overloaded function "" for the given arguments; pass the full signature ...` |
| Calling `read` on a state-changing function | `Function "" is not read-only.` |
| `from` is not a valid address | `The "from" option must be a valid address.` |
| No caller address (`from` unset and no default) | `A caller address is required. Set the "from" option or a default address on the TronWeb instance.` |
| A function with declared outputs returns no data | `Failed to execute` |
| Invalid `value` | `call value cannot be negative` / `call value must be an integer` / `call value exceeds safe integer range` / `call value must be a number or bigint` |
## Example
```ts
const abi = [
{
type: 'function',
name: 'balanceOf',
stateMutability: 'view',
inputs: [{ name: 'owner', type: 'address' }],
outputs: [{ name: 'balance', type: 'uint256' }],
},
] as const;
async function demo() {
const contract = tronWeb.contract(abi, 'TContractAddress...');
// only `view` / `pure` functions appear here
const balance = await contract.read.balanceOf(['TOwnerAddress...']);
console.log(balance);
// output-start
42n
// output-end
// override the caller (issuer) address explicitly, plus a call value (in sun)
await contract.read.balanceOf(['TOwnerAddress...'], { from: 'TCallerAddress...', value: 3n });
}
demo();
```
See also the [`write`](./write.md) namespace and the flat [`call()`](./method.call.md) surface.