Docs

state_call - Kusama RPC Method

Call a runtime API function on Kusama. Execute on-chain computations like account nonce lookups, fee estimation, and custom runtime logic without submitting a transaction.

Calls a runtime API function on Kusama and returns the SCALE-encoded result. This method lets you execute runtime logic (such as AccountNonceApi, TransactionPaymentApi, or any custom runtime API) without submitting a transaction.

Why Kusama? Build on Polkadot's canary network for real-world testing with live economic conditions with 7-day governance cycles (vs 1 month on Polkadot), lower bonding requirements, live KSM token economy, and first-to-market feature testing.

When to Use This Method

state_call is essential for experimental dApp developers, parachain teams, and early adopters validating new features:

  • Account Nonce Queries -- Retrieve the next nonce for an account via AccountNonceApi_account_nonce before constructing extrinsics
  • Fee Estimation -- Use TransactionPaymentApi_query_info to estimate fees for parachain experimentation, early feature deployment, and production-grade testing with real value
  • Custom Runtime APIs -- Call any runtime API exposed by the chain (e.g., staking queries, governance lookups, DeFi calculations)
  • Historical State Queries -- Execute runtime logic at a specific block by providing an optional block hash

Code Examples

Common Use Cases

1. Get Account Nonce for Transaction Construction

Query the next nonce before building and signing an extrinsic:

JavaScript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getNextNonce(api, address) {
  // Using the runtime API directly (preferred over system.accountNextIndex)
  const nonce = await api.call.accountNonceApi.accountNonce(address);
  return nonce.toNumber();
}

async function buildAndSendTransfer(api, sender, recipient, amount) {
  const nonce = await getNextNonce(api, sender.address);

  const transfer = api.tx.balances.transferKeepAlive(recipient, amount);
  const hash = await transfer.signAndSend(sender, { nonce });

  console.log(`Sent with nonce ${nonce}, hash: ${hash.toHex()}`);
}

2. Custom Runtime API Queries

Call chain-specific runtime APIs for DeFi or governance queries:

JavaScript
async function queryRuntimeApi(api, methodName, encodedArgs, blockHash) {
  const params = [methodName, encodedArgs];
  if (blockHash) params.push(blockHash);

  const result = await api.rpc.state.call(...params);
  return result.toHex();
}

// Example: query a staking-related runtime API at a specific block
const stakingResult = await queryRuntimeApi(
  api,
  'StakingApi_nominations_quota',
  '0x00e1f505', // SCALE-encoded balance
  '0xabc123...' // specific block hash
);

3. Historical State Query

Execute a runtime API call against a historical block:

JavaScript
async function getNonceAtBlock(api, address, blockHash) {
  const nonce = await api.call.accountNonceApi.accountNonce.at(blockHash, address);
  return nonce.toNumber();
}

// Compare current nonce vs historical nonce
const currentNonce = await getNonceAtBlock(api, address);
const historicalNonce = await getNonceAtBlock(api, address, oldBlockHash);
console.log(`Transactions since block: ${currentNonce - historicalNonce}`);

Error Handling

Common errors and solutions:

Error CodeDescriptionSolution
-32603Execution failedVerify the runtime API method name exists on this chain; check SCALE encoding of input data
-32602Invalid paramsEnsure data is properly SCALE-encoded as a hex string with 0x prefix
-32005Rate limit exceededReduce request frequency or implement client-side rate limiting
Method not foundRuntime API unavailableThe specified runtime API is not implemented by this chain's runtime -- use state_getMetadata to check