@parity/product-sdk-signer
Account connection and signing, decoupled from where the keys actually live.
SignerManager wraps one or more SignerProvider implementations behind a
Result-typed API for connecting, listing accounts, and reacting to status or
account changes. The two built-in providers — HostProvider (Polkadot
Desktop/Mobile) and DevProvider (the well-known Alice/Bob accounts) — let
the same call sites work in production and in tests.
npm install @parity/product-sdk-signerExports
Classes
| Name | Summary |
|---|---|
AccountNotFoundError | An account was not found by address. |
DestroyedError | The SignerManager has been destroyed and is no longer usable. |
DevProvider | Provider for Substrate development accounts. |
HostDisconnectedError | The host connection was lost. |
HostProvider | Provider for the Host API (Polkadot Desktop / Android). |
HostRejectedError | The host rejected the account or signing request. |
HostUnavailableError | The Host API is not available (product-sdk not installed or not inside a container). |
NoAccountsError | No accounts available from the provider. |
SignerError | Base class for all signer errors. Use instanceof SignerError to catch any signer-related error. |
SignerManager | Core orchestrator for signer management. |
SigningFailedError | A signing operation failed. |
TimeoutError | An operation timed out. |
Functions
| Name | Summary |
|---|---|
err() | Create a failed Result. |
isHostError() | Check if a SignerError is a host-related error. |
ok() | Create a successful Result. |
sleep() | Sleep for a given duration, cancellable via AbortSignal. |
withRetry() | Retry an async operation with exponential backoff. |
Interfaces
| Name | Summary |
|---|---|
AccountPersistence | Adapter for persisting the selected account address across sessions. |
ConnectContext | Context passed to the onConnect callback. |
ContextualAlias | A contextual alias obtained from Ring VRF. |
DevProviderOptions | Options for the dev account provider. |
HostProviderOptions | Options for the Host API provider. |
ProductAccount | A product account — an app-scoped derived account managed by the host wallet. |
RetryOptions | Options for retry with exponential backoff. |
RingLocation | Location of a Ring VRF ring on-chain. |
SignerAccount | A signing-capable account from any provider. |
SignerManagerOptions | Options for SignerManager construction. |
SignerProvider | Interface that all signer providers must implement. |
SignerState | Full state snapshot emitted to subscribers. |
Type Aliases
| Name | Summary |
|---|---|
ConnectionStatus | Connection status for a signer provider. |
DevAccountName | A well-known Substrate development account name (Alice, Bob, …) used to derive deterministic dev accounts from the standard Substrate dev mnemonic. |
DevKeyType | Supported key types for dev account derivation. |
OnConnect | Callback signature for SignerManagerOptions.onConnect. |
ProviderFactory | Factory function that creates a SignerProvider for a given type. |
ProviderType | Identifies the source of an account. |
Result | Lightweight Result type for operations that can fail expectedly. |
Unsubscribe | Function that unsubscribes a listener when called. |
Classes
class AccountNotFoundError
An account was not found by address.
Extends: SignerError
Constructors
constructor
new AccountNotFoundError(address: string): AccountNotFoundErrorProperties
address
stringclass DestroyedError
The SignerManager has been destroyed and is no longer usable.
Extends: SignerError
Constructors
constructor
new DestroyedError(): DestroyedErrorclass DevProvider
Provider for Substrate development accounts.
Uses the well-known DEV_PHRASE with hard derivation paths (//Alice, //Bob, etc.)
to create deterministic accounts for local development and testing.
Implements: SignerProvider
Constructors
constructor
new DevProvider(options?: DevProviderOptions): DevProviderProperties
type
"dev"Unique identifier for this provider type.
Methods
connect
Attempt to connect and discover accounts.
connect(): Promise<Result<SignerAccount[], SignerError>>Returns
Accounts on success, typed error on failure.
disconnect
Disconnect and clean up resources. Safe to call multiple times.
disconnect(): voidonAccountsChange
Subscribe to account list changes.
Emitted when the set of available accounts changes (e.g., user connects/disconnects in the host wallet).
onAccountsChange(_callback: (accounts: SignerAccount[]) => void): UnsubscribeReturns
Unsubscribe function.
onStatusChange
Subscribe to connection status changes.
Not all providers emit status changes — for example, dev accounts are always “connected” and never emit.
onStatusChange(_callback: (status: "disconnected" | "connecting" | "connected") => void): UnsubscribeReturns
Unsubscribe function.
class HostDisconnectedError
The host connection was lost.
Extends: SignerError
Constructors
constructor
new HostDisconnectedError(message: string = "Host connection lost"): HostDisconnectedErrorclass HostProvider
Provider for the Host API (Polkadot Desktop / Android).
Dynamically imports @novasamatech/host-api-wrapper at runtime so it remains
an optional peer dependency. Apps running outside a host container will
gracefully get a HOST_UNAVAILABLE error.
Supports both non-product accounts (user’s external wallets) and product accounts (app-scoped derived accounts managed by the host).
Implements: SignerProvider
Constructors
constructor
new HostProvider(options?: HostProviderOptions): HostProviderProperties
type
ProviderTypeUnique identifier for this provider type.
Methods
connect
Attempt to connect and discover accounts.
connect(signal?: AbortSignal): Promise<Result<SignerAccount[], SignerError>>Parameters
signal: Optional AbortSignal to cancel the connection attempt.
Returns
Accounts on success, typed error on failure.
createRingVRFProof
Create a Ring VRF proof for anonymous operations.
Proves that the signer is a member of the ring at the given location without revealing which member. Used for privacy-preserving protocols.
Requires a prior successful connect() call.
createRingVRFProof(dotNsIdentifier: string, derivationIndex: number, location: RingLocation, message: Uint8Array): Promise<Result<Uint8Array<ArrayBufferLike>, SignerError>>disconnect
Disconnect and clean up resources. Safe to call multiple times.
disconnect(): voidgetProductAccount
Get an app-scoped product account from the host.
Product accounts are derived by the host wallet for each app, identified
by dotNsIdentifier (e.g., “mark3t.dot”). The user controls these accounts
but they are scoped to the requesting app.
Requires a prior successful connect() call.
getProductAccount(dotNsIdentifier: string, derivationIndex: number = 0): Promise<Result<SignerAccount, SignerError>>getProductAccountAlias
Get a contextual alias for a product account via Ring VRF.
Aliases prove account membership in a ring without revealing which account produced the alias.
Requires a prior successful connect() call.
getProductAccountAlias(dotNsIdentifier: string, derivationIndex: number = 0): Promise<Result<ContextualAlias, SignerError>>getProductAccountSigner
Get a PolkadotSigner for a product account.
Convenience method for when you already have the product account details.
Requires a prior successful connect() call.
Routing is pinned to signerType: "createTransaction" via
PRODUCT_SIGNER_TYPE so unknown signed extensions (e.g. AsPgas
on Paseo Next) are forwarded to the host as opaque bytes for
metadata-driven decoding, rather than going through the PJS bridge
that throws on unknown extensions.
getProductAccountSigner(account: ProductAccount): PolkadotSigneronAccountsChange
Subscribe to account list changes.
Emitted when the set of available accounts changes (e.g., user connects/disconnects in the host wallet).
onAccountsChange(callback: (accounts: SignerAccount[]) => void): UnsubscribeReturns
Unsubscribe function.
onStatusChange
Subscribe to connection status changes.
Not all providers emit status changes — for example, dev accounts are always “connected” and never emit.
onStatusChange(callback: (status: ConnectionStatus) => void): UnsubscribeReturns
Unsubscribe function.
class HostRejectedError
The host rejected the account or signing request.
Extends: SignerError
Constructors
constructor
new HostRejectedError(message: string = "Host rejected the request"): HostRejectedErrorclass HostUnavailableError
The Host API is not available (product-sdk not installed or not inside a container).
Extends: SignerError
Constructors
constructor
new HostUnavailableError(message: string = "Host API is not available"): HostUnavailableErrorclass NoAccountsError
No accounts available from the provider.
Extends: SignerError
Constructors
constructor
new NoAccountsError(provider: ProviderType, message?: string): NoAccountsErrorProperties
provider
ProviderTypeclass SignerError
Base class for all signer errors. Use instanceof SignerError to catch any signer-related error.
Extends: Error
Constructors
constructor
new SignerError(message: string, options?: ErrorOptions): SignerErrorclass SignerManager
Core orchestrator for signer management.
Manages account discovery and signer creation via the Host API.
Framework-agnostic — use the subscribe() pattern to integrate with
React, Vue, or any framework.
Lifecycle
disconnected → connecting → connected ──── selectAccount / signRaw / …
▲ │ │
│ ▼ ▼
└── disconnect() provider drops → auto-reconnect → connected
(onConnect re-fires)
┌─ destroy() ──► (terminal — manager unusable)
▼Callbacks
-
subscribe(cb)fires synchronously on every state mutation, in registration order, inside the call stack that mutated state. It does not fire with the initial state — callgetState()if you need a priming read. Multiple mutations during the same operation produce multiple notifications. -
onConnect(account, ctx)(fromSignerManagerOptions) fires exactly when the manager transitions from non-connected to"connected"with a selected account. It fires on a microtask after thesubscribenotification, so subscribers always observestate.status === "connected"beforeonConnect’s side effects run. It re-fires after auto-reconnect (the SDK reconnects automatically when the provider drops), and re-fires after a freshconnect(). -
Internal
onAccountsChangewiring is worth a behavioral note: when the provider reports an updated account list, the manager preserves the current selection if its address is still present, or setsselectedAccounttonullif it isn’t — it does not fall back toaccounts[0]. The fallback-to-first only applies on connect-success, where there is no prior selection to preserve.
disconnect() vs destroy()
disconnect()resets state to initial. Subsequentconnect()calls work normally. Reversible.destroy()is terminal: the instance is marked unusable, all subscribers are cleared, and any further call returnsDestroyedError. Use in framework teardown (ReactuseEffectcleanup, HMR dispose).
Both methods cancel any in-flight connect, reconnect attempt, and
onConnect callback (the ctx.signal becomes aborted).
Examples
const manager = new SignerManager({
onConnect: async (_account, { requestResourceAllocation }) => {
await requestResourceAllocation([{ tag: "AutoSigning", value: undefined }]);
},
});
manager.subscribe(state => console.log(state.status));
await manager.connect(); // host provider (default)
await manager.connect("dev"); // Alice / Bob / … for testing
manager.selectAccount("5GrwvaEF…");
const signer = manager.getSigner();Constructors
constructor
new SignerManager(options?: SignerManagerOptions): SignerManagerMethods
connect
Connect to a provider.
If no provider type is specified, connects to the Host API. The SDK is designed to run exclusively inside a host container.
When connecting to a specific provider type:
"host": Connect to the Host API (default, recommended)"dev": Connect using dev accounts (for testing)
connect(providerType?: ProviderType): Promise<Result<SignerAccount[], SignerError>>createRingVRFProof
Create a Ring VRF proof for anonymous operations.
Proves that the signer is a member of the ring at the given location without revealing which member. Only available when connected via the host provider — returns HOST_UNAVAILABLE otherwise.
createRingVRFProof(dotNsIdentifier: string, derivationIndex: number, location: RingLocation, message: Uint8Array): Promise<Result<Uint8Array<ArrayBufferLike>, SignerError>>destroy
Destroy the manager and release all resources.
Terminal — clears all subscribers, cancels in-flight work, and
marks the instance unusable. Any subsequent method returns
DestroyedError. Idempotent. Use in framework teardown (React
useEffect cleanup, HMR dispose). For a reversible reset, use
disconnect instead.
destroy(): voiddisconnect
Disconnect from the current provider and reset state to initial.
Reversible — subsequent connect() calls work normally. Cancels
any in-flight connect, reconnect attempt, or onConnect callback
(ctx.signal becomes aborted).
disconnect(): voidgetProductAccount
Get an app-scoped product account from the host.
Product accounts are derived by the host wallet for each app, identified
by dotNsIdentifier (e.g., “mark3t.dot”). Only available when connected
via the host provider — returns HOST_UNAVAILABLE otherwise.
getProductAccount(dotNsIdentifier: string, derivationIndex: number = 0): Promise<Result<SignerAccount, SignerError>>Examples
const result = await manager.getProductAccount("myapp.dot");
if (result.ok) {
const signer = result.value.getSigner();
}getProductAccountAlias
Get a contextual alias for a product account via Ring VRF.
Aliases prove account membership in a ring without revealing which account produced the alias. Only available when connected via the host provider — returns HOST_UNAVAILABLE otherwise.
getProductAccountAlias(dotNsIdentifier: string, derivationIndex: number = 0): Promise<Result<ContextualAlias, SignerError>>getSigner
Get the PolkadotSigner for the currently selected account. Returns null if no account is selected or manager is disconnected.
getSigner(): PolkadotSigner | nullgetState
Get a snapshot of the current state.
getState(): SignerStateselectAccount
Select an account by address. Returns the account on success, or ACCOUNT_NOT_FOUND error.
selectAccount(address: string): Result<SignerAccount, SignerError>signRaw
Sign arbitrary bytes with the currently selected account.
Convenience wrapper around PolkadotSigner.signBytes — useful for
master key derivation, message signing, and proof generation without
constructing a full transaction.
Returns a SIGNING_FAILED error if no account is selected or signing fails.
signRaw(data: Uint8Array): Promise<Result<Uint8Array<ArrayBufferLike>, SignerError>>subscribe
Subscribe to state changes.
The callback fires synchronously on every state mutation, in
registration order, inside the call stack that mutated state. It
does not fire with the current state at subscription time —
call getState if you need a priming read.
For “fired once when the user connects” semantics, prefer the
SignerManagerOptions.onConnect option instead of gating on
state.status inside this callback — subscribe will fire many
times while connected (selectAccount, account swaps, etc.).
subscribe(callback: (state: SignerState) => void): () => voidReturns
an unsubscribe function.
class SigningFailedError
A signing operation failed.
Extends: SignerError
Constructors
constructor
new SigningFailedError(cause: unknown, message?: string): SigningFailedErrorclass TimeoutError
An operation timed out.
Extends: SignerError
Constructors
constructor
new TimeoutError(operation: string, ms: number): TimeoutErrorProperties
ms
numberoperation
stringFunctions
err()
Create a failed Result.
err(error: E): Result<never, E>isHostError()
Check if a SignerError is a host-related error.
isHostError(e: SignerError): e is HostUnavailableError | HostRejectedError | HostDisconnectedErrorok()
Create a successful Result.
ok(value: T): Result<T, never>sleep()
Sleep for a given duration, cancellable via AbortSignal.
Resolves immediately if the signal is already aborted. Cleans up the abort listener when the timer fires naturally to prevent listener accumulation in retry loops.
sleep(ms: number, signal?: AbortSignal): Promise<void>withRetry()
Retry an async operation with exponential backoff.
Calls fn up to maxAttempts times. If fn returns an error result,
waits with exponential backoff before the next attempt. Returns the first
successful result or the last error.
withRetry(fn: (attempt: number) => Promise<Result<T, E>>, options?: RetryOptions): Promise<Result<T, E>>Interfaces
interface AccountPersistence
Adapter for persisting the selected account address across sessions.
globalThis.localStorage satisfies this interface. Pass a custom
implementation for container environments (e.g., hostLocalStorage)
or for testing.
Methods
getItem
getItem(key: string): string | Promise<string | null> | nullremoveItem
removeItem(key: string): void | Promise<void>setItem
setItem(key: string, value: string): void | Promise<void>interface ConnectContext
Context passed to the onConnect callback.
Properties
requestResourceAllocation
(resources: { tag: "StatementStoreAllowance"; value: undefined } | { tag: "BulletinAllowance"; value: undefined } | { tag: "SmartContractAllowance"; value: number } | { tag: "AutoSigning"; value: undefined }[]) => Promise<{ tag: "Rejected"; value: undefined } | { tag: "Allocated"; value: undefined } | { tag: "NotAvailable"; value: undefined }[]>Request a batch of host resource allocations. Bound shorthand for
requestResourceAllocation from @parity/product-sdk-host —
throws on failure, returns the unwrapped outcomes on success.
signal
AbortSignalAborted when the manager disconnects or is destroyed while the
callback is still running. Pass through to fetch / cancellation
primitives so mid-flight work stops promptly.
interface ContextualAlias
A contextual alias obtained from Ring VRF.
Proves account membership in a ring without revealing which account.
Properties
alias
Uint8ArrayThe Ring VRF alias bytes.
context
Uint8ArrayRing context (32 bytes).
interface DevProviderOptions
Options for the dev account provider.
Properties
keyType
DevKeyTypeKey type for account derivation. Default: “sr25519”
mnemonic
stringCustom mnemonic phrase instead of DEV_PHRASE.
names
readonly string[]Which dev accounts to create. Default: all 6 standard accounts.
ss58Prefix
numberSS58 prefix for address encoding. Default: 42
interface HostProviderOptions
Options for the Host API provider.
Properties
loadHostApiEnum
() => Promise<HostApiEnumHelper>Custom loader for @novasamatech/host-api (used to construct the
ChainSubmit permission request). Defaults to dynamic import.
loadSdk
() => Promise<ProductSdkModule>Custom SDK loader. Defaults to import("@novasamatech/host-api-wrapper").
Override this for testing or custom SDK setups.
maxRetries
numberMax retry attempts for initial connection. Default: 3
productAccount
{ derivationIndex?: number; dotNsIdentifier: string }If set, connect() returns a single product account for the given
dotNsIdentifier, skipping the legacy fetch entirely. For apps
that sign exclusively with a per-dapp derived account.
SignerAccount.name is populated best-effort from
accounts.getUserId().primaryUsername; failures leave it null.
Signing is pinned to createTransaction (see PR #96).
requestChainSubmitPermission
booleanWhether to request the host’s ChainSubmit permission after a
successful connect(). Without this, subsequent signing requests are
rejected by the host with PermissionDenied. Default: true.
Set to false if your app needs to defer the permission prompt or
drives it manually.
(Previously named requestTransactionSubmitPermission — alias kept
for backwards compatibility but the new wire format uses ChainSubmit.)
requestTransactionSubmitPermission
booleanretryDelay
numberInitial retry delay in ms. Default: 500
ss58Prefix
numberSS58 prefix for address encoding. Default: 42
interface ProductAccount
A product account — an app-scoped derived account managed by the host wallet.
The host derives a unique keypair for each app (identified by dotNsIdentifier)
so apps get their own account that the user controls but is scoped to the app.
Properties
derivationIndex
numberDerivation index within the app scope. Default: 0
dotNsIdentifier
stringApp identifier (e.g., “mark3t.dot”).
publicKey
Uint8ArrayRaw public key (32 bytes).
interface RetryOptions
Options for retry with exponential backoff.
Properties
backoffMultiplier
numberMultiplier applied to delay after each attempt. Default: 2
initialDelay
numberInitial delay in ms before first retry. Default: 500
maxAttempts
numberMaximum number of attempts. Default: 3
maxDelay
numberMaximum delay cap in ms. Default: 10_000
signal
AbortSignalAbortSignal to cancel retries early.
interface RingLocation
Location of a Ring VRF ring on-chain.
Matches the product-sdk’s RingLocation codec shape.
Properties
genesisHash
stringhints
{ palletInstance?: number }ringRootHash
stringinterface SignerAccount
A signing-capable account from any provider.
Properties
address
SS58StringSS58 address (generic prefix 42 by default).
h160Address
`0x${string}`H160 EVM address derived from the public key.
For native Substrate accounts: keccak256(publicKey), last 20 bytes. For EVM-derived accounts: strips the 0xEE padding. Used for pallet-revive / Asset Hub EVM contract interactions.
name
string | nullHuman-readable name if available from the provider.
publicKey
Uint8ArrayRaw public key (32 bytes). May be sr25519, ed25519, or ecdsa depending on the provider.
source
ProviderTypeWhich provider supplied this account.
Methods
getSigner
Get the PolkadotSigner for this account.
getSigner(): PolkadotSignerinterface SignerManagerOptions
Options for SignerManager construction.
Properties
createProvider
ProviderFactoryCustom provider factory. Override to inject test doubles or custom providers.
dappName
stringApp name used for storage key namespacing. Default: “product-sdk”
The selected account is persisted under product-sdk:signer:{dappName}:selectedAccount.
hostTimeout
numberMaximum time in ms to wait for the Host API. Applied as an AbortSignal timeout on the host provider connection. Default: 10_000
maxRetries
numberMaximum retry attempts for provider connection. Default: 3
onConnect
OnConnectCallback fired exactly when the manager transitions to connected
with a selected account — not on subsequent state mutations while
still connected. Fires again after auto-reconnect, so a fresh host
session re-runs the callback.
Common use: request product resource allocations once per session.
The ctx exposes a pre-bound requestResourceAllocation helper
plus an AbortSignal that fires if the user disconnects or
destroys the manager mid-flight.
requestResourceAllocation throws on failure (matches the
@parity/product-sdk-host export of the same name); errors thrown
from onConnect are logged but do not affect the connected state —
the next reconnect retries.
persistence
AccountPersistence | nullStorage adapter for persisting selected account.
Uses host localStorage when inside a container.
Set to null to disable persistence entirely.
ss58Prefix
numberSS58 prefix for address encoding. Default: 42
interface SignerProvider
Interface that all signer providers must implement.
Providers are responsible for discovering accounts and creating signers from a specific source (Host API or dev accounts).
Properties
type
ProviderTypeUnique identifier for this provider type.
Methods
connect
Attempt to connect and discover accounts.
connect(signal?: AbortSignal): Promise<Result<SignerAccount[], SignerError>>Parameters
signal: Optional AbortSignal to cancel the connection attempt.
Returns
Accounts on success, typed error on failure.
disconnect
Disconnect and clean up resources. Safe to call multiple times.
disconnect(): voidonAccountsChange
Subscribe to account list changes.
Emitted when the set of available accounts changes (e.g., user connects/disconnects in the host wallet).
onAccountsChange(callback: (accounts: SignerAccount[]) => void): UnsubscribeReturns
Unsubscribe function.
onStatusChange
Subscribe to connection status changes.
Not all providers emit status changes — for example, dev accounts are always “connected” and never emit.
onStatusChange(callback: (status: ConnectionStatus) => void): UnsubscribeReturns
Unsubscribe function.
interface SignerState
Full state snapshot emitted to subscribers.
Properties
accounts
readonly SignerAccount[]All available accounts across all connected providers.
activeProvider
ProviderType | nullWhich provider is active (null if disconnected).
error
SignerError | nullLast error (null if no error).
selectedAccount
SignerAccount | nullCurrently selected account (null if none selected).
status
ConnectionStatusCurrent connection status.
Type Aliases
type ConnectionStatus
Connection status for a signer provider.
type ConnectionStatus = "disconnected" | "connecting" | "connected"type DevAccountName
A well-known Substrate development account name (Alice, Bob, …) used to derive deterministic dev accounts from the standard Substrate dev mnemonic.
type DevAccountName = typeof DEFAULT_DEV_NAMES[number]type DevKeyType
Supported key types for dev account derivation.
type DevKeyType = "sr25519" | "ed25519"type OnConnect
Callback signature for SignerManagerOptions.onConnect.
type OnConnect = (account: SignerAccount, ctx: ConnectContext) => void | Promise<void>type ProviderFactory
Factory function that creates a SignerProvider for a given type.
type ProviderFactory = (type: ProviderType) => SignerProvidertype ProviderType
Identifies the source of an account.
"host": Host API provider (Polkadot Desktop / Mobile) — the primary provider"dev": Development accounts (Alice, Bob, etc.) — for testing only
type ProviderType = "host" | "dev"type Result
Lightweight Result type for operations that can fail expectedly.
type Result = { ok: true; value: T } | { error: E; ok: false }type Unsubscribe
Function that unsubscribes a listener when called.
type Unsubscribe = () => void