import { type Extrinsic, Metadata, PortableRegistry } from '@dedot/codecs'; import { ConnectionStatus, JsonRpcProvider } from '@dedot/providers'; import { Callback, ChainSubmittableExtrinsic, GenericStorageQuery, GenericSubstrateApi, InjectedSigner, IRuntimeTxCall, ISubmittableResult, Query, QueryFnResult, RpcVersion, TxUnsub, Unsub } from '@dedot/types'; import { HexString } from '@dedot/utils'; import { SubstrateApi } from '../chaintypes/index.js'; import { ApiEvent, ApiOptions, BlockExplorer, ISubstrateClient, ISubstrateClientAt, SubstrateRuntimeVersion, IChainSpec, type EventHandlerFn } from '../types.js'; /** * Configuration options for DedotClient */ export type ClientOptions = ApiOptions & { /** * The JSON-RPC version to use. * * - _unset_ (default): auto-detect. Try JSON-RPC v2 first and transparently fall back * to legacy if the connected node does not expose v2 methods (no `chainHead_*`). * After `connect()` resolves, `client.rpcVersion` reflects the version that was picked. * - `'v2'`: force JSON-RPC v2. Throws `JsonRpcV2NotSupportedError` during `connect()` * if the node does not support v2. * - `'legacy'`: force legacy JSON-RPC. */ rpcVersion?: RpcVersion; }; /** * @name DedotClient * @description The main entry point for interacting with PolkadotSDK-based blockchains. * * DedotClient is a facade that provides a unified API for both JSON-RPC v2 (default) and legacy * JSON-RPC versions. * * @example * ```typescript * import { DedotClient, WsProvider } from 'dedot'; * import type { PolkadotApi } from '@dedot/chaintypes/polkadot'; * * // Create and connect to a Polkadot node * const provider = new WsProvider('wss://rpc.polkadot.io'); * const client = await DedotClient.new(provider); * * // Get the current best block * const bestBlock = await client.block.best(); * console.log('Best block:', bestBlock.number, bestBlock.hash); * * // Subscribe to finalized blocks * const unsub = client.block.finalized((block) => { * console.log('Finalized:', block.number); * }); * * // Query on-chain storage * const balance = await client.query.system.account('14...'); * console.log('Balance:', balance); * * // Subscribe to runtime upgrades * const unsub = client.on('runtimeUpgraded', (version, block) => { * console.log('Runtime upgraded to:', version.specVersion, 'at block:', block.number); * }); * * // Sending transactions * await client.tx.balances.transferKeepAlive('15...', 1000000000000n) * .signAndSend(signer) * .untilFinalized(); * * // Disconnect when done * await client.disconnect(); * ``` * * @template ChainApi - Chain-specific API type for type-safe interactions (defaults to SubstrateApi) */ export declare class DedotClient implements ISubstrateClient { #private; /** * The JSON-RPC version being used ('v2' or 'legacy'). * * In auto-detect mode (no `rpcVersion` option), this is resolved during `connect()`. */ rpcVersion: RpcVersion; /** * Creates a new DedotClient instance. * * Use factory methods (`create`, `new`, `legacy`) for automatic connection. * * @param options - Client configuration options or a JsonRpcProvider instance */ constructor(options: ClientOptions | JsonRpcProvider); /** * Factory method to create and connect a new DedotClient instance. * * @param options - Client configuration options or a JsonRpcProvider instance * @returns A connected DedotClient instance * * @example * ```typescript * const client = await DedotClient.create({ * provider: new WsProvider('wss://rpc.polkadot.io'), * }); * ``` */ static create(options: ClientOptions | JsonRpcProvider): Promise>; /** * Alias for `DedotClient.create` * * @param options - Client configuration options or a JsonRpcProvider instance * @returns A connected DedotClient instance */ static new(options: ClientOptions | JsonRpcProvider): Promise>; /** * Factory method to create a DedotClient using legacy JSON-RPC. * * This is a convenience method that automatically sets `rpcVersion: 'legacy'`. * * @param options - Client configuration options or a JsonRpcProvider instance * @returns A connected DedotClient instance using legacy JSON-RPC * * @example * ```typescript * const client = await DedotClient.legacy({ * provider: new WsProvider('wss://rpc.polkadot.io'), * }); * ``` */ static legacy(options: ClientOptions | JsonRpcProvider): Promise>; /** The API configuration options */ get options(): ApiOptions; /** Current connection status */ get status(): ConnectionStatus; /** The underlying JSON-RPC provider */ get provider(): JsonRpcProvider; /** Transaction builder for submitting extrinsics */ get tx(): ChainApi['tx']; /** Raw JSON-RPC method access */ get rpc(): ChainApi['rpc']; /** The genesis hash of the connected chain */ get genesisHash(): HexString; /** Current runtime version information */ get runtimeVersion(): SubstrateRuntimeVersion; /** The chain metadata */ get metadata(): Metadata; /** Type registry for encoding/decoding chain types */ get registry(): PortableRegistry; /** * Access to pallet constants. * * @example * ```typescript * const existentialDeposit = client.consts.balances.existentialDeposit; * const ss58Prefix = client.consts.system.ss58Prefix; * ``` */ get consts(): ChainApi['consts']; /** * Storage query interface for reading on-chain state. * * @example * ```typescript * // One-time query * const account = await client.query.system.account(address); * * // Subscribe to storage changes * const unsub = await client.query.system.number((blockNumber) => { * console.log('Current block:', blockNumber); * }); * ``` */ get query(): ChainApi['query']; /** * Runtime API call interface. * * @example * ```typescript * const rawMetadata = await client.call.metadata.metadataAtVersion(16); * const version = await client.call.core.version(); * ``` */ get call(): ChainApi['call']; /** * Event type definitions and utilities. * * @example * ```typescript * // Check if an event matches a specific type * if (client.events.balances.Transfer.is(event)) { * console.log('Transfer event:', event.data); * } * ``` */ get events(): ChainApi['events']; /** * Error type definitions and utilities. * * @example * ```typescript * // Check if an error matches a specific type * if (client.errors.balances.InsufficientBalance.is(dispatchError)) { * console.log('Insufficient balance error'); * } * ``` */ get errors(): ChainApi['errors']; /** * View functions interface (requires Metadata V16+). * * @example * ```typescript * // Call a view function * const result = await client.view.voterList.scores(ALICE_ADDRESS); * ``` */ get view(): ChainApi['view']; /** * Block explorer interface for accessing block data. * * Provides methods to get/subscribe to best and finalized blocks, * as well as retrieve block headers and bodies. * * @example * ```typescript * // Get the current best block * const bestBlock = await client.block.best(); * console.log('Best block:', bestBlock.number, bestBlock.hash); * * // Subscribe to finalized blocks * const unsub = client.block.finalized((block) => { * console.log('Finalized block:', block.number); * }); * * // Get block header and body * const header = await client.block.header(blockHash); * const body = await client.block.body(blockHash); * ``` */ get block(): BlockExplorer; /** * Chain specification interface for accessing chain information. * * Provides methods to get chain name, genesis hash, and chain properties. * * @example * ```typescript * const chainName = await client.chainSpec.chainName(); * const genesisHash = await client.chainSpec.genesisHash(); * const properties = await client.chainSpec.properties(); * * console.log(`Connected to ${chainName}`); * console.log('Token symbol:', properties.tokenSymbol); * console.log('Token decimals:', properties.tokenDecimals); * ``` */ get chainSpec(): IChainSpec; /** * Establishes connection to the blockchain network. * * When `rpcVersion` was not specified, this tries JSON-RPC v2 first and * transparently falls back to legacy if the node does not support v2. * * @returns This client instance for method chaining */ connect(): Promise; /** * Closes the connection to the blockchain network. */ disconnect(): Promise; /** * Subscribe to client events. * * @param event - The event to listen for ('ready', 'connected', 'disconnected', 'reconnecting', 'runtimeUpgraded', 'error') * @param handler - Callback function to handle the event * @returns Unsubscribe function */ on(event: Event, handler: EventHandlerFn): () => void; /** * Subscribe to a client event once. * * @param event - The event to listen for * @param handler - Callback function to handle the event * @returns Unsubscribe function */ once(event: Event, handler: EventHandlerFn): () => void; /** * Unsubscribe from client events. * * @param event - The event to unsubscribe from * @param handler - The handler function to remove (optional, removes all handlers if not provided) * @returns This client instance for method chaining */ off(event: Event, handler?: EventHandlerFn): this; /** * Get a client instance at a specific block hash. * * This allows querying historical state at a specific block. * * @template ChainApiAt - Chain API type for the historical state (defaults to ChainApi) * @param hash - The block hash to query at * @returns A client instance for querying state at the specified block * * @example * ```typescript * const clientAtBlock = await client.at('0x1234...'); * const historicalBalance = await clientAtBlock.query.system.account('14...'); * ``` */ at(hash: `0x${string}`): Promise>; /** * Get the current runtime version with metadata sync. * * Unlike the `runtimeVersion` getter, this method ensures the corresponding * metadata for the runtime version is downloaded and set up. Useful for * preparing for runtime upgrades. * * @returns The current runtime version */ getRuntimeVersion(): Promise; /** * Set or update the signer instance for signing transactions. * * @param signer - The signer instance (or undefined to clear) */ setSigner(signer?: InjectedSigner | undefined): void; /** * Query multiple storage items in a single call or subscribe to multiple storage items. * * @example * ```typescript * // One-time query * const [balance, blockNumber] = await client.queryMulti([ * { fn: client.query.system.account, args: [ALICE] }, * { fn: client.query.system.number, args: [] } * ]); * * // Subscription * const unsub = await client.queryMulti([ * { fn: client.query.system.account, args: [ALICE] }, * { fn: client.query.system.number, args: [] } * ], ([balance, blockNumber]) => { * console.log('Balance:', balance, 'Block:', blockNumber); * }); * ``` * * @template Fns - Array of storage query functions * @param queries - Array of query specifications with function and arguments * @param callback - Optional callback for subscription mode * @returns Query results array, or unsubscribe function if callback provided */ queryMulti(queries: { [K in keyof Fns]: Query; }): Promise<{ [K in keyof Fns]: QueryFnResult; }>; queryMulti(queries: { [K in keyof Fns]: Query; }, callback: Callback<{ [K in keyof Fns]: QueryFnResult; }>): Promise; /** * Broadcast a transaction to the network and track its status. * * @param tx - The transaction (hex string or Extrinsic instance) * @param callback - Optional callback for transaction status updates * @returns TxUnsub object with utility methods (`.untilFinalized()`, `.untilBestChainBlockIncluded()`) * * @example * ```typescript * // Wait for finalization * const result = await client.sendTx(txHex).untilFinalized(); * * // With status callback to track progress * const unsub = await client.sendTx(txHex, (result) => { * console.log('Status:', result.status); * if (result.dispatchError) { * console.error('Transaction failed:', result.dispatchError); * } * }); * ``` */ sendTx(tx: HexString | Extrinsic, callback?: Callback>): TxUnsub; /** * Convert a transaction input into a submittable extrinsic * with `sign`, `signAndSend`, `send`, and `paymentInfo` methods. * * @param tx - A hex-encoded extrinsic or runtime call, a Uint8Array of encoded bytes, * an Extrinsic instance, or an IRuntimeTxCall object. * For HexString/Uint8Array, it first tries to decode as a full extrinsic; * if that fails, it falls back to decoding as a raw runtime call. * @returns A submittable extrinsic instance * * @example * ```typescript * // From a raw hex extrinsic * const submittable = client.toTx(rawTxHex); * * // From a runtime call object * const submittable = client.toTx({ pallet: 'Balances', palletCall: { name: 'TransferKeepAlive', params: { dest, value } } }); * * // Sign and send * const unsub = await submittable.signAndSend(alice, (result) => { * console.log('Status:', result.status); * }); * ``` */ toTx(tx: HexString | Uint8Array | Extrinsic | IRuntimeTxCall): ChainSubmittableExtrinsic; /** * Clear internal caches. * * @param keepMetadataCache - If true, preserves the metadata cache (default: false) */ clearCache(keepMetadataCache?: boolean): Promise; }