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-accounts
Then, 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.addresses
contains the delegate SS58 strings.multisig
: the address represents a multisig.value.addresses
holds all signatories andvalue.threshold
the 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; whenwait
istrue
, 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")
}
})