Skip to main content

Polkadot

UKey Wallet Polkadot Provider is used to connect Polkadot/Substrate accounts, sign transactions and messages in web applications, and send transactions with the Polkadot.js API. The page is accessible via window.$ukey.polkadot or the standard Polkadot.js extension API.

ℹ️

UKey Wallet implements the Polkadot.js extension interface and can be recognized by wallet tools and DApps compatible with Substrate extensions.



Find Provider

// UKey Wallet appears as a Polkadot.js extension
const provider = window.$ukey?.polkadot;

// Note: Or use the standard web3Enable API
import { web3Enable, web3Accounts } from "@polkadot/extension-dapp";

Get Going

Enable extension

// Note: Use UKey Wallet provider directly
const enabled = await provider.web3Enable("UKey Wallet Demo");

if (enabled) {
const accounts = await provider.web3Accounts();
console.log("Selected account:", accounts);
}

Extend the API using Polkadot.js (preferred)

import { web3Enable, web3Accounts } from "@polkadot/extension-dapp";

// Enable every extension, including UKey Wallet
const extensions = await web3Enable("UKey Wallet Demo");

if (extensions.length === 0) {
throw new Error("Extension not found");
}

// Retrieve all accounts
const allAccounts = await web3Accounts();
console.log("Selected account:", allAccounts);

Account management

Read wallet

const accounts = await provider.web3Accounts();

accounts.forEach((account) => {
console.log({
address: account.address, // Note: Substrate address
name: account.name, // Note: Account name
type: account.type, // one of 'sr25519' | 'ed25519' | 'ecdsa'
genesisHash: account.genesisHash, // Chain genesis hash when needed
});
});

Subscribe to account changes

const unsubscribe = provider.web3AccountsSubscribe((accounts) => {
console.log("Active account changed:", accounts);
});

// Remember to call unsubscribe() later when cleaning up

Signing

Signature transaction payload

Transaction payload is usually generated by the Polkadot.js API, and the wallet is responsible for displaying and signing:

import { web3FromAddress } from '@polkadot/extension-dapp'

// Retrieve the injector of a specific account
const injector = await web3FromAddress(accountAddress)

// Note: Signature payload
const payload = {
address: accountAddress,
blockHash: '0x...',
blockNumber: '0x...',
era: '0x...',
genesisHash: '0x...',
method: '0x...',
nonce: '0x...',
specVersion: '0x...',
tip: '0x...',
transactionVersion: '0x...',
signedExtensions: [...],
version: 4,
}

const callResult = await provider.web3SignPayload(payload)

console.log({
id: callResult.id,
signature: callResult.signature, // Note: Hexadecimal signature
})

Sign original message

const payload = {
address: accountAddress,
data: "0x48656c6c6f", // Note: Hexadecimal encoded message
type: "bytes",
};

const callResult = await provider.web3SignRaw(payload);

console.log({
id: callResult.id,
signature: callResult.signature,
});

Used with Polkadot.js API

set up

npm install @polkadot/api @polkadot/extension-dapp

Connect and sign transactions

import { ApiPromise, WsProvider } from "@polkadot/api";
import {
web3Enable,
web3FromAddress,
web3Accounts,
} from "@polkadot/extension-dapp";

// Note: Enable extension
await web3Enable("UKey Wallet Demo");

// Retrieve an account
const accounts = await web3Accounts();
const account = accounts[0];

// establish connectioned to chain
const wsProvider = new WsProvider("wss:/rpc.polkadot.io");
const api = await ApiPromise.create({ provider: wsProvider });

// Retrieve injector
const injector = await web3FromAddress(account.address);

// Note: Create and sign transactions
const tx = api.tx.balances.transfer(
recipientAddress,
1000000000000, // equals 1 DOT in planck units
);

// Note: Sign and send
const hash = await tx.signAndSend(account.address, { signer: injector.signer });

console.log("Tx hash:", hash.toHex());

Listen for transaction events

await tx.signAndSend(
account.address,
{ signer: injector.signer },
({ status, events }) => {
if (status.isInBlock) {
console.log("Included at block:", status.asInBlock.toHex());
}
if (status.isFinalized) {
console.log("Final confirmation at:", status.asFinalized.toHex());

events.forEach(({ event }) => {
if (api.events.system.ExtrinsicSuccess.is(event)) {
console.log("Transaction completed successfully");
}
if (api.events.system.ExtrinsicFailed.is(event)) {
console.log("Transaction execution failed");
}
});
}
},
);

RPC method

Send RPC request

const requestResult = await provider.web3RpcSend({
method: "chain_getHeader",
requestParams: [],
});

console.log("Latest block header data:", requestResult.result);

Subscribe to RPC events

const subscriptionId = await provider.web3RpcSubscribe(
{
method: "chain_subscribeNewHeads",
requestParams: [],
},
(response) => {
console.log("Observed new block:", response.result);
},
);

// Note: Unsubscribe later
await provider.web3RpcUnSubscribe();

List available providers

const providers = await provider.web3RpcListProviders();
console.log("Discovered providers:", providers);

API Notes

Methods

MethodDetails
web3Enable(dappName)Enable extensions for dApps
web3Accounts(anyType?)Get all accounts
web3AccountsSubscribe(callback)Subscribe to account changes
web3SignPayload(payload)Signature transaction payload
web3SignRaw(payload)Sign original message
web3RpcSend(request)Send RPC request
web3RpcSubscribe(request, callback)Subscribe to RPC events
web3RpcUnSubscribe()Cancel all subscriptions
web3RpcListProviders()List RPC providers
web3RpcStartProvider(key)Start a specific provider

Types

interface InjectedAccount {
address: string; // Note: Substrate address
name?: string; // Note: Account name
type?: "sr25519" | "ed25519" | "ecdsa";
genesisHash?: string; // Chain restriction when needed
}

interface SignerPayloadJSON {
address: string;
blockHash: string;
blockNumber: string;
era: string;
genesisHash: string;
method: string;
nonce: string;
specVersion: string;
tip: string;
transactionVersion: string;
signedExtensions: string[];
version: number;
}

interface SignerPayloadRaw {
address: string;
data: string; // Note: Hexadecimal encoded data
type: "bytes" | "payload";
}

interface SignerResult {
id: number;
signature: string; // Note: Hexadecimal signature
}

Chain List

NetworkDetails
PolkadotPrimary relay network
KusamaExperimental canary network
AcalaDeFi-focused network
MoonbeamEVM-ready network
AstarSmart-contract focused network
Any SubstrateUser-defined chain

Handle Errors

try {
const callResult = await provider.web3SignPayload(payload);
} catch (error) {
if (error.message === "Cancelled") {
console.log("Signing was canceled by the user");
} else {
console.error("Signature generation failed:", error);
}
}

Use with React

import { useState, useEffect } from "react";
import { web3Enable, web3Accounts } from "@polkadot/extension-dapp";

function usePolkadotAccounts() {
const [accounts, setAccounts] = useState([]);
const [isConnected, setIsConnected] = useState(false);

const connect = async () => {
const extensions = await web3Enable("UKey Wallet Demo");
if (extensions.length > 0) {
const allAccounts = await web3Accounts();
setAccounts(allAccounts);
setIsConnected(true);
}
};

return { accounts, isConnected, connect };
}