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 Hub | cosmoshub-4 | 是 |
| Osmosis | osmosis-1 | 是 |
| Juno | juno-1 | 是 |
| Stargaze | stargaze-1 | 是 |
| Akash | akashnet-2 | 是 |
| Secret Network | secret-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;