> ## Documentation Index
> Fetch the complete documentation index at: https://build.flashnet.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Reading state

> Token info, balances, allowances, fees, arbitrary RPC reads

The execution module ships viem-backed read helpers for the contract reads every integration ends up doing. Each function takes the `rpcUrl` directly so they work outside an `ExecutionClient` instance.

For anything not wrapped, use the viem `PublicClient` exposed on the ExecutionClient (see [Read-only RPC methods](#read-only-rpc-methods) at the bottom). All standard `eth_*` read methods work; writes go through intents.

## Token info

```typescript theme={null}
import { fetchTokenInfo } from "@flashnet/sdk";

const info = await fetchTokenInfo(rpcUrl, tokenAddress);
// { address, symbol, name, decimals }
```

Reads `symbol`, `name`, and `decimals` in a single multicall. Throws if any of the three fails. Don't catch the error and fall back to defaults. `decimals: 0` masquerading as 18 will silently destroy your amount math.

## Balances

```typescript theme={null}
import { fetchTokenBalance, fetchNativeBalance } from "@flashnet/sdk";

const erc20Balance = await fetchTokenBalance(rpcUrl, tokenAddress, account);
const nativeBalance = await fetchNativeBalance(rpcUrl, account);
```

Both return `bigint`. `fetchNativeBalance` returns wei; divide by `10n ** 10n` to get sats (Flashnet's native unit is sats scaled to wei via `10^10`).

## Allowances

```typescript theme={null}
import { fetchAllowance } from "@flashnet/sdk";

const allowance = await fetchAllowance(rpcUrl, tokenAddress, owner, spender);
```

For `SparkToken` ERC20s, prefer EIP-2612 Permit signatures over standing allowances. The swap path uses Permit and you avoid an extra approval transaction. See [Swaps](/products/execution/swaps).

## Nonce

```typescript theme={null}
import { fetchNonce } from "@flashnet/sdk";

const nonce = await fetchNonce(rpcUrl, account);
```

Returns the next nonce to use for an outgoing transaction. Required when building a signed tx for `ExecutionClient.execute`.

## Fee parameters

```typescript theme={null}
import { fetchEip1559Fees } from "@flashnet/sdk/execution";

const fees = await fetchEip1559Fees(rpcUrl);
// { maxFeePerGas: 0n, maxPriorityFeePerGas: 0n } on Flashnet today
```

`fetchEip1559Fees` ships from the `/execution` subpath, not the root. The other read helpers on this page are re-exported at `@flashnet/sdk` directly.

Flashnet runs zero-gas. The node correctly reports zero, but `viem.estimateFeesPerGas()` applies its own multipliers and floor that produce non-zero values. `fetchEip1559Fees` reads the raw node values without that adjustment.

A future fee change (operator policy, partner chain) would surface here. Always fetch instead of hard-coding zero.

## Putting it together

The standard pre-flight before an `execute` intent:

```typescript theme={null}
import { fetchNonce } from "@flashnet/sdk";
import { fetchEip1559Fees } from "@flashnet/sdk/execution";

const account = await execClient.getEvmAccount();
const [nonce, fees, { execution }] = await Promise.all([
  fetchNonce(rpcUrl, account.address),
  fetchEip1559Fees(rpcUrl),
  execClient.getNetworkInfo(),
]);

const signedTx = await account.signTransaction({
  chainId: execution.chainId,
  nonce,
  to: targetAddress,
  value: 0n,
  data: calldata,
  gas: 500_000n,
  ...fees,
  type: "eip1559",
});
```

## Multicall

`fetchTokenInfo` uses Multicall3 internally. The Multicall3 contract is deployed at the canonical cross-chain address (`0xcA11bde05977b3631167028862bE2a173976CA11`) on every Flashnet chain, so any tooling that already understands Multicall3 works without configuration.

For your own batched reads, point a viem `PublicClient` at `rpcUrl` and pass `multicallAddress: "0xcA11bde05977b3631167028862bE2a173976CA11"`.

## Read-only RPC methods

For any `eth_*` read method not wrapped above, call `ExecutionClient.getPublicClient()` to get a configured viem `PublicClient`:

```typescript theme={null}
const publicClient = execClient.getPublicClient();

// Block and chain reads
const block = await publicClient.getBlock({ blockTag: "finalized" });
const blockNumber = await publicClient.getBlockNumber();

// Transaction reads
const receipt = await publicClient.getTransactionReceipt({ hash });
const tx = await publicClient.getTransaction({ hash });

// Contract reads
const value = await publicClient.readContract({ abi, address, functionName, args });
const result = await publicClient.multicall({ contracts: [...] });

// Logs
const logs = await publicClient.getLogs({ address, fromBlock, toBlock });

// Native balance and code
const balance = await publicClient.getBalance({ address });
const code = await publicClient.getCode({ address });
```

Every read method on the [viem PublicClient interface](https://viem.sh/docs/clients/public.html) works against the Flashnet RPC. The gateway proxy filters writes (`eth_sendTransaction`, `eth_sendRawTransaction`). Submit those as intents via `execute`, `withdraw`, or `withdrawToken`.

Debug methods (`debug_traceTransaction`, etc.) are blocked at the gateway. If you need them, point at a full-node RPC directly. See `traceInnermostRevert`'s `directRpcUrl` option in [Executing transactions](/products/execution/executing#decoding-reverts).
