Algorand
UKey Wallet Algorand Provider is used to connect Algorand accounts, sign transactions, broadcast transactions and sign messages in web applications. The page is accessible via window.$ukey.algo.
ℹ️
UKey Wallet Algorand Provider supports both traditional interfaces and ARC-0001 compatible interfaces, making it easy to access new and old projects.
Fast Links
Find Provider
// Detect the UKey Wallet Algorand provider
const provider = window.$ukey?.algo;
if (!provider) {
throw new Error("UKey Wallet Algorand provider not detected");
}
// Verify compatibility
console.log("isUKey:", provider.isUKey); // Reference value: true
Get Going
Connect (legacy API)
const { address } = await provider.connect();
console.log("Connection established:", address);
// Verify connection state
console.log("isConnected:", provider.isConnected);
console.log("Resolved address:", provider.address);
Enable (ARC-0001)
const callResult = await provider.enable({
genesisID: "mainnet-v1.0",
genesisHash: "wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8=",
});
console.log("Selected account:", callResult.accounts);
console.log("Network genesis hash:", callResult.genesisHash);
Unlink
await provider.disconnect();
console.log("Connection closed");
Transfers
Signed transaction (ARC-0001)
The following example constructs a payment transaction, encodes it and gives it to the wallet for signature:
import algosdk from "algosdk";
// Build transaction
const suggestedParams = await algodClient.getTransactionParams().do();
const txn = algosdk.makePaymentTxnWithSuggestedParamsFromObject({
from: senderAddress,
to: recipientAddress,
amount: 1000000, // one ALGO (Micro Algos)
suggestedParams,
});
// Prepare for signing
const walletTxns = [
{
txn: Buffer.from(algosdk.encodeUnsignedTransaction(txn)).toString("base64"),
},
];
// Sign with the wallet
const signedTxns = await provider.signTxns(walletTxns);
console.log("Signed payload:", signedTxns);
Sign multiple transactions
// Group the transactions
const txns = [txn1, txn2, txn3];
algosdk.assignGroupID(txns);
// Prepare for signing
const walletTxns = txns.map((txn) => ({
txn: Buffer.from(algosdk.encodeUnsignedTransaction(txn)).toString("base64"),
}));
// Sign every transaction
const signedTxns = await provider.signTxns(walletTxns);
Partial signature (multiple signatures)
// Sign only selected transactions in the group
const walletTxns = [
{ txn: encodedTxn1 },
{ txn: encodedTxn2, signers: [] }, // Skip this one
{ txn: encodedTxn3 },
];
const signedTxns = await provider.signTxns(walletTxns);
// signedTxns[1] 在这种情况下会是 null
broadcast deal
Broadcast a signed transaction:
const callResult = await provider.postTxns(signedTxns);
console.log("Returned tx IDs:", callResult.txIDs);
Sign and broadcast
Complete signing and broadcasting in one step:
const callResult = await provider.signAndPostTxns(walletTxns);
console.log("Returned tx IDs:", callResult.txIDs);
Traditional trading API
Signature transaction (traditional)
// Build the transaction as Uint8Array
const txnBytes = algosdk.encodeUnsignedTransaction(txn);
// Sign with the wallet
const signedTxnBytes = await provider.signTransaction([txnBytes]);
// submit
const { txId } = await algodClient.sendRawTransaction(signedTxnBytes[0]).do();
Sign and send (traditional)
const callResult = await provider.signAndSendTransaction([txnBytes]);
console.log("Tx ID:", callResult.txId);
Msg Sign
Sign any message
const message = new TextEncoder().encode("Algorand sample message");
const { signature, address } = await provider.signMessage(
message,
"utf8", // 也可以改成 'base64'
);
console.log("Generated signature:", signature);
console.log("Recovered signer:", address);
Verify signature
import nacl from "tweetnacl";
const message = new TextEncoder().encode("Algorand sample message");
const { signature } = await provider.signMessage(message);
// Retrieve public key from address
const publicKey = algosdk.decodeAddress(provider.address).publicKey;
const isValid = nacl.sign.detached.verify(message, signature, publicKey);
console.log("Validation result:", isValid);
Event Flow
Watch Accounts
provider.on("accountChanged", (address) => {
if (address) {
console.log("Active account changed:", address);
} else {
console.log("Connection closed");
}
});
Listen for connections
provider.on("connect", ({ address }) => {
console.log("Connection established:", address);
});
provider.on("disconnect", () => {
console.log("Connection closed");
});
Using the Algod client
Get the client from Provider
// Retrieve a preconfigured client
const algodClient = await provider.getAlgodv2Client();
const indexerClient = await provider.getIndexerClient();
// Use the client
const status = await algodClient.status().do();
console.log("Reported network status:", status);
Manually set up the client
import algosdk from "algosdk";
const algodClient = new algosdk.Algodv2(
"", // 公共节点一般不需要 Token
"https://mainnet-api.algonode.cloud",
"",
);
const indexerClient = new algosdk.Indexer(
"",
"https://mainnet-idx.algonode.cloud",
"",
);
API Notes
Methods
| Method | Details |
|---|---|
connect() | Connected wallet (legacy) |
disconnect() | Disconnect wallet |
enable(opts?) | Enable wallet (ARC-0001) |
signTxns(transactions) | Signed Transaction (ARC-0001) |
postTxns(signedTxns) | Broadcast signed transactions |
signAndPostTxns(transactions) | Sign and broadcast |
signTransaction(txns) | Sign transaction (traditional) |
signAndSendTransaction(txns) | Sign and send (traditional) |
signMessage(message, encoding?) | Sign any message |
getAlgodv2Client() | Get the Algod client |
getIndexerClient() | Get Indexer client |
Types
interface EnableOpts {
genesisID?: string;
genesisHash?: string;
}
interface EnableResult {
genesisID: string;
genesisHash: string;
accounts: string[];
}
interface WalletTransaction {
txn: string; // Note: Base64 encoded unsigned transaction
signers?: string[]; // addresses that should sign (null means skip)
stxn?: string; // Note: Pre-signed transaction
message?: string; // Note: message displayed
msig?: MultisigMetadata;
authAddr?: string; // Note: Rekeyed auth address
}
interface SignTxnsResult {
// Base64 数组,对应已签名交易(null 表示跳过该项)
[index: number]: string | null;
}
interface PostTxnsResult {
txIDs: string[];
}
interface TransactionResult {
txId: string;
}
property
| Property | Type | Description |
|---|---|---|
isConnected | boolean | connection status |
address | string | null | Connected address |
isUKey | boolean | UKey Wallet logo |
Events
| Event | Inputs | Details |
|---|---|---|
connect | { address } | Wallet is connected |
disconnect | - | Wallet session closed |
accountChanged | address | Selected account changed |
Handle Errors
try {
const signedTxns = await provider.signTxns(walletTxns);
} catch (error) {
if (error.code === 4001) {
console.log("The user declined the request");
} else if (error.code === 4100) {
console.log("Wallet is locked");
} else {
console.error("Operation error:", error.message);
}
}
Common error codes
| Code | Description |
|---|---|
| 4001 | User rejected the request |
| 4100 | Authorization required |
| 4200 | Action is unavailable |
| 4300 | Input value is invalid |
Complete example
import algosdk from "algosdk";
async function submitAlgoTransfer() {
// establish connection
const provider = window.$ukey?.algo;
const { address } = await provider.connect();
// Set up the client
const algodClient = new algosdk.Algodv2(
"",
"https://mainnet-api.algonode.cloud",
"",
);
// Retrieve inputs
const suggestedParams = await algodClient.getTransactionParams().do();
// Build transaction
const txn = algosdk.makePaymentTxnWithSuggestedParamsFromObject({
from: address,
to: "TARGET_ACCOUNT_ADDRESS",
amount: 1000000, // one ALGO
suggestedParams,
});
// Sign with the wallet
const walletTxns = [
{
txn: Buffer.from(algosdk.encodeUnsignedTransaction(txn)).toString(
"base64",
),
},
];
const signedTxns = await provider.signTxns(walletTxns);
// submit
const { txId } = await algodClient
.sendRawTransaction(Buffer.from(signedTxns[0], "base64"))
.do();
console.log("Tx ID:", txId);
// Wait for confirmation
await algosdk.waitForConfirmation(algodClient, txId, 4);
console.log("Confirmation received!");
}