Linked Accounts SDK
The linked accounts SDK resolves relationships between an account and the accounts that can act on its behalf through proxies or multisig accounts.
For proxies, it uses on-chain data. Multisig accounts are deterministic but not listed on-chain, so the SDK relies on a multisig provider (with several implementations available) to resolve them through an indexer.
Getting Started
Install the Accounts SDK using your package manager:
npm i @polkadot-api/sdk-accountsThen, initialize it by passing in the typedApi for your chain:
import {
createLinkedAccountsSdk,
subscanProvider,
} from "@polkadot-api/sdk-accounts"
import { dot } from "@polkadot-api/descriptors"
import { getWsProvider } from "polkadot-api/ws-provider"
import { createClient } from "polkadot-api"
const client = createClient(getWsProvider("wss://rpc.ibp.network/polkadot"))
const multisigProvider = subscanProvider("polkadot", process.env.SUBSCAN_KEY!)
const typedApi = client.getTypedApi(dot)
const linkedAccounts = createLinkedAccountsSdk(typedApi, multisigProvider)API
getLinkedAccounts$(address)
Returns an Observable<LinkedAccountsResult> of the accounts linked to address. The observable emits a single value and then completes. The LinkedAccountsResult is an enum of 3 variants:
root: no proxy or multisig relationships detected.proxy: the account delegates to other accounts.value.addressescontains the delegate SS58 strings.multisig: the address represents a multisig.value.addressesholds all signatories andvalue.thresholdthe approval threshold.
getNestedLinkedAccounts$(address)
Returns an Observable<NestedLinkedAccountsResult> that recursively resolves linked accounts.
Essentially the same as getLinkedAccounts$, but that re-runs getLinkedAccounts$ for each of the linked accounts (and so on, recursively).
The observable emits intermediate values by setting pending resolutions with null. Once everything has been explored, it completes. This is useful for visualising complex proxy or multisig hierarchies.
Multisig Providers
A multisig provider is a simple interface that you can use to plug your own indexer or source. It's a function that given an address, it should return an object with the addresses and threshold, or null if it wasn't found.
export type MultisigProvider = (address: SS58String) => Promise<{
addresses: SS58String[]
threshold: number
} | null>The SDK ships with pre-made providers for a couple of public indexers:
subscanProvider(chain: string, apiKey: string): queries using Subscan indexer, with your ownapiKey.novasamaProvider(chain: 'polkadot' | 'kusama'): queries using Novasama indexer.staticProvider(multisigs: Array<{ multisigAddr: SS58String, addresses: SS58String[], threshold: number }>): returns multisig information from a predefined list, useful for tests or offline scenarios.
Public indexers are subject to query limits and/or fees.
Given the interface is composable, there's also a couple of extra utilities to combine them:
fallbackMultisigProviders(...providers): chains providers and returns the first non-null response. This is useful because some indexers might not have indexed some multisigs, so you can just fall through many of them.throttleMultisigProvider(provider, maxConcurrent, wait?): limits concurrent requests to avoid rate limit errors; whenwaitistrue, additional calls are queued, otherwise they are dropped and fallback tonull.
Example
linkedAccounts.getLinkedAccounts$(address).subscribe((result) => {
switch (result.type) {
case "proxy":
console.log("Delegated accounts", result.value.addresses)
break
case "multisig":
console.log(
`Multisig with threshold ${result.value.threshold}`,
result.value.addresses,
)
break
default:
console.log("Root account")
}
})