--- 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.