<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Ross Bulat - Software Engineer Building Decentralized &amp; Intelligent Systems Blog</title>
        <link>https://rossbulat.com/polkadot</link>
        <description>Ross Bulat - Software Engineer Building Decentralized &amp; Intelligent Systems Blog</description>
        <lastBuildDate>Sun, 29 Jun 2025 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <item>
            <title><![CDATA[Polkadot Cloud Staking Journey and JS Apps Staking Sunset Steps]]></title>
            <link>https://rossbulat.com/polkadot/staking-journey-js-apps-staking-sunset</link>
            <guid>https://rossbulat.com/polkadot/staking-journey-js-apps-staking-sunset</guid>
            <pubDate>Sun, 29 Jun 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Since launching in 2023, the Polkadot Staking Dashboard has grown from a user-friendly alternative to Polkadot JS Apps into the flagship staking interface for the ecosystem. This article reflects on that journey, the architectural breakthroughs, and the path toward sunsetting JS Apps Staking entirely.]]></description>
            <content:encoded><![CDATA[<p>Since launching in 2023, the <a href="https://staking.polkadot.cloud/" target="_blank" rel="noopener noreferrer" class="">Polkadot Staking Dashboard</a> has grown from a user-friendly alternative to Polkadot JS Apps into the flagship staking interface for the ecosystem. This article reflects on that journey, the architectural breakthroughs, and the path toward sunsetting JS Apps Staking entirely.</p>
<!-- -->
<p>In 2025, we undertook a major architectural evolution of the dashboard, abstracting its codebase to be fully network-agnostic while integrating cutting-edge APIs for seamless multi-chain support. This strategic shift enabled us to achieve:</p>
<ul>
<li class="">
<p><strong>Scalable, lightweight Staking API:</strong> Designed to handle complex queries beyond the capabilities of the node itself—such as historical reward data, era exposure checks for fast unstaking status, and other intensive operations.</p>
</li>
<li class="">
<p><strong>Dedot API integration:</strong> Integrated the Dedot API—the next-generation JavaScript client for Substrate-based chains—positioned as the modern successor to the Polkadot JS API for improved performance, maintainability, and developer experience.</p>
</li>
<li class="">
<p><strong>Multi-network NPoS support:</strong> Enabled both the Staking Dashboard and Staking API to seamlessly support any network implementing Nominated Proof of Stake (NPoS), ensuring broad compatibility across the Polkadot ecosystem and beyond.</p>
</li>
</ul>
<p>The Staking Dashboard has also maintained its pro-collaboration stance in a number of ways, including the ability to be fully functional even when the Staking API is disabled, allowing networks to onboard themselves to the staking dashboard before support rolls out on the Staking API side.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="journey-of-the-staking-dashboard">Journey of the Staking Dashboard<a href="https://rossbulat.com/polkadot/staking-journey-js-apps-staking-sunset#journey-of-the-staking-dashboard" class="hash-link" aria-label="Direct link to Journey of the Staking Dashboard" title="Direct link to Journey of the Staking Dashboard" translate="no">​</a></h2>
<p>For the Staking Dashboard to replace the staking functionality in JS Apps, it must not only match JS Apps feature-for-feature but also surpass them in key areas so users feel compelled to switch.</p>
<p>Since its inception, the dashboard has aimed to deliver a cleaner, more user-friendly experience than JS Apps while maintaining the same commitment to unbiased design.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="problems-solved-on-initial-release">Problems Solved on Initial Release<a href="https://rossbulat.com/polkadot/staking-journey-js-apps-staking-sunset#problems-solved-on-initial-release" class="hash-link" aria-label="Direct link to Problems Solved on Initial Release" title="Direct link to Problems Solved on Initial Release" translate="no">​</a></h3>
<img src="https://rossbulat.com/img/2025-06-29-staking-journey-js-apps-staking-sunset/InitialRelease.png" alt="Initial Release">
<center><i>Ross presenting an early Staking Dashboard beta at Polkadot Decoded 2022</i></center>
<br>
<p>When the Staking Dashboard first launched, it set out to resolve key usability and accessibility issues that had long affected the experience on Polkadot JS Apps. Notable improvements included:</p>
<ul>
<li class="">
<p><strong>Guided staking setup:</strong> A step-by-step onboarding flow for nominators, featuring one-click optimal validator selection based on current network metrics—eliminating the guesswork and manual validator research required by JS Apps.</p>
</li>
<li class="">
<p><strong>Advanced validator discovery:</strong> A fast, paginated validator browser with powerful filters (e.g., commission, identity, active/inactive status), replacing the monolithic, slow-to-load validator list used in JS Apps that hindered discovery and comparison.</p>
</li>
<li class="">
<p><strong>First-class hardware wallet support:</strong> Direct integration and open-sourcing of support for Ledger devices and Polkadot Vault—pioneering secure offline staking. This foundation later expanded to include support for WalletConnect, making secure access more flexible across devices.</p>
</li>
<li class="">
<p><strong>Consistent and predictable UI:</strong> A refined, state-aware interface designed to keep the dashboard visually consistent across all usage scenarios, minimizing user confusion and interface surprises—especially when transitioning between states like bonding, nominating, and unbonding.</p>
</li>
</ul>
<p>These were fundamental improvements that the initial dashboard components were built around. The engineering model adopted was very much agile, with rapid iteration on ideas and receiving user feedback.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="problems-solved-mid-1x-cycle">Problems Solved Mid-1.x Cycle<a href="https://rossbulat.com/polkadot/staking-journey-js-apps-staking-sunset#problems-solved-mid-1x-cycle" class="hash-link" aria-label="Direct link to Problems Solved Mid-1.x Cycle" title="Direct link to Problems Solved Mid-1.x Cycle" translate="no">​</a></h3>
<img src="https://rossbulat.com/img/2025-06-29-staking-journey-js-apps-staking-sunset/MidCycleUpdates.png" alt="Mid-Cycle Updates">
<center><i>Ross presenting some mid-cycle updates to the Staking Dashboard at Polkadot Decoded 2023</i></center>
<br>
<p>As the codebase of the dashboard started to formalise, more enhancements were added to the UI that further improved the usability of the NPoS system, such as validator performance graphs that sit alongside each user’s nominations for users to see performances at a glance, and the deprecation of controller accounts.</p>
<p>This era involved continuous upgrades to the dashboard. I shared a number of updates to the community as dashboard updates were rolling out.</p>
<ul>
<li class="">
<p><strong><a href="https://github.com/polkadot-cloud/polkadot-staking-dashboard/releases/tag/v1.3.0" target="_blank" rel="noopener noreferrer" class="">1.3</a> (8 Apr 2024):</strong> Introduced the first dedicated Nomination Pool workflow: a new “Join Pool” canvas with batched pool-performance fetching, progress bars, and low-member-pool prioritisation. Added a “Start Nominating” wizard, extension disconnect flow, colour-polish, and multiple UX bug-fixes (e.g., search-bar and Polkagate-Snap issues).</p>
</li>
<li class="">
<p><strong><a href="https://github.com/polkadot-cloud/polkadot-staking-dashboard/releases/tag/v1.4.0" target="_blank" rel="noopener noreferrer" class="">1.4</a>: (18 Apr 2024):</strong> A mainly refactor &amp; hardening release: moved Ledger/Vault account handling to a network-parameterised API and replaced many low-level helpers with the shared @w3ux/utils library. It also patched free-balance display, search filters and pools unsubscription logic.</p>
</li>
<li class="">
<p><strong><a href="https://github.com/polkadot-cloud/polkadot-staking-dashboard/releases/tag/v1.6.0" target="_blank" rel="noopener noreferrer" class="">1.6</a> (1 Aug 2024)</strong>: Rolled out People Chain identity support, generic Ledger-app signing, and a “Nominee Decentralisation” insight showing how distributed a user’s nominations are. Under the hood it abstracted state bootstrapping, refreshed logos, and removed obsolete reward code, plus several Ledger and Vault fixes.</p>
</li>
<li class="">
<p><strong><a href="https://github.com/polkadot-cloud/polkadot-staking-dashboard/releases/tag/v1.7.0" target="_blank" rel="noopener noreferrer" class="">1.7</a> (8 Nov 2024)</strong>: Focused on UX polish and connectivity: brand refresh (new logo &amp; fonts), WalletConnect integration, lighter pool-item UI, and hook refactors (useSize, useTimeLeft, resize listener throttling removed). Also upgraded to the latest @w3ux utilities and fixed era-subscription and account bugs.</p>
</li>
<li class="">
<p><strong><a href="https://github.com/polkadot-cloud/polkadot-staking-dashboard/releases/tag/app-v1.8.0" target="_blank" rel="noopener noreferrer" class="">1.8</a> (16 Jan 2025)</strong>: Began the monorepo split (app, ui-core, ui-overlay, etc.) and shipped deep Staking API GraphQL integration: historical pool-rewards and nominator-rewards moved off Subscan, light-client now boots from WSS nodes only. Added a 100% commission warning, disabled dual-staking, and normalised titles/assets across packages.</p>
</li>
<li class="">
<p><strong><a href="https://x.com/rossbulat/status/1895036435293454785" target="_blank" rel="noopener noreferrer" class="">1.9</a> (27 Feb 2025)</strong>: Announced as “<em>faster, smarter, more rewarding</em>” — this release deepened Staking API hooks, unveiled an overhauled Rewards page with earnings projections, improved Ledger support, delivered initial WalletConnect v2 tweaks, and re-branded the project to Polkadot Cloud Staking.</p>
</li>
<li class="">
<p><strong><a href="https://x.com/rossbulat/status/1935161399292084699" target="_blank" rel="noopener noreferrer" class="">2.0</a> (18 June 2025)</strong>: Marketed as the biggest update to date, v2.0 pairs a re-engineered API layer with a fully-refined UX, resulting in lightning-fast data loading and smarter staking flows. It lays the groundwork for seamless multi-chain support and positions the dashboard as the reference staking front-end for the Polkadot ecosystem.</p>
</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-rocky-transition-to-polkadot-cloud">A Rocky Transition to Polkadot Cloud<a href="https://rossbulat.com/polkadot/staking-journey-js-apps-staking-sunset#a-rocky-transition-to-polkadot-cloud" class="hash-link" aria-label="Direct link to A Rocky Transition to Polkadot Cloud" title="Direct link to A Rocky Transition to Polkadot Cloud" translate="no">​</a></h3>
<p>In mid-2024 the Polkadot Staking Dashboard project faced some strong headwinds amid major structural changes within the Polkadot ecosystem:</p>
<ul>
<li class="">
<p><strong>Project migration:</strong> The Staking Dashboard transitioned from an internal Parity project to an independent one, moving from <code>paritytech/polkadot-staking-dashboard</code> to <code>polkadot-cloud/polkadot-staking-dashboard</code>.</p>
</li>
<li class="">
<p><strong>Funding shift:</strong> Ongoing funding for the project transitioned to OpenGov.</p>
</li>
<li class="">
<p><strong>Hosting migration:</strong> The application was moved from the official <code>polkadot.network</code> domain to its new home at <a href="https://polkadot.cloud/" target="_blank" rel="noopener noreferrer" class="">polkadot.cloud</a>.</p>
</li>
<li class="">
<p><strong>Landing page decommissioned:</strong> The former staking landing page on <code>polkadot.network</code> was taken offline, removing the primary entry point for new stakers on Polkadot.</p>
</li>
<li class="">
<p><strong>Team &amp; partnerships rebuilt:</strong> The original team structure and partnerships were reset, requiring a complete rebuild of the core team and collaborative relationships.</p>
</li>
</ul>
<p>While this period posed an existential threat to the Staking Dashboard, it also served as a catalyst for deep strategic reflection. It forced us to re-evaluate the dashboard’s long-term value within the ecosystem, ultimately paving the way for pivotal architectural and product decisions in the months that followed:</p>
<ul>
<li class="">
<p><strong>Reintegration of the dashboard into the Polkadot Cloud platform</strong>, strengthening its alignment with broader ecosystem goals.</p>
</li>
<li class="">
<p><strong>Exclusive reliance on the Dedot API</strong> for all node interactions, backed by a strong collaborative relationship with its core developers. We view Dedot as the future of JavaScript-based chain interactions—and it has proven flawless in execution thus far.</p>
</li>
<li class="">
<p><strong>Scalability through the Staking API</strong>, purpose-built to handle large-scale data requests via a high-performance GraphQL backend.</p>
</li>
<li class="">
<p><strong>Restructuring of the codebase into a monorepo workspace</strong>, improving modularity, separation of concerns, and enabling more robust testing practices.</p>
</li>
<li class="">
<p><strong>Complete re-architecture of the state and API layers</strong>, laying the foundation for seamless multi-network support beyond Polkadot, Kusama, and Westend.</p>
</li>
<li class="">
<p><strong>Expanded user support</strong>, with the introduction of Discord and email channels offering same-day responses to support inquiries.</p>
</li>
<li class="">
<p><strong>Agile to CI/CD development model</strong>, enabling rapid iteration and deployment of new features, bug fixes, and performance improvements, with additional inclusion of AI tools to assist with development and testing.</p>
</li>
</ul>
<p>Many of these ideas were integrated into the <a href="https://polkadot.polkassembly.io/referenda/1370" target="_blank" rel="noopener noreferrer" class="">Mid 2024 Staking Dashboard OpenGov proposal</a>, which have now all been implemented.</p>
<p>Despite the turbulence, the Staking Dashboard emerged stronger than ever and is now firmly positioned for long-term success. The launch of the new <a href="https://polkadot.cloud/stake" target="_blank" rel="noopener noreferrer" class="">Polkadot Cloud Staking</a> landing page marks a symbolic milestone—proof that we have overcome our challenges.</p>
<img src="https://rossbulat.com/img/2025-06-29-staking-journey-js-apps-staking-sunset/StakingLandingPage.png" alt="Staking Landing Page">
<center><i>The brand new landing page for Polkadot Cloud Staking, released in June 2025</i></center>
<br>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="staking-api-problems-solved">Staking API: Problems Solved<a href="https://rossbulat.com/polkadot/staking-journey-js-apps-staking-sunset#staking-api-problems-solved" class="hash-link" aria-label="Direct link to Staking API: Problems Solved" title="Direct link to Staking API: Problems Solved" translate="no">​</a></h3>
<p>The Staking API has become a core component of the Polkadot Staking Dashboard experience. Since the dashboard’s initial release, the Nominated Proof of Stake (NPoS) system has scaled significantly—introducing data volumes that make certain operations infeasible to handle through node interactions alone. Consider the following metrics:</p>
<ul>
<li class="">At launch, there were <strong>297 active validators per era</strong>. Today, that number has grown to <strong>600</strong>, with plans to expand further.</li>
<li class="">Previously, only a limited number of nominators per validator received rewards—totaling around <strong>21,500 rewarded nominators per era</strong>. Now, <strong>all nominators backing active validators are rewarded</strong>.</li>
<li class=""><strong>Era exposure chain state is now paginated</strong>, supporting a much larger number of exposures than before.</li>
<li class="">As of writing, there are <strong>over 38,000 nomination pool members</strong> participating across <strong>239 active pools on Polkadot</strong>. Handling such high-volume data is no longer practical within a front-end application alone.</li>
</ul>
<p>As NPoS continues to scale, some chain state now require indexing in optimised databases for fast querying - that is the role of the Staking API.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="staking-dashboard-20-and-beyond">Staking Dashboard 2.0 and Beyond<a href="https://rossbulat.com/polkadot/staking-journey-js-apps-staking-sunset#staking-dashboard-20-and-beyond" class="hash-link" aria-label="Direct link to Staking Dashboard 2.0 and Beyond" title="Direct link to Staking Dashboard 2.0 and Beyond" translate="no">​</a></h3>
<p>Each Staking Dashboard release raises the stakes for the Polkadot Cloud platform, and our 2.0 release was no different. Our biggest update yet achieved the following:</p>
<ul>
<li class="">
<p><strong>Dedot-first architecture</strong> – Polkadot JS API was removed entirely and replaced by a Dedot-powered “global-bus” layer, unifying all chain calls and dramatically reducing load times.</p>
</li>
<li class="">
<p><strong>True multi-currency display</strong> – balances, rewards and payouts can now be displayed in 27 fiat currencies.</p>
</li>
<li class="">
<p><strong>One-click pool &amp; nominator setup</strong> – revised onboarding flows let users bond, join a pool, or nominate a curated set of validators with a single action, replacing several manual steps.</p>
</li>
<li class="">
<p><strong>New “Quick Actions” &amp; expanded Overview</strong> – a context-aware action bar plus richer balance widgets put the most common tasks (bond, rebond, withdraw, etc.) one tap away.</p>
</li>
<li class="">
<p><strong>Nomination-pool invites &amp; smarter management UI</strong> – invite links, full-screen management, and simplified confirmation dialogs make pool coordination far easier.</p>
</li>
<li class="">
<p><strong>React 19 + UI overhaul</strong> – upgraded to React 19, introduced SimpleBar-based scrolling, canvas max-width controls, and a cleaner header with new Account/Settings pop-overs for a sleeker feel.</p>
</li>
<li class="">
<p><strong>Unified wallet &amp; hardware flows</strong> – Ledger, Polkadot Vault and WalletConnect are now handled by a single provider layer, streamlining account selection and signing.</p>
</li>
<li class="">
<p><strong>Light-client improvements</strong> – chain specs now come from <code>@substrate/connect-known-chains</code>, giving the embedded Smoldot client faster boot-strapping and broader chain coverage.</p>
</li>
<li class="">
<p><strong>Developer-experience boosts</strong> – the monorepo migrated from Yarn to PNPM and had its TS configs slimmed down, cutting build times and CI latency.</p>
</li>
</ul>
<p>With its latest additions, Polkadot Staking Dashboard is now in a position where we can entertain a complete sunset of JS Apps Staking.</p>
<img src="https://rossbulat.com/img/2025-06-29-staking-journey-js-apps-staking-sunset/HelloDedot.jpeg" alt="Staking API">
<center><i>Staking Dashboard 2.0 was released alongside a full rollout of the <a href="https://docs.dedot.dev/" target="_blank" rel="noopener noreferrer" class="">Dedot API</a></i></center>
<br>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="add-your-network-to-staking-dashboard">Add Your Network to Staking Dashboard<a href="https://rossbulat.com/polkadot/staking-journey-js-apps-staking-sunset#add-your-network-to-staking-dashboard" class="hash-link" aria-label="Direct link to Add Your Network to Staking Dashboard" title="Direct link to Add Your Network to Staking Dashboard" translate="no">​</a></h3>
<p>We actively encourage ecosystem teams to collaborate with us and integrate their networks into the Polkadot Cloud platform. Multi-network support is a key part of the dashboard’s future direction, and expanding coverage beyond Polkadot, Kusama, and Westend unlocks powerful new capabilities for users and developers alike.</p>
<p>As more networks are added, the dashboard will evolve into a unified interface for staking across the entire ecosystem—enabling features like cross-network statistics, aggregated staking rewards across multiple tokens, and a broader analytics layer that reflects the diversity of Substrate-based networks.</p>
<p>Integrating your network is a straightforward process, and we’re here to support each step:</p>
<ul>
<li class="">Add your <strong>network metadata</strong> to the supported networks list.</li>
<li class="">Include your <strong>chain icons</strong> in the dashboard’s static assets.</li>
<li class="">Provide a <strong>light client chain spec</strong> for Smoldot compatibility.</li>
<li class="">Configure <strong>CSS variables</strong> to enable a custom dashboard theme for your network.</li>
<li class="">Supply your <strong>Dedot API service</strong>, which defines all supported chain interactions and the required API instances.</li>
</ul>
<p>Once integrated, we can work closely with your team to extend support to the Staking API—unlocking full data scalability and enabling advanced features like historical reward tracking, high-volume querying, and performance insights tailored to your chain.</p>]]></content:encoded>
            <category>Polkadot</category>
            <category>Staking Dashboard</category>
            <category>Polkadot Cloud</category>
        </item>
        <item>
            <title><![CDATA[Staking Dashboard Dedot API Service Integration]]></title>
            <link>https://rossbulat.com/polkadot/dedot-api-service-integration</link>
            <guid>https://rossbulat.com/polkadot/dedot-api-service-integration</guid>
            <pubDate>Mon, 05 May 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[This post introduces a significant Polkadot Staking Dashboard refactor that addresses long-standing limitations. At the heart of this upgrade is a fully decoupled architecture and new infrastructure for managing chain state.]]></description>
            <content:encoded><![CDATA[<p>This post introduces a significant <a href="https://github.com/polkadot-cloud/polkadot-staking-dashboard" target="_blank" rel="noopener noreferrer" class="">Polkadot Staking Dashboard</a> refactor that addresses long-standing limitations. At the heart of this upgrade is a fully decoupled architecture and new infrastructure for managing chain state.</p>
<!-- -->
<p>The next-generation <a href="https://docs.dedot.dev/" target="_blank" rel="noopener noreferrer" class="">Dedot API</a> — a lightweight, high-performance Substrate client offering fully typed APIs in a compact bundle - has also been deeply integrated. This integration positions the dashboard as a production-ready reference implementation for teams looking to integrate Dedot into their own apps.</p>
<p>In this article, I'll outline the core problems addressed in the refactor, walk through the Dedot integration, and share the key design decisions that shaped this transformation.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="problems-solved">Problems Solved<a href="https://rossbulat.com/polkadot/dedot-api-service-integration#problems-solved" class="hash-link" aria-label="Direct link to Problems Solved" title="Direct link to Problems Solved" translate="no">​</a></h2>
<p>Heading into the "Polkadot Hub" era, otherwise known as "Plaza" or the "AssetHub Migration", Staking Dashboard has had to solve some fundamental problems to reposition it for this multi-chain setup:</p>
<ul>
<li class="">
<p><strong>Plaza Compatibility:</strong> Automatically routes staking queries based on whether a chain uses AssetHub or the Relay Chain — no manual config needed.</p>
</li>
<li class="">
<p><strong>Multi-Network Support (No Forking):</strong>  New networks can be added via config only, thanks to abstracted logic and metadata services — no need to fork the codebase.</p>
</li>
<li class="">
<p><strong>Fully Typed Chain State:</strong> Uses Dedot API with TypeScript generics to distinguish between chain types (Staking, Relay, People), enabling autocompletion and safer refactors.</p>
</li>
<li class="">
<p><strong>Global Chain State Management:</strong> Maintains app-wide chain state (e.g. active era, nominations) via API-layer subscriptions, reducing redundancy and improving UI responsiveness.</p>
</li>
<li class="">
<p><strong>Decoupled API from UI:</strong> Blockchain logic is isolated into services, allowing UI components to work across networks without assumptions about API structure.</p>
</li>
</ul>
<p>Solving these problems pave the way for more sophisticated features and network support, for example, a liquid staking feature that requires deep integtation away from the relay / system chains.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="dedot-api-integration">Dedot API Integration<a href="https://rossbulat.com/polkadot/dedot-api-service-integration#dedot-api-integration" class="hash-link" aria-label="Direct link to Dedot API Integration" title="Direct link to Dedot API Integration" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="project-structure">Project Structure<a href="https://rossbulat.com/polkadot/dedot-api-service-integration#project-structure" class="hash-link" aria-label="Direct link to Project Structure" title="Direct link to Project Structure" translate="no">​</a></h3>
<p>The <a href="https://github.com/polkadot-cloud/polkadot-staking-dashboard" target="_blank" rel="noopener noreferrer" class="">Polkadot Staking Dashboard</a> is a monorepo; a workspace of packages that comprise the application. This walkthrough focuses on 3 of these packages:</p>
<ul>
<li class="">
<p><a href="https://github.com/polkadot-cloud/polkadot-staking-dashboard/tree/main/packages/dedot-api" target="_blank" rel="noopener noreferrer" class="">dedot-api</a>: Contains all Dedot API logic, from connecting to a client, fetching chainspec, querying and submitting transactions.</p>
</li>
<li class="">
<p><a href="https://github.com/polkadot-cloud/polkadot-staking-dashboard/tree/main/packages/global-bus" target="_blank" rel="noopener noreferrer" class="">global-bus</a>: Responsible for storing state and making that state accessible workspace-wide via Rxjs subscriptions. The global bus decouples this state from the UI itself, and allows other packages to access or subscribe to its members.</p>
</li>
<li class="">
<p><a href="https://github.com/polkadot-cloud/polkadot-staking-dashboard/tree/main/packages/app" target="_blank" rel="noopener noreferrer" class="">app</a>: The main UI and React hierarchy of the dashboard. App contexts and components subscribe to global bus state, and update their own state with the data they require. This in-turn triggers re-renders when such data updates,</p>
</li>
</ul>
<p>Notably, this project structure completely decouples the <code>api</code> client, and app-wide state, from the UI side. The UI does not need to know anything about the Dedot API client itself, only the state that dictates what is displayed in the UI.</p>
<p>This setup allows an update cycle with clear separation of concerns.</p>
<p>The <code>dedot-api</code> package is responsible for connecting to, and handling everything node related. It also exposes an interface for the UI to query chain state and submit transactions. Upon network switching, it is also responsible for unsubscribing to active subscriptions and resetting state.  <code>dedot-api</code>  will be explored in more detail in the following sections.</p>
<p>Global bus simply holds observables along with utilities to manage them.  Staking Dashboard's <code>global-bus</code> forces all <code>BehaviorSubject</code>s to be private, but exposes getters &amp; setters to manage their state. To manage an API status, for example, the following utilities are defined:</p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// Staking Dashboard forces this to be private</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> _apiStatus </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">BehaviorSubject</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name">Record</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name builtin">string</span><span class="token class-name punctuation" style="color:#393A34">,</span><span class="token class-name"> ApiStatus</span><span class="token class-name operator" style="color:#393A34">&gt;&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// This is public and used by components to subscribe to</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> apiStatus$ </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> _apiStatus</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">asObservable</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// Getter: Gets the API status for a chain ID</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">getApiStatus</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">id</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  _apiStatus</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getValue</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">id</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'disconnected'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// Setter: Sets the API status for a given chain ID</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">setApiStatus</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">id</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> status</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> ApiStatus</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  _apiStatus</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">next</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token operator" style="color:#393A34">...</span><span class="token plain">_apiStatus</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getValue</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">id</span><span class="token punctuation" style="color:#393A34">]</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> status</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// Setter: Resets state to an empty record</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">resetApiStatus</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  _apiStatus</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">next</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>Storing state and providing utilities to manage such state is the only job of the global bus. The UI can use the global bus, as can the Dedot API package. The UI can leverage the global bus to set initial React state values, for example - this is especially useful if those initial values are derived from local storage. Dedot API on the other hand populates the global bus as it receives chain data.</p>
<p>As a simple mental modal, Dedot API provides data to the global bus, whereas the UI consumes that data. There are some exceptions to this based on user interaction, such as switching network.</p>
<p>Within the <code>app</code> itself, components simply subscribe to global bus observables and update their local state. This can be done in a <code>useEffect</code> hook that also handles unsubscribe logic on component unmount:</p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// Import observable from the global bus package</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> apiStatus$ from ‘global</span><span class="token operator" style="color:#393A34">-</span><span class="token plain">bus’</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// Subscribe to global bus within a component</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">useEffect</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> subApiStatus </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> apiStatus$</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">subscribe</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">result</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">setApiStatus</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">result</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    subApiStatus</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">unsubscribe</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<p>So with enough intuition to now understand how the app is functioning, let's dive into the <code>dedot-api</code> package itself and explore how it functions to serve multi-network, type-safe services.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="defining-network-services">Defining Network Services<a href="https://rossbulat.com/polkadot/dedot-api-service-integration#defining-network-services" class="hash-link" aria-label="Direct link to Defining Network Services" title="Direct link to Defining Network Services" translate="no">​</a></h3>
<p>The <code>dedot-api</code> package defines <strong>services</strong> that networks can implement. When implemented, services drive everything node-related, including:</p>
<ul>
<li class="">Initialising the node connection via WebSocket or light client</li>
<li class="">Boostrapping network data like fetching chain specs, ss58 prefix, existential deposit, and so on</li>
<li class="">Subscribing to required chain state and updating the global bus in real time</li>
<li class="">Exposing an interface the UI can call to fetch queries and submit transactions.</li>
</ul>
<p>The way a service is configured varies depending on how many chains are required on the network. At the time of writing, Staking Dashboard supports Polkadot, Kusama and Westend networks, and they all currently adhere to the same chain setup. Concretely, they all comprise:</p>
<ul>
<li class="">A Relay chain: Where all staking and validator data currently resides (pending AssetHub migration).</li>
<li class="">A People chain: Where identities are stored - required for displaying identities for stakers, validators and pool operators.</li>
</ul>
<p>With this in mind, we can implement one service, that I've called the <code>Default Service</code>, that connects to both of these chains for every network that implements it. This is done within the <code>initDedotService</code> function of the <code>dedot-api</code> package.</p>
<p>Let's take a look at how a default service is being instantiated (<a href="https://github.com/polkadot-cloud/polkadot-staking-dashboard/blob/main/packages/dedot-api/src/index.ts" target="_blank" rel="noopener noreferrer" class="">Source File</a>):</p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">network </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'westend'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> Service</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> apis</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> ids </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getDefaultService</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">network</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> rest</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  service </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Service</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cur</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> ids</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">...</span><span class="token plain">apis</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">network </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'kusama'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> Service</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> apis</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> ids </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getDefaultService</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">network</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> rest</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  service </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Service</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cur</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> ids</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">...</span><span class="token plain">apis</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">network </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'polkadot'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> Service</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> apis</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> ids </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getDefaultService</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">network</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> rest</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  service </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Service</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cur</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> ids</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">...</span><span class="token plain">apis</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>Although simple and perhaps tedius looking upon first look, these conditional statements and initialisations are doing quite a bit of work:</p>
<ul>
<li class="">They allow us to call different service initialisers depending on the active network. We currently only require the default service (that provides a Relay chain and People chain api), but more services could be implemented, such as for solo-chain networks.</li>
<li class="">The service class itself is returned, along with the instantiated Dedot API clients, and the chain IDs of those clients.</li>
<li class=""><strong>The conditionals are ensuring type-safety, by narrowing down the <em>chain types</em> of the initialised API clients.</strong> Note how we instantiate <code>service</code> within each conditional - this is ensuring that <code>service</code> is type-narrowed to the correct chain types.</li>
</ul>
<p>This last point is crucially important for type safety. <code>getDefaultService</code> is a generic function with the following signature:</p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">getDefaultService</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">T</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name">NetworkId</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  network</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> rpcEndpoints</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> providerType </span><span class="token punctuation" style="color:#393A34">}</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> NetworkConfig</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token builtin">Promise</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">DefaultService</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">T</span><span class="token operator" style="color:#393A34">&gt;&gt;</span><br></span></code></pre></div></div>
<p>So <code>T</code> is dictating which network we're providing a service for, and ultimately which chain types are being returned for the Dedot clients.</p>
<p>If we delve into the actual return types of <code>DefaultService</code>, we can see that the service class itself is being returned (services for each supported network are defined <a href="https://github.com/polkadot-cloud/polkadot-staking-dashboard/tree/main/packages/dedot-api/src/services" target="_blank" rel="noopener noreferrer" class="">here</a>), along with type-safe Dedot Clients - the clients we use for <code>api.query</code>, <code>api.tx</code>, etc.</p>
<p>With these chain types provided, the entire chain metadata is now type-safe and intellisense-ready. Finally, <code>ids</code> simply provides strings of the provided client ids. The following types break down the return type of <code>getDefaultService</code>:</p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">DefaultService</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name constant" style="color:#36acaa">T</span><span class="token class-name"> </span><span class="token class-name keyword" style="color:#00009f">extends</span><span class="token class-name"> </span><span class="token class-name keyword" style="color:#00009f">keyof</span><span class="token class-name"> ServiceType</span><span class="token class-name operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  Service</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> ServiceType</span><span class="token punctuation" style="color:#393A34">[</span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  apis</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">DedotClient</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">Service</span><span class="token punctuation" style="color:#393A34">[</span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> DedotClient</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">Service</span><span class="token punctuation" style="color:#393A34">[</span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">]</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  ids</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">NetworkId</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> SystemChainId</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token class-name">ServiceType</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  polkadot</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">typeof</span><span class="token plain"> PolkadotService</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  kusama</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">typeof</span><span class="token plain"> KusamaService</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  westend</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">typeof</span><span class="token plain"> WestendService</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  KusamaApi</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  PolkadotApi</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  WestendApi</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token operator" style="color:#393A34">...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'@dedot/chaintypes'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">Service</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  polkadot</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">PolkadotApi</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> PolkadotPeopleApi</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  kusama</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">KusamaApi</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> KusamaPeopleApi</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  westend</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">WestendApi</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> WestendPeopleApi</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>With API clients now initialised with the required service class, <code>initDedotService</code> now simply exposes its public interface via <code>global-bus</code> and starts the service, beginning its bootstrapping of chain state and subscriptions:</p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// Expose service interface via global bus</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">setServiceInterface</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">service</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">interface</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// Start the service</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> service</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">start</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="defining-dedot-api-clients">Defining Dedot API Clients<a href="https://rossbulat.com/polkadot/dedot-api-service-integration#defining-dedot-api-clients" class="hash-link" aria-label="Direct link to Defining Dedot API Clients" title="Direct link to Defining Dedot API Clients" translate="no">​</a></h3>
<p>So far we've been discussing service bootstrapping without mentioning the <a href="https://www.npmjs.com/package/dedot" target="_blank" rel="noopener noreferrer" class=""><code>dedot</code></a> or <a href="https://www.npmjs.com/package/@dedot/chaintypes" target="_blank" rel="noopener noreferrer" class=""><code>@dedot/chaintypes</code></a> packages. For developers accustomed to using Polkadot JS API, Initialising Dedot Clients will look familiar. A standard websocket provider api &amp; client initialisation looks like the following:</p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> WsProvider </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'dedot'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> PolkadotApi </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'@dedot/chaintypes'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> provider </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">WsProvider</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'wss://rpc.polkadot.io'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> client </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> DedotClient</span><span class="token punctuation" style="color:#393A34">.</span><span class="token generic-function function" style="color:#d73a49">new</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name">PolkadotApi</span><span class="token generic-function generic class-name operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">provider</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p>One notable difference here is that the <code>PolkadotApi</code> interface is being imported and assigned to the Dedot Client initialiser's type parameter. This interface is known as a <em>chain type</em>, which types the entire  <code>client</code> interface. With chain types being pure TypeScript, app bundle sizes are not affected, and intellisense within your IDE becomes available. Dedot's Chaintypes contributed to making the solution this article is discussing possible.</p>
<p>For more information about getting started with Dedot, visit the <a href="https://docs.dedot.dev/" target="_blank" rel="noopener noreferrer" class="">official docs</a>.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="implementing-a-default-service">Implementing a Default Service<a href="https://rossbulat.com/polkadot/dedot-api-service-integration#implementing-a-default-service" class="hash-link" aria-label="Direct link to Implementing a Default Service" title="Direct link to Implementing a Default Service" translate="no">​</a></h3>
<p>To understand the basic structure of the Default Service, we can look at the abstract class each default service must implement. <code>DefaultServiceClass</code> (<a href="https://github.com/polkadot-cloud/polkadot-staking-dashboard/blob/main/packages/dedot-api/src/types/serviceDefault.ts" target="_blank" rel="noopener noreferrer" class="">Source Code</a>) defines the type parameters and class members each default service must implement.</p>
<p>Three generic parameters are defined in this class definition:</p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">abstract</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">DefaultServiceClass</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name"></span><br></span><span class="token-line" style="color:#393A34"><span class="token class-name">  RelayApi </span><span class="token class-name keyword" style="color:#00009f">extends</span><span class="token class-name"> RelayChain</span><span class="token class-name punctuation" style="color:#393A34">,</span><span class="token class-name"></span><br></span><span class="token-line" style="color:#393A34"><span class="token class-name">  PeopleApi </span><span class="token class-name keyword" style="color:#00009f">extends</span><span class="token class-name"> PeopleChain</span><span class="token class-name punctuation" style="color:#393A34">,</span><span class="token class-name"></span><br></span><span class="token-line" style="color:#393A34"><span class="token class-name">  StakingApi </span><span class="token class-name keyword" style="color:#00009f">extends</span><span class="token class-name"> StakingChain</span><span class="token class-name punctuation" style="color:#393A34">,</span><span class="token class-name"></span><br></span><span class="token-line" style="color:#393A34"><span class="token class-name"></span><span class="token class-name operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name">ServiceClass</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token operator" style="color:#393A34">...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>These <a href="https://github.com/polkadot-cloud/polkadot-staking-dashboard/blob/b227c2ef82b6c721ad1328717a97a8a3b9e2d34c/packages/dedot-api/src/types/index.ts#L17" target="_blank" rel="noopener noreferrer" class="">parameters</a> are simply unions that categorise chains into specific groups:</p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">//  A union of the relay chain types</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">RelayChain</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> PolkadotApi </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> KusamaApi </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> WestendApi</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//  A union of the people chain types</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">RelayChain</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> PolkadotPeopleApi </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> KusamaPeopleApi </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> WestendPeopleApi</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// A union of the chain types that staking resides on</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// NOTE: These will change when staking is migrated to AssetHub</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">StakingChain</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> PolkadotApi </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> KusamaApi </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> WestendApi</span><br></span></code></pre></div></div>
<p><code>DefaultServiceClass</code> expects a chain type for a <strong>Relay chain</strong>, a <strong>People chain</strong>, and a <strong>staking chain</strong> (the chain on which staking and nomination pools reside). Note that there can be overlap here - the class simply needs knowledge of which chain types to use.</p>
<p>So for the <a href="https://github.com/polkadot-cloud/polkadot-staking-dashboard/blob/main/packages/dedot-api/src/services/polkadot.ts" target="_blank" rel="noopener noreferrer" class="">Polkadot service</a>,  we can implement this class with the <code>PolkadotApi</code> chain type, satisfying the Relay chain and Staking chain, and <code>PolkadotPeopleApi</code> as the People chain type.</p>
<p>Within the service implementation, these types can then be assigned to subscriptions, queries, and transactions.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="implementing-the-polkadot-service">Implementing the Polkadot Service<a href="https://rossbulat.com/polkadot/dedot-api-service-integration#implementing-the-polkadot-service" class="hash-link" aria-label="Direct link to Implementing the Polkadot Service" title="Direct link to Implementing the Polkadot Service" translate="no">​</a></h3>
<p><code>PolkadotService</code> implements <code>DefaultServiceClass</code> with <code>PolkadotApi</code> and <code>PolkadotPeopleApi</code>. These chain types are then passed into each query and each subscription within the service:</p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> PolkadotApi </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'@dedot/chaintypes/polkadot'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> PolkadotPeopleApi </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'@dedot/chaintypes/polkadot-people'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">PolkadotService</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">implements</span><span class="token plain"> </span><span class="token class-name">DefaultServiceClass</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name"></span><br></span><span class="token-line" style="color:#393A34"><span class="token class-name">    </span><span class="token class-name comment" style="color:#999988;font-style:italic">// Relay Chain</span><span class="token class-name"></span><br></span><span class="token-line" style="color:#393A34"><span class="token class-name">    PolkadotApi</span><span class="token class-name punctuation" style="color:#393A34">,</span><span class="token class-name"> </span><br></span><span class="token-line" style="color:#393A34"><span class="token class-name">    </span><span class="token class-name comment" style="color:#999988;font-style:italic">// People Chain</span><span class="token class-name"></span><br></span><span class="token-line" style="color:#393A34"><span class="token class-name">    PolkadotPeopleApi</span><span class="token class-name punctuation" style="color:#393A34">,</span><span class="token class-name"> </span><br></span><span class="token-line" style="color:#393A34"><span class="token class-name">    </span><span class="token class-name comment" style="color:#999988;font-style:italic">// Staking-residing chain</span><span class="token class-name"></span><br></span><span class="token-line" style="color:#393A34"><span class="token class-name">    PolkadotApi</span><span class="token class-name operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    relayChainSpec</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> ChainSpecs</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">PolkadotApi</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    peopleChainSpec</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> ChainSpecs</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">PolkadotPeopleApi</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    apiStatus</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      relay</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> ApiStatus</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">PolkadotApi</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      people</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> ApiStatus</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">PolkadotPeopleApi</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    coreConsts</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> CoreConsts</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">PolkadotApi</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    stakingConsts</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> StakingConsts</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">PolkadotApi</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    blockNumber</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> BlockNumberQuery</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">PolkadotApi</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    activeEra</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> ActiveEraQuery</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">PolkadotApi</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    relayMetrics</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> RelayMetricsQuery</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">PolkadotApi</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    poolsConfig</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> PoolsConfigQuery</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">PolkadotApi</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    stakingMetrics</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> StakingMetricsQuery</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">PolkadotApi</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    eraRewardPoints</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> EraRewardPointsQuery</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">PolkadotApi</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    fastUnstakeConfig</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> FastUnstakeConfigQuery</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">PolkadotApi</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    fastUnstakeQueue</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> FastUnstakeQueueQuery</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">PolkadotApi</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    subActiveAddress</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Subscription</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    subImportedAccounts</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Subscription</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    subActiveEra</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Subscription</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    subAccountBalances</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> AccountBalances</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">PolkadotApi</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> PolkadotPeopleApi</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      relay</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      people</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    subStakingLedgers</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> StakingLedgers</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">PolkadotApi</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    subProxies</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Proxies</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">PolkadotApi</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    subActivePoolIds</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Subscription</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    subActivePools</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> ActivePools</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">PolkadotApi</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token operator" style="color:#393A34">...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>Every query and subscription is generic over an chain type group, which is why they must be provided within the service class. To maintain package modularity and ease of maintenance, chain interactions are stored in separate folders depending on their type,  and separated into separate files:</p>
<ul>
<li class=""><a href="https://github.com/polkadot-cloud/polkadot-staking-dashboard/tree/main/packages/dedot-api/src/spec" target="_blank" rel="noopener noreferrer" class=""><code>spec</code></a>: Fetching of chain specs and API status</li>
<li class=""><a href="https://github.com/polkadot-cloud/polkadot-staking-dashboard/tree/main/packages/dedot-api/src/consts" target="_blank" rel="noopener noreferrer" class=""><code>consts</code></a>: Fetching of groups of chain constants</li>
<li class=""><a href="https://github.com/polkadot-cloud/polkadot-staking-dashboard/tree/main/packages/dedot-api/src/query" target="_blank" rel="noopener noreferrer" class=""><code>query</code></a>: Chain state queries, multi-queries and entries queries</li>
<li class=""><a href="https://github.com/polkadot-cloud/polkadot-staking-dashboard/tree/main/packages/dedot-api/src/subscribe" target="_blank" rel="noopener noreferrer" class=""><code>subscribe</code></a>: Chain state subscriptions and multi-subscriptions</li>
<li class=""><a href="https://github.com/polkadot-cloud/polkadot-staking-dashboard/tree/main/packages/dedot-api/src/runtimeApi" target="_blank" rel="noopener noreferrer" class=""><code>runtimeApi</code></a>: Runtime API call handlers</li>
<li class=""><a href="https://github.com/polkadot-cloud/polkadot-staking-dashboard/tree/main/packages/dedot-api/src/tx" target="_blank" rel="noopener noreferrer" class=""><code>tx</code></a>: Transaction definitions</li>
</ul>
<p>These functions and classes do not assume a particular chain, but instead define what kind of chain they expect, such as a <code>RelayChain</code> or a <code>StakingChain</code>.</p>
<p>The granularity of services classes and their contents allow easy maintenance, even when chain state is not consistent between networks. For instance, Westend will carry out its AssetHub migration before Kusama and Polkadot, which will result in  <code>WestendAssetHub</code> being assigned to the <code>StakingChain</code> union in place of the current <code>WestendApi</code> Relay chain.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="polkadot-service-flow">Polkadot Service Flow<a href="https://rossbulat.com/polkadot/dedot-api-service-integration#polkadot-service-flow" class="hash-link" aria-label="Direct link to Polkadot Service Flow" title="Direct link to Polkadot Service Flow" translate="no">​</a></h3>
<p>Having discussed the general structure of the Polkadot service, let's break down what the <code>start</code> function does:</p>
<ul>
<li class="">Chain specs are fetched for both Relay and People chains and set in the global bus.</li>
<li class="">Relay chain constants and Staking chain constants  are fetched and set in the global bus.</li>
<li class="">"Base" queries are subscribed to, ranging from the block number, active era, and various groups of chain state queries that either the service or UI requires.</li>
<li class="">Subscriptions to global bus are initialised and handled. Examples include:<!-- -->
<ul>
<li class="">The active era, which therein allow further subscriptions to staking metrics.</li>
<li class="">The Staking Dashboard active account, which in-turn subscribes to the account's fast unstake status.</li>
<li class="">All  imported accounts to the dashboard, which in-turn:<!-- -->
<ul>
<li class="">Subscribes to each account's balances, on both Relay and People chain</li>
<li class="">Subscribes to each account's staking ledger</li>
<li class="">Subscribes to each account's proxies</li>
</ul>
</li>
<li class="">Active nomination pool IDs, or the IDs of nomination pools that imported accounts are members of, which in-turn:<!-- -->
<ul>
<li class="">Subscribes to the corresponding bonded pool, its reward pool, and its nominators.</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>This service flow embeds subscriptions within subscriptions, which adds complexity to the service. This is why separation of concerns is valuable with this API logic completely abstracted from the UI.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="managing-new-and-stale-subscription-entries">Managing New and Stale Subscription Entries<a href="https://rossbulat.com/polkadot/dedot-api-service-integration#managing-new-and-stale-subscription-entries" class="hash-link" aria-label="Direct link to Managing New and Stale Subscription Entries" title="Direct link to Managing New and Stale Subscription Entries" translate="no">​</a></h4>
<p>In multiple instances, subscriptions need to be unsubscribed and removed from class state.  A concise example is with the active pool ID subscriptions, whereby removed pool IDs require an unsubscribe to that pool. Conversely, newly added pool IDs require a new subscription.</p>
<p>To deal with these changes elegently, Rxjs's <code>pairwise</code> and <code>startsWith</code> utilities can be leveraged, giving the callback access to both it's previous and current state:</p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">subActivePoolIds </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> activePoolIds$</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// Access previous and current state of observable</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">pipe</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">startWith</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">pairwise</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">subscribe</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">prev</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> cur</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// This diff function determines which pool IDs have been removed, and which added</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> added</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> removed </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">diffPoolIds</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">prev</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> cur</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// For removed pool IDs, unsubscribe from its activePool subscription</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    removed</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">forEach</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">poolId</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">subActivePools</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">poolId</span><span class="token punctuation" style="color:#393A34">]</span><span class="token operator" style="color:#393A34">?.</span><span class="token function" style="color:#d73a49">unsubscribe</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// For added pool IDs, initialise activePool subscriptions</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    added</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">forEach</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">poolId</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">subActivePools</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">poolId</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">ActivePoolQuery</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// NOTE: I am explicitly providing the correct api class for each query</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">apiRelay</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        poolId</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">stakingConsts</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">poolsPalletId</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">interface</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<p>The service flow discussed here all happens automatically, starting from the service's <code>start</code> function. It provides the core state for the Staking Dashboard's currently active network and its imported accounts.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="exposing-a-service-interface">Exposing a Service Interface<a href="https://rossbulat.com/polkadot/dedot-api-service-integration#exposing-a-service-interface" class="hash-link" aria-label="Direct link to Exposing a Service Interface" title="Direct link to Exposing a Service Interface" translate="no">​</a></h3>
<p>In addition to the one-way data flow of the service <code>start</code>  function, there are cases where the UI needs to interact with the service for specific data, rather than relying on the global bus. Examples include:</p>
<ul>
<li class="">Fetching identity data for a page of validators as they are browsed</li>
<li class="">Runtime API calls for a nomination pool's reward balance when a pool page is visited</li>
<li class="">Transaction instantiation and submission.</li>
</ul>
<p>These are functionalities that the app requests upon a user input - and this requires a public  service API the UI can use to interact with the service. This is why the service interface was exposed via the global bus just before <code>start</code> was called:</p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// Expose service interface via global bus</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">setServiceInterface</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">service</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">interface</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// &lt;- UI now has access to service interface</span><br></span></code></pre></div></div>
<p>The service interface itself is defined <a href="https://github.com/polkadot-cloud/polkadot-staking-dashboard/blob/main/packages/types/src/interfaces.ts" target="_blank" rel="noopener noreferrer" class="">here</a>, providing the queries, transactions and signer utilities for the dashboard. Each service then implements this interface, providing the correct APIs to the respective function calls <strong>within the service class itself</strong>. This stays true to our core principle that the app doesn’t need to know which chain it’s interacting with.</p>
<p>To drill this concept, let's look at the <code>query.bondedPool</code> interface:</p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// Public service interface</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">query</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function-variable function" style="color:#d73a49">bondedPool</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">poolId</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token builtin">Promise</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">BondedPoolQuery </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">undefined</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>This is the publicly exposed API that just rquires a <code>poolId</code> argument, and either returns a bonded pool or undefined if nothing was found. When the service implements this query however, it is responsible for passing the correct API to the corresponding function call:</p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// Service class implementation</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">query</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function-variable function" style="color:#d73a49">bondedPool</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">async</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">poolId</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> query</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">bondedPool</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">apiRelay</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> poolId</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>The Relay chain API is being passed to the <code>bondedPool</code> function in this case.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="exposing-the-service-interface-to-react-components">Exposing the Service Interface to React Components<a href="https://rossbulat.com/polkadot/dedot-api-service-integration#exposing-the-service-interface-to-react-components" class="hash-link" aria-label="Direct link to Exposing the Service Interface to React Components" title="Direct link to Exposing the Service Interface to React Components" translate="no">​</a></h4>
<p>The service interface is subscribed to within the app's <a href="https://github.com/polkadot-cloud/polkadot-staking-dashboard/blob/main/packages/app/src/contexts/Api/index.tsx" target="_blank" rel="noopener noreferrer" class=""><code>Api</code></a> context, and is exposed as a <code>serviceApi</code> object for the entire app to use:</p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// Listen for service interface updates and expose via this context</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">useEffect</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> subServiceInterface </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> serviceInterface$</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">subscribe</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">result</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">setServiceApi</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">result</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    subServiceInterface</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">unsubscribe</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token operator" style="color:#393A34">...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// Expose `serviceApi` for app components to use</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">APIContext</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Provider</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    value</span><span class="token operator" style="color:#393A34">=</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      serviceApi</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">children</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token operator" style="color:#393A34">/</span><span class="token plain">APIContext</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Provider</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<p>Components can then access this <code>serviceApi</code> via the <code>useApi</code> hook, an idiomatic way for the React component hierarchy:</p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">MyComponent</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> serviceApi  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useApi</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> bondedPool </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> serviceApi</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">query</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">bondedPool</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token operator" style="color:#393A34">...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="unsubscribing-on-network-switchng">Unsubscribing on Network Switchng<a href="https://rossbulat.com/polkadot/dedot-api-service-integration#unsubscribing-on-network-switchng" class="hash-link" aria-label="Direct link to Unsubscribing on Network Switchng" title="Direct link to Unsubscribing on Network Switchng" translate="no">​</a></h3>
<p>Importantly, all service classes must implement unsubscribe and tidy-up logic (See the Polkadot service <a href="https://github.com/polkadot-cloud/polkadot-staking-dashboard/blob/b227c2ef82b6c721ad1328717a97a8a3b9e2d34c/packages/dedot-api/src/services/polkadot.ts#L216" target="_blank" rel="noopener noreferrer" class="">unsubscribe</a> function):</p>
<ul>
<li class="">Service class subscriptions are unsubscribed</li>
<li class="">Dedot queries are unsubscribed</li>
<li class="">The Dedot clients are then disconnected</li>
<li class="">Global bus chain state is reset</li>
</ul>
<p>Again, Rxjs's <code>pairwise</code> utility is leveraged to perform this tidy-up before a new Service is instantiated on a network switch (<a href="https://github.com/polkadot-cloud/polkadot-staking-dashboard/blob/b227c2ef82b6c721ad1328717a97a8a3b9e2d34c/packages/dedot-api/src/index.ts#L25" target="_blank" rel="noopener noreferrer" class="">Source Code</a>).</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="conclusion--next-steps">Conclusion &amp; Next Steps<a href="https://rossbulat.com/polkadot/dedot-api-service-integration#conclusion--next-steps" class="hash-link" aria-label="Direct link to Conclusion &amp; Next Steps" title="Direct link to Conclusion &amp; Next Steps" translate="no">​</a></h2>
<p>This refactor lays the foundation for a more modular, scalable, and future-proof Staking Dashboard. The Dedot API now plays a critical role in the Staking Dashboard's developer and user experience.</p>
<p>Looking ahead, there are two key directions to take the implementation further:</p>
<ul>
<li class=""><strong>AssetHub Chain to Default Service:</strong> As each network transitions staking logic to AssetHub, the default service can be extended to treat AssetHub as a third chain api, alongside the Relay chain and People chain.</li>
<li class=""><strong>External Network Integrations:</strong> With the new service-based architecture, it's now straightforward to introduce additional networks that have traditionally forked the Staking Dashboard, such as <a href="https://vara.network/" target="_blank" rel="noopener noreferrer" class="">Vara network</a>, by creating dedicated service modules—no forking required.</li>
</ul>
<p>These improvements continue to move the dashboard toward a more universal, multi-network staking interface that’s easier to maintain and extend across the Polkadot ecosystem.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="useful-links">Useful Links<a href="https://rossbulat.com/polkadot/dedot-api-service-integration#useful-links" class="hash-link" aria-label="Direct link to Useful Links" title="Direct link to Useful Links" translate="no">​</a></h2>
<ul>
<li class="">
<p>Dedot API Docs: <a href="https://docs.dedot.dev/" target="_blank" rel="noopener noreferrer" class="">https://docs.dedot.dev/</a></p>
</li>
<li class="">
<p>Dedot Telegram Group: <a href="https://t.me/JoinDedot" target="_blank" rel="noopener noreferrer" class="">https://t.me/JoinDedot</a></p>
</li>
<li class="">
<p>Staking Dashboard GitHub: <a href="https://github.com/polkadot-cloud/polkadot-staking-dashboard" target="_blank" rel="noopener noreferrer" class="">https://github.com/polkadot-cloud/polkadot-staking-dashboard</a></p>
</li>
</ul>]]></content:encoded>
            <category>Polkadot</category>
            <category>Staking Dashboard</category>
            <category>Dedot API</category>
        </item>
    </channel>
</rss>