{"id":87161,"plugin_id":"plugin_asdk_app_6abfbd9a20c481919866ead0f4722d34","kind":"skill","collection_source":"plugin_package","comparison_source":null,"observed_at":"2026-11-09T12:07:50.520Z","digest":"e777c5c2a1fe9dcd88f9b0039c957e73ccf8d787f0ee5f2ddba46a4c189ccb93","against":null,"payload":{"description":"Use when reading Substrate and Polkadot data through Dwellir endpoints: @polkadot/api connection setup, core RPC methods (system_*, chain_*, state_*), storage queries, WebSocket subscriptions, Sidecar REST APIs, and best practices. Use when working with Polkadot, Kusama, Substrate chains, parachains, extrinsics, or Sidecar REST endpoints through Dwellir. Triggers on mentions of polkadot, kusama, substrate, parachain, xcm, moonbeam, astar, acala, @polkadot/api, extrinsic, pallet, GRANDPA, sidecar, asset hub, bridge hub, or Substrate chain names.\n","included_files":[],"name":"substrate","skill_md_contents":"---\nname: substrate\ndescription: >\n  Use when reading Substrate and Polkadot data through Dwellir endpoints:\n  @polkadot/api connection setup, core RPC methods (system_*, chain_*, state_*),\n  storage queries, WebSocket subscriptions, Sidecar REST APIs, and best practices.\n  Use when working with Polkadot, Kusama, Substrate chains, parachains,\n  extrinsics, or Sidecar REST endpoints through Dwellir.\n  Triggers on mentions of polkadot, kusama, substrate, parachain, xcm,\n  moonbeam, astar, acala, @polkadot/api, extrinsic, pallet, GRANDPA,\n  sidecar, asset hub, bridge hub, or Substrate chain names.\n---\n\n# Substrate / Polkadot Ecosystem Reference\n\nUse Dwellir for blockchain reads, storage queries, and read-only application development.\nThis skill does not sign or submit extrinsics, transfer assets, or modify node keys.\nAn existing wallet or a rejected MCP method does not authorize an alternate execution route.\n\nDiscover endpoints with `list_endpoints` and choose a key reference with `list_keys`.\nCall a separately exposed read tool, such as `chain_getHeader`, `chain_getFinalizedHead`, or `state_getStorage`.\nUse its input schema for named arguments, including `endpoint_id` and `key_ref`.\nThe direct RPC examples below describe application code; MCP supports a smaller method set.\nRead credentials from environment variables or a secret store. Never print authenticated URLs or raw connection errors.\n\n## Overview\n\nSubstrate chains are WebSocket-native. While HTTP works for individual queries, **WSS is the preferred protocol** for Substrate — it supports subscriptions and is more efficient for the stateful connection model Substrate expects.\n\n- **Protocol:** JSON-RPC 2.0 over WSS (preferred) and HTTPS\n- **Authentication:** API key in URL path\n- **WSS format:** `wss://api-{chain}.n.dwellir.com/{API_KEY}`\n- **HTTPS format:** `https://api-{chain}.n.dwellir.com/{API_KEY}`\n\n## Connection Setup\n\n### @polkadot/api (JavaScript/TypeScript)\n\nThe standard SDK for Substrate chains.\n\n```typescript\nimport { ApiPromise, WsProvider } from '@polkadot/api';\n\nconst wsProvider = new WsProvider(\n  `wss://api-polkadot.n.dwellir.com/${process.env.DWELLIR_API_KEY}`\n);\nconst api = await ApiPromise.create({ provider: wsProvider });\n\n// Chain info\nconst chain = await api.rpc.system.chain();\nconst version = await api.rpc.system.version();\nconsole.log(`Connected to ${chain} v${version}`);\n```\n\n### py-substrate-interface (Python)\n\n```python\nfrom substrateinterface import SubstrateInterface\nimport os\n\nsubstrate = SubstrateInterface(\n    url=f\"wss://api-polkadot.n.dwellir.com/{os.environ['DWELLIR_API_KEY']}\"\n)\n\nresult = substrate.query(\"System\", \"Account\", [address])\nprint(f\"Free balance: {result.value['data']['free']}\")\n```\n\n### subxt (Rust)\n\n```rust\nuse subxt::{OnlineClient, PolkadotConfig};\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let api_key = std::env::var(\"DWELLIR_API_KEY\")?;\n    let url = format!(\"wss://api-polkadot.n.dwellir.com/{}\", api_key);\n    let api = OnlineClient::<PolkadotConfig>::from_url(&url)\n        .await.map_err(|_| \"Dwellir connection failed\")?;\n\n    let block = api.blocks().at_latest().await.map_err(|_| \"Dwellir block query failed\")?;\n    println!(\"Latest block: #{}\", block.number());\n    Ok(())\n}\n```\n\n### Raw WebSocket\n\n```javascript\nimport WebSocket from 'ws';\n\nconst ws = new WebSocket(\n  `wss://api-polkadot.n.dwellir.com/${process.env.DWELLIR_API_KEY}`\n);\n\nws.on('open', () => {\n  ws.send(JSON.stringify({\n    jsonrpc: '2.0',\n    method: 'chain_getBlock',\n    params: [],\n    id: 1,\n  }));\n});\n\nws.on('message', (data) => {\n  console.log(JSON.parse(data));\n});\n```\n\n## Supported Parachains\n\nDwellir provides deep coverage of the Polkadot and Kusama ecosystems.\n\n### Relay Chains\n\n| Chain | Endpoint Slug | Protocols |\n|-------|---------------|-----------|\n| Polkadot | `api-polkadot` | HTTPS, WSS |\n| Kusama | `api-kusama` | HTTPS, WSS |\n\n### Polkadot Parachains\n\n| Chain | Endpoint Slug | Description |\n|-------|---------------|-------------|\n| Asset Hub Polkadot | `api-asset-hub-polkadot` | Native asset management (formerly Statemint) |\n| Bridge Hub Polkadot | `api-bridge-hub-polkadot` | Cross-chain bridging |\n| Acala | `api-acala` | DeFi hub — stablecoins, DEX, liquid staking |\n| Astar | `api-astar` | Multi-VM smart contracts (EVM + WASM) |\n| Bifrost | `api-bifrost-polkadot` | Liquid staking for multiple chains |\n| Centrifuge | `api-centrifuge` | Real-world asset tokenization |\n| Hydration | `api-hydration` | Omnipool DEX — single-sided liquidity |\n| KILT | `api-kilt` | Decentralized identity and credentials |\n| Moonbeam | `api-moonbeam` | Ethereum-compatible smart contracts |\n\n### Kusama Parachains\n\n| Chain | Endpoint Slug | Description |\n|-------|---------------|-------------|\n| Asset Hub Kusama | `api-asset-hub-kusama` | Asset management on Kusama |\n| Bridge Hub Kusama | `api-bridge-hub-kusama` | Cross-chain bridging on Kusama |\n| Moonriver | `api-moonriver` | Moonbeam's canary network |\n\n### Testnets\n\n| Chain | Endpoint Slug |\n|-------|---------------|\n| Moonbase Alpha | `api-moonbase-alpha` |\n\nFull and current list: [dwellir.com/docs/getting-started/supported-chains](https://www.dwellir.com/docs/getting-started/supported-chains)\n\n## Core RPC Methods\n\n### system_* — Node & Network Info\n\n| Method | Description |\n|--------|-------------|\n| `system_chain` | Chain name |\n| `system_name` | Node implementation name |\n| `system_version` | Node version |\n| `system_health` | Node health (peers, syncing) |\n| `system_properties` | Chain properties (SS58 prefix, token decimals, token symbol) |\n| `system_peers` | Connected peer list |\n| `system_localPeerId` | Local node peer ID |\n| `system_nodeRoles` | Roles of the node (full, authority, light) |\n\n### chain_* — Block & Header Access\n\n| Method | Description | Params |\n|--------|-------------|--------|\n| `chain_getBlock` | Get block by hash (latest if omitted) | `[blockHash?]` |\n| `chain_getBlockHash` | Get block hash by number | `[blockNumber?]` |\n| `chain_getHeader` | Get block header | `[blockHash?]` |\n| `chain_getFinalizedHead` | Hash of latest finalized block | `[]` |\n\n### state_* — Storage & Runtime\n\n| Method | Description | Params |\n|--------|-------------|--------|\n| `state_getStorage` | Read a storage entry | `[storageKey, blockHash?]` |\n| `state_getStorageAt` | Read storage at specific block | `[storageKey, blockHash]` |\n| `state_queryStorage` | Query storage changes over range | `[keys, fromBlock, toBlock?]` |\n| `state_queryStorageAt` | Query storage at a block | `[keys, blockHash?]` |\n| `state_getMetadata` | Runtime metadata (types, pallets, calls) | `[blockHash?]` |\n| `state_getRuntimeVersion` | Runtime spec and impl version | `[blockHash?]` |\n| `state_getKeys` | List storage keys with prefix | `[prefix, blockHash?]` |\n| `state_getKeysPaged` | Paginated storage key listing | `[prefix, count, startKey?, blockHash?]` |\n| `state_call` | Execute a runtime API call | `[method, data, blockHash?]` |\n\n### grandpa_* — Finality\n\n| Method | Description |\n|--------|-------------|\n| `grandpa_roundState` | Current GRANDPA round state |\n| `grandpa_proveFinality` | Prove finality of a block |\n\n## Storage Queries\n\nSubstrate storage is key-value based. The `@polkadot/api` provides high-level wrappers.\n\n### Query Account Balance\n\n```typescript\n// Using @polkadot/api\nconst { data: { free, reserved } } = await api.query.system.account(address);\nconsole.log(`Free: ${free.toHuman()}, Reserved: ${reserved.toHuman()}`);\n```\n\n### Query Multiple Accounts\n\n```typescript\nconst accounts = ['5GrwvaEF...', '5FHneW46...'];\nconst balances = await api.query.system.account.multi(accounts);\nbalances.forEach((balance, i) => {\n  console.log(`${accounts[i]}: ${balance.data.free.toHuman()}`);\n});\n```\n\n### Read Arbitrary Storage\n\n```typescript\n// Pallet: Staking, Storage: Validators\nconst validators = await api.query.staking.validators.entries();\nvalidators.forEach(([key, prefs]) => {\n  console.log(`Validator: ${key.args[0].toString()}, Commission: ${prefs.commission.toHuman()}`);\n});\n```\n\n### Raw Storage Query\n\n```json\n{\n    \"jsonrpc\": \"2.0\",\n    \"method\": \"state_getStorage\",\n    \"params\": [\"0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9...\"],\n    \"id\": 1\n  }\n```\n\n## Runtime Calls\n\n### Get Metadata\n\n```typescript\nconst metadata = await api.rpc.state.getMetadata();\nconst pallets = metadata.asLatest.pallets.map(p => p.name.toString());\nconsole.log('Pallets:', pallets);\n```\n\n### Runtime API Calls\n\n```typescript\n// Check transaction payment info\nconst info = await api.call.transactionPaymentApi.queryInfo(extrinsic, extrinsic.length);\nconsole.log(`Estimated fee: ${info.partialFee.toHuman()}`);\n```\n\n## WebSocket Subscriptions\n\nSubscriptions are the primary way to receive real-time data from Substrate chains.\n\n### Subscribe to New Block Headers\n\n```typescript\nconst unsub = await api.rpc.chain.subscribeNewHeads((header) => {\n  console.log(`New block #${header.number}: ${header.hash.toHex()}`);\n});\n\n// Later: unsub();\n```\n\n### Subscribe to Finalized Heads\n\n```typescript\nconst unsub = await api.rpc.chain.subscribeFinalizedHeads((header) => {\n  console.log(`Finalized #${header.number}: ${header.hash.toHex()}`);\n});\n```\n\n### Subscribe to Storage Changes\n\n```typescript\n// Watch balance changes for an account\nconst unsub = await api.query.system.account(address, ({ data }) => {\n  console.log(`Balance changed — Free: ${data.free.toHuman()}`);\n});\n```\n\n### Subscribe to All Events\n\n```typescript\nconst unsub = await api.query.system.events((events) => {\n  events.forEach(({ event }) => {\n    console.log(`${event.section}.${event.method}: ${event.data.toString()}`);\n  });\n});\n```\n\n### Raw WebSocket Subscriptions\n\n```json\n// Subscribe to new heads\n{\"jsonrpc\":\"2.0\",\"method\":\"chain_subscribeNewHeads\",\"params\":[],\"id\":1}\n\n// Subscribe to finalized heads\n{\"jsonrpc\":\"2.0\",\"method\":\"chain_subscribeFinalizedHeads\",\"params\":[],\"id\":1}\n\n// Subscribe to storage changes\n{\"jsonrpc\":\"2.0\",\"method\":\"state_subscribeStorage\",\"params\":[[\"0x...\"]],\"id\":1}\n\n// Unsubscribe\n{\"jsonrpc\":\"2.0\",\"method\":\"chain_unsubscribeNewHeads\",\"params\":[\"subscriptionId\"],\"id\":1}\n```\n\n## Code Examples\n\n### Query Staking Info\n\n```typescript\nconst api = await ApiPromise.create({\n  provider: new WsProvider(`wss://api-polkadot.n.dwellir.com/${process.env.DWELLIR_API_KEY}`),\n});\n\n// Active era\nconst activeEra = await api.query.staking.activeEra();\nconsole.log(`Active era: ${activeEra.unwrap().index.toString()}`);\n\n// Total staked\nconst totalIssuance = await api.query.balances.totalIssuance();\nconsole.log(`Total issuance: ${totalIssuance.toHuman()}`);\n```\n\n### Cross-Chain (XCM) Query — Asset Hub Balance\n\n```typescript\nconst assetHubApi = await ApiPromise.create({\n  provider: new WsProvider(\n    `wss://api-asset-hub-polkadot.n.dwellir.com/${process.env.DWELLIR_API_KEY}`\n  ),\n});\n\n// Query foreign asset balance\nconst balance = await assetHubApi.query.system.account(address);\nconsole.log(`Asset Hub balance: ${balance.data.free.toHuman()}`);\n```\n\n### Monitor Moonbeam EVM Events\n\nMoonbeam is an EVM-compatible parachain — you can use both Substrate and EVM methods.\n\n```typescript\nimport { JsonRpcProvider } from 'ethers';\n\n// EVM-style access to Moonbeam\nconst provider = new JsonRpcProvider(\n  `https://api-moonbeam.n.dwellir.com/${process.env.DWELLIR_API_KEY}`\n);\n\nconst blockNumber = await provider.getBlockNumber();\nconsole.log(`Moonbeam block: ${blockNumber}`);\n```\n\n## Sidecar REST API\n\nSubstrate API Sidecar provides a REST interface for querying chain data. Availability depends on the account and endpoint.\n\n### Available Sidecar Endpoints\n\n| Chain | Endpoint Slug |\n|-------|---------------|\n| Polkadot | `api-polkadot-sidecar` |\n| Kusama | `api-kusama-sidecar` |\n| Asset Hub Polkadot | `api-asset-hub-polkadot-sidecar` |\n| Asset Hub Kusama | `api-asset-hub-kusama-sidecar` |\n| Centrifuge | `api-centrifuge-sidecar` |\n| KILT | `api-kilt-sidecar` |\n\n### Sidecar URL Format\n\n```\nhttps://api-{chain}-sidecar.n.dwellir.com/{API_KEY}\n```\n\n### Key Sidecar Routes\n\n| Route | Method | Description |\n|-------|--------|-------------|\n| `/blocks/head` | GET | Latest block with extrinsics and events |\n| `/blocks/{blockId}` | GET | Block by number or hash |\n| `/blocks/head/header` | GET | Latest block header only |\n| `/accounts/{accountId}/balance-info` | GET | Free, reserved, frozen balances |\n| `/accounts/{accountId}/staking-info` | GET | Staking status, nominations, rewards |\n| `/accounts/{accountId}/staking-payouts` | GET | Staking payout history |\n| `/accounts/{accountId}/vesting-info` | GET | Vesting schedules |\n| `/pallets/{palletId}/storage` | GET | List storage items for pallet |\n| `/pallets/{palletId}/storage/{storageItemId}` | GET | Specific storage value |\n| `/pallets/{palletId}/errors` | GET | Pallet error definitions |\n| `/pallets/{palletId}/constants` | GET | Pallet constants |\n| `/transaction/fee-estimate` | POST | Estimate fee without submitting a transaction |\n| `/runtime/metadata` | GET | Full runtime metadata |\n| `/runtime/spec` | GET | Runtime spec version |\n| `/node/version` | GET | Node software version |\n| `/node/network` | GET | Network info (chain, peers) |\n\n### Sidecar Code Example\n\n```typescript\nconst SIDECAR_URL = `https://api-polkadot-sidecar.n.dwellir.com/${process.env.DWELLIR_API_KEY}`;\n\n// Get account balance\nconst response = await fetch(`${SIDECAR_URL}/accounts/${accountId}/balance-info`);\nconst balance = await response.json();\nconsole.log(`Free: ${balance.free}, Reserved: ${balance.reserved}`);\n\n// Get latest block\nconst blockResponse = await fetch(`${SIDECAR_URL}/blocks/head`);\nconst block = await blockResponse.json();\nconsole.log(`Block #${block.number}: ${block.extrinsics.length} extrinsics`);\n```\n\n## Best Practices\n\n1. **Use WebSocket** — Substrate chains are designed for persistent connections. WSS is more efficient than HTTP for multi-call workflows and required for subscriptions.\n\n2. **Cache metadata** — Runtime metadata is large (~500KB+). Cache it and only refresh on runtime upgrades (check `state_getRuntimeVersion`).\n\n3. **Handle runtime upgrades** — Substrate chains can upgrade at any block. Listen for `system.events` containing `system.CodeUpdated` to refresh metadata.\n\n4. **Use type registries** — `@polkadot/api` auto-detects types from metadata. For custom pallets, provide type definitions in the `ApiPromise.create({ types: {...} })` call.\n\n5. **Batch storage queries** — Use `api.query.*.multi()` or `api.queryMulti()` instead of individual queries to reduce round trips.\n\n6. **Watch finalized blocks** — For reliable data, subscribe to `chain_subscribeFinalizedHeads` rather than `chain_subscribeNewHeads`. Finalized blocks are guaranteed not to be reverted.\n\n7. **Clean up subscriptions** — Always call the unsubscribe function returned by subscription methods to avoid resource leaks.\n\n8. **Use Sidecar for REST needs** — If your application prefers REST over WebSocket, use the Sidecar add-on instead of wrapping JSON-RPC calls.\n\n## Documentation Links\n\n- Polkadot docs: [dwellir.com/docs/polkadot](https://www.dwellir.com/docs/polkadot)\n- Kusama docs: [dwellir.com/docs/kusama](https://www.dwellir.com/docs/kusama)\n- Moonbeam docs: [dwellir.com/docs/moonbeam](https://www.dwellir.com/docs/moonbeam)\n- Acala docs: [dwellir.com/docs/acala](https://www.dwellir.com/docs/acala)\n- Astar docs: [dwellir.com/docs/astar](https://www.dwellir.com/docs/astar)\n- @polkadot/api docs: [polkadot.js.org/docs/api](https://polkadot.js.org/docs/api)\n- Substrate JSON-RPC spec: [paritytech.github.io/json-rpc-interface-spec](https://paritytech.github.io/json-rpc-interface-spec)\n- Sidecar docs: [paritytech.github.io/substrate-api-sidecar/dist](https://paritytech.github.io/substrate-api-sidecar/dist)\n"},"changes":[],"summary":"First saved snapshot. No earlier version is available for comparison.","summary_kind":"deterministic","summary_metadata":{}}