Cosmos
UKey Wallet Cosmos Provider is used to connect Cosmos ecological chain accounts, sign transactions, broadcast transactions and integrate with CosmJS in web applications. The page is accessible via window.$ukey.cosmos.
UKey Wallet Cosmos Provider is compatible with the Keplr wallet interface. Existing Keplr access usually only requires adjusting the Provider detection entrance.
Fast Links
Find Provider
// Note: Detect UKey Wallet Cosmos provider
const provider = window.$ukey?.cosmos;
if (!provider) {
throw new Error("UKey Wallet Cosmos provider not detected");
}
// Note: Check if it is UKey Wallet
console.log("Detected provider:", provider.isUKey ? "UKey Wallet" : "Unrecognized");
Get Going
Enable target chain
const chainId = "cosmoshub-4";
// Note: Enable chain - returns key information
const key = await provider.enable(chainId);
// Note: Or enable multiple chains at the same time
await provider.enable(["cosmoshub-4", "osmosis-1", "juno-1"]);
Read account information
const chainId = "cosmoshub-4";
const key = await provider.getKey(chainId);
console.log({
name: key.name, // Note: Account name
algo: key.algo, // signing algorithm, for instance secp256k1
pubKey: key.pubKey, // public key as a Uint8Array
address: key.address, // Bech32 address as Uint8Array
bech32Address: key.bech32Address, // Note: Bech32 format address
isNanoLedger: key.isNanoLedger, // Note: Hardware wallet logo
});
chain management
Add custom chain
If the target chain does not yet have built-in support, you can provide the chain configuration via experimentalSuggestChain and request the user to add it:
await provider.experimentalSuggestChain({
chainId: "my-chain-1",
chainName: "My Custom Chain",
rpc: "https://rpc.mychain.io",
rest: "https://lcd.mychain.io",
bip44: { coinType: 118 },
bech32Config: {
bech32PrefixAccAddr: "mychain",
bech32PrefixAccPub: "mychainpub",
bech32PrefixValAddr: "mychainvaloper",
bech32PrefixValPub: "mychainvaloperpub",
bech32PrefixConsAddr: "mychainvalcons",
bech32PrefixConsPub: "mychainvalconspub",
},
currencies: [
{
coinDenom: "TOKEN",
coinMinimalDenom: "utoken",
coinDecimals: 6,
},
],
feeCurrencies: [
{
coinDenom: "TOKEN",
coinMinimalDenom: "utoken",
coinDecimals: 6,
gasPriceStep: { low: 0.01, average: 0.025, high: 0.04 },
},
],
stakeCurrency: {
coinDenom: "TOKEN",
coinMinimalDenom: "utoken",
coinDecimals: 6,
},
});
Unlink
await provider.disconnect();
Msg Sign
Amino signature
Amino is suitable for Cosmos transactions that still use traditional encoding:
const chainId = "cosmoshub-4";
const signer = "cosmos1demoaccount...";
const signDoc = {
chain_id: chainId,
account_number: "0",
sequence: "0",
fee: {
amount: [{ denom: "uatom", amount: "5000" }],
gas: "200000",
},
msgs: [
{
type: "cosmos-sdk/MsgSend",
value: {
from_address: signer,
to_address: "cosmos1demoaccount...",
amount: [{ denom: "uatom", amount: "1000000" }],
},
},
],
memo: "",
};
const callResult = await provider.signAmino(chainId, signer, signDoc);
console.log({
signed: callResult.signed, // Note: Signed document
signature: callResult.signature, // Example response: { pub_key, signature }
});
Direct signature (Protobuf)
Direct signature is suitable for modern Protobuf encoding transactions and is also the more common method for most new accesses:
import { makeSignDoc } from "@cosmjs/proto-signing";
const chainId = "cosmoshub-4";
const signer = "cosmos1demoaccount...";
const signDoc = makeSignDoc(
bodyBytes, // Note: trading body
authInfoBytes, // Note: Authorization information including handling fee
chainId,
accountNumber,
);
const callResult = await provider.signDirect(chainId, signer, signDoc);
console.log({
signed: callResult.signed,
signature: callResult.signature,
});
Sign arbitrary data
Arbitrary message signatures are suitable for login authentication or off-chain attestation. Add domain name, nonce and timestamp to the message:
const chainId = "cosmoshub-4";
const signer = "cosmos1demoaccount...";
const data = "Login to MyApp at 2024-01-01T00:00:00Z";
const signature = await provider.signArbitrary(chainId, signer, data);
// Validate signature
const isValid = await provider.verifyArbitrary(
chainId,
signer,
data,
signature,
);
console.log("Signature check passed:", isValid);
Send tx
broadcast deal
const chainId = 'cosmoshub-4'
const txBytes = new Uint8Array([...]) // Note: Signed transaction bytes
// Available broadcast modes: 'block', 'sync', 'async'
const callResult = await provider.sendTx(chainId, txBytes, 'sync')
console.log('Tx hash:', callResult)
Offline Signer
You can get the offline signer from Provider and then hand it over to CosmJS to construct and send the transaction:
import { SigningStargateClient } from "@cosmjs/stargate";
const chainId = "cosmoshub-4";
// Note: Automatically detect the best signer type
const offlineSigner = await provider.getOfflineSignerAuto(chainId);
// Note: or use a specific signer type
const aminoSigner = provider.getOfflineSignerOnlyAmino(chainId);
const directSigner = provider.getOfflineSigner(chainId);
// Note: Use with CosmJS
const client = await SigningStargateClient.connectWithSigner(
"https://rpc.cosmos.network",
offlineSigner,
);
// Note: Send tokens
const callResult = await client.sendTokens(
senderAddress,
recipientAddress,
[{ denom: "uatom", amount: "1000000" }],
{ amount: [{ denom: "uatom", amount: "5000" }], gas: "200000" },
);
API Notes
Methods
| Method | Details |
|---|---|
enable(chainIds) | Enable the chain and get key information |
disable(chainIds) | Disable chain |
disconnect() | Disconnect all chains |
getKey(chainId) | Get the account key of the chain |
signAmino(chainId, signer, signDoc) | Sign Amino encoded transactions |
signDirect(chainId, signer, signDoc) | Sign Protobuf-encoded transactions |
sendTx(chainId, tx, mode) | Broadcast a signed transaction |
signArbitrary(chainId, signer, data) | Sign any message |
verifyArbitrary(chainId, signer, data, signature) | Verify signature |
experimentalSuggestChain(chainInfo) | Add a custom chain |
getOfflineSigner(chainId) | Get the Direct offline signer |
getOfflineSignerOnlyAmino(chainId) | Get the Amino-only offline signer |
getOfflineSignerAuto(chainId) | Automatically detect the best signer type |
Key interface
interface Key {
name: string; // Note: human readable name
algo: string; // Note: Signature algorithm
pubKey: Uint8Array; // Public key bytes
address: Uint8Array; // Note: address byte
bech32Address: string; // Note: Bech32 format address
isNanoLedger: boolean; // whether this comes from a hardware wallet
isKeystone: boolean; // whether the device is a Keystone wallet
}
Chain List
| Network | Chain ID | Native support |
|---|---|---|
| Cosmos Hub | cosmoshub-4 | yes |
| Osmosis | osmosis-1 | yes |
| Juno | juno-1 | yes |
| Stargaze | stargaze-1 | yes |
| Akash | akashnet-2 | yes |
| Secret Network | secret-4 | yes |
| User-defined chain | Any chain ID | Add it with experimentalSuggestChain |
Handle Errors
try {
await provider.enable("cosmoshub-4");
} catch (error) {
if (error.code === 4001) {
console.log("The user declined the request");
} else if (error.message.includes("not supported")) {
console.log("This chain is unsupported; try experimentalSuggestChain instead");
} else {
console.error("Unable to connect:", error);
}
}
Migrate from Keplr
UKey Wallet Cosmos Provider is compatible with the Keplr interface. During migration, UKey Wallet is read first, and then falls back to Keplr if it is not installed:
// 旧写法(仅 Keplr)
const keplrProvider = window.keplr;
// Updated flow: prefer UKey Wallet first, then fall back to Keplr
const cosmosProvider = window.$ukey?.cosmos || keplrProvider;