Skip to main content
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 at the bottom). All standard eth_* read methods work; writes go through intents.

Token info

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

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

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.

Nonce

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

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