Skip to content

Dedot is a next-generation JavaScript client for Polkadot and Polkadot SDK-based blockchains. Designed to elevate the dApp development experience, Dedot is built and optimized to be lightweight and tree-shakable, offering precise types and APIs suggestions for individual Polkadot SDK-based blockchains.

  • Lightweight and tree-shakable: No more bn.js or WebAssembly blobs, optimized for dapps bundle size.
  • Fully typed API: Comprehensive TypeScript support for seamless on-chain interaction.
  • Multi-version JSON-RPC support: Compatible with both legacy and new JSON-RPC APIs for broad ecosystem interoperability.
  • Light client support: Designed to work with light clients such as Smoldot.
  • Native TypeScript for scale codec: Implements scale codec parsing directly in TypeScript without relying on custom wrappers.
  • Wallet integration: Works out-of-the-box with @polkadot/extension-based wallets.
  • Familiar API design: Similar API style to Polkadot.js for easy and fast migration.

To add Dedot to your project, use the following command:

Terminal window
npm i dedot

To enable auto-completion/IntelliSense for individual chains, install the @dedot/chaintypes package as a development dependency:

Terminal window
npm i -D @dedot/chaintypes

To connect to and interact with different networks, Dedot provides two client options depending on your needs:

Use the following snippets to connect to Polkadot using DedotClient:

import { DedotClient, WsProvider } from 'dedot';
import type { PolkadotApi } from '@dedot/chaintypes';
// Initialize providers & clients
const provider = new WsProvider('wss://rpc.polkadot.io');
const client = await DedotClient.new<PolkadotApi>(provider);

If the node doesn't support new JSON-RPC APIs yet, you can connect to the network using the LegacyClient, which is built on top of the legacy JSON-RPC APIs.

import { LegacyClient, WsProvider } from 'dedot';
import type { PolkadotApi } from '@dedot/chaintypes';
const provider = new WsProvider('wss://rpc.polkadot.io');
const client = await LegacyClient.new<PolkadotApi>(provider);

It is recommended to specify the ChainApi interface (e.g., PolkadotApi in the example in the previous section) of the chain you want to interact with. This enables type and API suggestions/autocompletion for that particular chain (via IntelliSense). If you don't specify a ChainApi interface, a default SubstrateApi interface will be used.

import { DedotClient, WsProvider } from 'dedot';
import type { PolkadotApi, KusamaApi } from '@dedot/chaintypes';
const polkadotClient = await DedotClient.new<PolkadotApi>(
new WsProvider('wss://rpc.polkadot.io')
);
const kusamaClient = await DedotClient.new<KusamaApi>(
new WsProvider('wss://kusama-rpc.polkadot.io')
);
const genericClient = await DedotClient.new(
new WsProvider('ws://localhost:9944')
);

If you don't find the ChainApi for the network you're working with in the list, you can generate the ChainApi (types and APIs) using the built-in dedot cli.

Terminal window
# Generate ChainApi interface for Polkadot network via rpc endpoint: wss://rpc.polkadot.io
npx dedot chaintypes -w wss://rpc.polkadot.io

Or open a pull request to add your favorite network to the @dedot/chaintypes repo.

Dedot provides several ways to read data from the chain:

  • Access runtime constants: Use the syntax client.consts.<pallet>.<constantName> to inspect runtime constants (parameter types).

    const ss58Prefix = client.consts.system.ss58Prefix;
    console.log('Polkadot ss58Prefix:', ss58Prefix);
  • Storage queries: Use the syntax client.query.<pallet>.<storgeEntry> to query on-chain storage.

    const balance = await client.query.system.account('INSERT_ADDRESS');
    console.log('Balance:', balance.data.free);
  • Subscribe to storage changes:

    const unsub = await client.query.system.number((blockNumber) => {
    console.log(`Current block number: ${blockNumber}`);
    });
  • Call Runtime APIs: Use the syntax client.call.<runtimeApi>.<methodName> to execute Runtime APIs.

    const metadata = await client.call.metadata.metadataAtVersion(15);
    console.log('Metadata V15', metadata);
  • Watch on-chain events: Use the syntax client.events.<pallet>.<eventName> to access pallet events.

    const unsub = await client.events.system.NewAccount.watch((events) => {
    console.log('New Account Created', events);
    });

Sign the transaction using IKeyringPair from Keyring (@polkadot/keyring) and send the transaction.

import { cryptoWaitReady } from '@polkadot/util-crypto';
import { Keyring } from '@polkadot/keyring';
// Setup keyring
await cryptoWaitReady();
const keyring = new Keyring({ type: 'sr25519' });
const alice = keyring.addFromUri('//Alice');
// Send transaction
const unsub = await client.tx.balances
.transferKeepAlive('INSERT_DEST_ADDRESS', 2_000_000_000_000n)
.signAndSend(alice, async ({ status }) => {
console.log('Transaction status', status.type);
if (status.type === 'BestChainBlockIncluded') {
console.log(`Transaction is included in best block`);
}
if (status.type === 'Finalized') {
console.log(
`Transaction completed at block hash ${status.value.blockHash}`
);
await unsub();
}
});

You can also use Signer from wallet extensions:

const injected = await window.injectedWeb3['polkadot-js'].enable('My dApp');
const account = (await injected.accounts.get())[0];
const signer = injected.signer;
const unsub = await client.tx.balances
.transferKeepAlive('INSERT_DEST_ADDRESS', 2_000_000_000_000n)
.signAndSend(account.address, { signer }, async ({ status }) => {
console.log('Transaction status', status.type);
if (status.type === 'BestChainBlockIncluded') {
console.log(`Transaction is included in best block`);
}
if (status.type === 'Finalized') {
console.log(
`Transaction completed at block hash ${status.value.blockHash}`
);
await unsub();
}
});

For more detailed information about Dedot, check the official documentation.

Last updated: