# state_call - Polkadot RPC Method

Calls a runtime API function on Polkadot 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 Polkadot?** Build on the heterogeneous multi-chain protocol with $300M+ DeFi TVL and JAM supercomputer upgrade incoming with shared relay chain security, XCM cross-chain messaging, JAM upgrade targeting 1M TPS, and 2.1B DOT supply cap.

## When to Use This Method

`state_call` is essential for parachain developers, cross-chain dApp builders, and teams requiring shared security:

- **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 cross-chain DeFi, parachain deployment, XCM interoperability, and DOT staking (8-10% APY)
- **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

## Best Practices

- Requires method name and encoded parameters specific to the runtime API
- Results are runtime-specific and version-dependent
- This is a non-mutating call -- safe for unlimited read queries
- Use `state_getRuntimeVersion` to verify compatibility before calling runtime APIs

## Request Parameters

- `method` (`String, required`): The runtime API method name (e.g., "AccountNonceApi_account_nonce")
- `data` (`String, required`): SCALE-encoded call data as a hex string (e.g., the encoded account ID)
- `blockHash` (`String, optional`): Block hash to execute against; defaults to the best block if omitted

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_call",
  "params": ["AccountNonceApi_account_nonce", "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"],
  "id": 1
}
```

## Response Fields

- `result` (`String, required`): SCALE-encoded result as a hex string; decode with the appropriate codec for the runtime API return type

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x05000000"
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Execution failed: Runtime API method not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Query account nonce via runtime API
curl -X POST https://api-polkadot.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "state_call",
    "params": [
      "AccountNonceApi_account_nonce",
      "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
    ],
    "id": 1
  }'
```

```javascript
// Using @polkadot/api (high-level)
import { ApiPromise, WsProvider } from '@polkadot/api';

const provider = new WsProvider('wss://api-polkadot.n.dwellir.com/YOUR_API_KEY');
const api = await ApiPromise.create({ provider });

// Call AccountNonceApi via the typed runtime API
const account = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const nonce = await api.call.accountNonceApi.accountNonce(account);
console.log('Account nonce:', nonce.toNumber());

// Call TransactionPaymentApi for fee estimation
const transfer = api.tx.balances.transferKeepAlive(account, 1000000000000);
const info = await api.call.transactionPaymentApi.queryInfo(transfer.toHex(), transfer.encodedLength);
console.log('Fee info:', info.toJSON());

await api.disconnect();

// Using fetch (low-level JSON-RPC)
const response = await fetch('https://api-polkadot.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'state_call',
    params: [
      'AccountNonceApi_account_nonce',
      '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
    ],
    id: 1
  })
});

const { result } = await response.json();
console.log('SCALE-encoded result:', result);
```

```python
import requests

def state_call(method, data, block_hash=None):
    params = [method, data]
    if block_hash:
        params.append(block_hash)

    response = requests.post(
        'https://api-polkadot.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'state_call',
            'params': params,
            'id': 1
        }
    )
    return response.json()['result']

# Query account nonce
account_id = '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d'
result = state_call('AccountNonceApi_account_nonce', account_id)
print(f'SCALE-encoded nonce: {result}')

# Using substrate-interface (auto-decodes)
from substrateinterface import SubstrateInterface

substrate = SubstrateInterface(url='wss://api-polkadot.n.dwellir.com/YOUR_API_KEY')
nonce = substrate.rpc_request('state_call', [
    'AccountNonceApi_account_nonce',
    account_id
])['result']
print(f'Nonce result: {nonce}')
```

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();

    // Query account nonce via runtime API
    let account_id = "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

    let response = client
        .post("https://api-polkadot.n.dwellir.com/YOUR_API_KEY")
        .json(&json!({
            "jsonrpc": "2.0",
            "method": "state_call",
            "params": ["AccountNonceApi_account_nonce", account_id],
            "id": 1
        }))
        .send()
        .await?;

    let result: serde_json::Value = response.json().await?;
    println!("SCALE-encoded nonce: {}", result["result"]);

    // Decode the SCALE-encoded u32 nonce
    let hex = result["result"].as_str().unwrap().trim_start_matches("0x");
    let bytes = hex::decode(hex)?;
    if bytes.len() >= 4 {
        let nonce = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
        println!("Decoded nonce: {}", nonce);
    }

    Ok(())
}
```

## 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}`);
```

## Related Methods

- [`state_getStorage`](https://www.dwellir.com/docs/polkadot/state_getStorage) -- Query a single storage item by key
- [`state_getMetadata`](https://www.dwellir.com/docs/polkadot/state_getMetadata) -- Get full runtime metadata including available runtime APIs
- [`state_queryStorageAt`](https://www.dwellir.com/docs/polkadot/state_queryStorageAt) -- Batch query multiple storage keys at a specific block
- [`payment_queryInfo`](https://www.dwellir.com/docs/polkadot/payment_queryInfo) -- Estimate fees (uses `TransactionPaymentApi` internally)
- [`system_version`](https://www.dwellir.com/docs/polkadot/system_version) -- Get the node version for compatibility checking
