跳到主要内容

Cosmos

UKey Wallet Cosmos Provider 用于在 Web 应用中连接 Cosmos 生态链账户、签名交易、广播交易并与 CosmJS 集成。页面中可通过 window.$ukey.cosmos 访问。

ℹ️

UKey Wallet Cosmos Provider 兼容 Keplr 钱包接口,现有 Keplr 接入通常只需调整 Provider 检测入口。


快捷链接


找 Provider

// 检查 UKey Wallet Cosmos provider
const provider = window.$ukey?.cosmos;

if (!provider) {
throw new Error("未检测到 UKey Wallet Cosmos provider");
}

// 确认是否为 UKey Wallet
console.log("识别到的 Provider:", provider.isUKey ? "UKey Wallet" : "未知");

快上手

启用目标链

const chainId = "cosmoshub-4";

// 启用链并返回密钥信息
const key = await provider.enable(chainId);

// 也可以一次启用多条链
await provider.enable(["cosmoshub-4", "osmosis-1", "juno-1"]);

读取账户信息

const chainId = "cosmoshub-4";
const key = await provider.getKey(chainId);

console.log({
name: key.name, // 账户显示名
algo: key.algo, // 签名方案(secp256k1)
pubKey: key.pubKey, // Uint8Array 公钥
address: key.address, // Bech32 地址,对应 Uint8Array
bech32Address: key.bech32Address, // Bech32 地址
isNanoLedger: key.isNanoLedger, // 是否标记为硬件钱包
});

链管理

添加自定义链

如果目标链尚未内置支持,可以通过 experimentalSuggestChain 提供链配置并请求用户添加:

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,
},
});

断连

await provider.disconnect();

消息签署

Amino 签名

Amino 适合仍使用传统编码的 Cosmos 交易:

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, // 已完成签名的文档
signature: callResult.signature, // 返回参考:{ pub_key, signature }
});

Direct 签名(Protobuf)

Direct 签名适合现代 Protobuf 编码交易,也是多数新接入更常用的方式:

import { makeSignDoc } from "@cosmjs/proto-signing";

const chainId = "cosmoshub-4";
const signer = "cosmos1demoaccount...";

const signDoc = makeSignDoc(
bodyBytes, // 交易 body
authInfoBytes, // 附带手续费的授权信息
chainId,
accountNumber,
);

const callResult = await provider.signDirect(chainId, signer, signDoc);

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

签名任意数据

任意消息签名适合登录认证或链下证明。建议在消息中加入域名、nonce 和时间戳:

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);

// 校验签名
const isValid = await provider.verifyArbitrary(
chainId,
signer,
data,
signature,
);
console.log("签名校验结果:", isValid);

发交易

广播交易

const chainId = 'cosmoshub-4'
const txBytes = new Uint8Array([...]) // 已完成签名的交易字节

// 广播模式可选:'block'、'sync'、'async'
const callResult = await provider.sendTx(chainId, txBytes, 'sync')

console.log('交易哈希值:', callResult)

离线签名器

可以从 Provider 获取离线签名器,再交给 CosmJS 构造和发送交易:

import { SigningStargateClient } from "@cosmjs/stargate";

const chainId = "cosmoshub-4";

// 自动判断最合适的签名器类型
const offlineSigner = await provider.getOfflineSignerAuto(chainId);

// 也可以换成指定的签名器类型
const aminoSigner = provider.getOfflineSignerOnlyAmino(chainId);
const directSigner = provider.getOfflineSigner(chainId);

// 结合 CosmJS 使用
const client = await SigningStargateClient.connectWithSigner(
"https://rpc.cosmos.network",
offlineSigner,
);

// 发起代币转账
const callResult = await client.sendTokens(
senderAddress,
recipientAddress,
[{ denom: "uatom", amount: "1000000" }],
{ amount: [{ denom: "uatom", amount: "5000" }], gas: "200000" },
);

API说明

方法集

方法说明
enable(chainIds)启用链并获取密钥信息
disable(chainIds)禁用链
disconnect()断开所有链的连接
getKey(chainId)获取链的账户密钥
signAmino(chainId, signer, signDoc)签名 Amino 编码的交易
signDirect(chainId, signer, signDoc)签名 Protobuf 编码的交易
sendTx(chainId, tx, mode)广播已签名的交易
signArbitrary(chainId, signer, data)签名任意消息
verifyArbitrary(chainId, signer, data, signature)验证签名
experimentalSuggestChain(chainInfo)添加自定义链
getOfflineSigner(chainId)获取 Direct 离线签名器
getOfflineSignerOnlyAmino(chainId)获取仅 Amino 离线签名器
getOfflineSignerAuto(chainId)自动检测最佳签名器类别

Key 接口

interface Key {
name: string; // 展示名称
algo: string; // 签名方案
pubKey: Uint8Array; // 公钥内容字节序列
address: Uint8Array; // 地址值字节
bech32Address: string; // Bech32 地址
isNanoLedger: boolean; // 是否来自硬件设备
isKeystone: boolean; // 是否属于 Keystone 设备
}

链列表

链 ID原生支持
Cosmos Hubcosmoshub-4
Osmosisosmosis-1
Junojuno-1
Stargazestargaze-1
Akashakashnet-2
Secret Networksecret-4
自定义链任意链 ID使用 experimentalSuggestChain 补充

处理异常

try {
await provider.enable("cosmoshub-4");
} catch (error) {
if (error.code === 4001) {
console.log("用户已拒绝本次请求");
} else if (error.message.includes("not supported")) {
console.log("当前链暂不支持,请尝试 experimentalSuggestChain");
} else {
console.error("连接未成功:", error);
}
}

从 Keplr 迁移

UKey Wallet Cosmos Provider 与 Keplr 接口兼容。迁移时优先读取 UKey Wallet,未安装时再回退到 Keplr:

// 旧写法(仅 Keplr)
const keplrProvider = window.keplr;

// 调整后(优先使用 UKey Wallet,Keplr 作为回退)
const cosmosProvider = window.$ukey?.cosmos || keplrProvider;