跳到主要内容

Cardano

UKey Wallet Cardano Provider 用于在 Web 应用中连接 Cardano 钱包、读取地址和 UTxO、签名交易、确认提交交易以及签名链下数据。页面中可通过 window.cardano.ukey 访问,也提供 window.cardano.nami 兼容入口。

ℹ️

UKey Wallet 实现 CIP-30 Cardano dApp Connector,并提供 Nami 兼容性,方便现有 Cardano DApp 迁移。


快捷链接


找 Provider

// UKey Wallet 同时暴露 ukey 与 nami 两套接口
const ukey = window.cardano?.ukey;
const nami = window.cardano?.nami;

// 确认是否可用
if (!ukey) {
throw new Error("未检测到 UKey Wallet Cardano provider");
}

// 读取钱包信息
console.log("钱包名称:", ukey.name); // 'UKey Wallet'
console.log("API 版本号:", ukey.apiVersion); // '0.1.0'
console.log("图标地址:", ukey.icon);

快上手

请求启用钱包

// 向钱包申请访问授权
const api = await window.cardano.ukey.enable();

// 此时即可调用完整 API
const networkId = await api.getNetworkId();
console.log("当前网络:", networkId === 1 ? "主网" : "测试网");

检查是否已启用

const isEnabled = await window.cardano.ukey.isEnabled();

if (isEnabled) {
const api = await window.cardano.ukey.enable();
// 继续使用 API...
}

账户信息

读取网络 ID

const api = await window.cardano.ukey.enable();
const networkId = await api.getNetworkId();

// 0 表示测试网,1 表示主网
console.log("当前网络:", networkId);

读取余额

const balance = await api.getBalance();
// 返回值为 CBOR 编码内容(十六进制字符串)
console.log("CBOR 余额:", balance);

// 借助 cardano-serialization-lib 解码
import { Value } from "@emurgo/cardano-serialization-lib-browser";
const value = Value.from_bytes(Buffer.from(balance, "hex"));
const lovelace = value.coin().to_str();
console.log("当前余额:", parseInt(lovelace) // 1000000, "ADA");

读取地址

// 读取已使用地址(已有交易历史)
const usedAddresses = await api.getUsedAddresses();
console.log("已有使用记录的地址:", usedAddresses);

// 读取未使用地址(新地址)
const unusedAddresses = await api.getUnusedAddresses();
console.log("尚未使用的地址:", unusedAddresses);

// 读取找零地址
const changeAddress = await api.getChangeAddress();
console.log("找零用途地址:", changeAddress);

// 读取奖励/质押地址
const rewardAddresses = await api.getRewardAddresses();
console.log("奖励/质押地址:", rewardAddresses);

读取 UTxO

// 读取所有 UTxOs
const utxos = await api.getUtxos();
console.log("读取到的 UTxOs:", utxos);

// 读取满足最小金额的 UTxOs
const utxosWithAmount = await api.getUtxos(
"1000000", // 最低参考值为 1 ADA(CBOR 编码)
);

// 用分页方式读取
const paginatedUtxos = await api.getUtxos(undefined, {
page: 0,
limit: 10,
});

交易项

签交易

// transaction 这里要传 CBOR 编码后的十六进制字符串
const signedTx = await api.signTx(transactionCbor, partialSign);

// partialSign flag: boolean
// - false: 会把钱包持有的所有输入都签上
// - true: 只签那些明确归当前钱包所有的输入(适合多签)

console.log("签名后的交易数据:", signedTx);

确认提交交易

// 确认提交签名后的交易
const txHash = await api.submitTx(signedTransactionCbor);
console.log("交易哈希:", txHash);

完整交易流程

import {
TransactionBuilder,
TransactionBuilderConfigBuilder,
LinearFee,
BigNum,
Address,
TransactionOutput,
Value,
} from "@emurgo/cardano-serialization-lib-browser";

async function submitAdaTransfer(recipientAddress, amountLovelace) {
const api = await window.cardano.ukey.enable();

// 读取 UTxOs
const utxos = await api.getUtxos();
const changeAddress = await api.getChangeAddress();

// 组装交易
const txBuilder = TransactionBuilder.new(
TransactionBuilderConfigBuilder.new()
.fee_algo(LinearFee.new(BigNum.from_str("44"), BigNum.from_str("155381")))
.pool_deposit(BigNum.from_str("500000000"))
.key_deposit(BigNum.from_str("2000000"))
.max_value_size(5000)
.max_tx_size(16384)
.coins_per_utxo_byte(BigNum.from_str("4310"))
.build(),
);

// 从 UTxO 列表里补充输入项
utxos.forEach((utxo) => {
// 把 UTxO 添加为输入...
});

// 加入输出
txBuilder.add_output(
TransactionOutput.new(
Address.from_bech32(recipientAddress),
Value.new(BigNum.from_str(amountLovelace)),
),
);

// 配置找零地址
txBuilder.add_change_if_needed(Address.from_bech32(changeAddress));

// 组装交易
const tx = txBuilder.build_tx();
const txCbor = Buffer.from(tx.to_bytes()).toString("hex");

// 执行签名
const signedTxCbor = await api.signTx(txCbor, false);

// 执行确认提交
const txHash = await api.submitTx(signedTxCbor);
console.log("交易哈希:", txHash);

return txHash;
}

数据签名

签名数据 (CIP-8)

数据签名可用于登录认证、地址所有权证明和链下授权。建议在消息中加入 nonce 和应用来源:

const api = await window.cardano.ukey.enable();

const addresses = await api.getUsedAddresses();
const address = addresses[0];

// 这里准备待签名的消息内容
const payload = Buffer.from("Cardano demo message").toString("hex");

const signature = await api.signData(address, payload);

console.log({
signature: signature.signature, // COSE_Sign1 格式签名
key: signature.key, // COSE_Key 公钥数据
});

验证签名

import { COSESign1, COSEKey } from "@emurgo/cardano-message-signing-browser";

const coseSign1 = COSESign1.from_bytes(Buffer.from(signature.signature, "hex"));
const coseKey = COSEKey.from_bytes(Buffer.from(signature.key, "hex"));

// 读取签名后的 payload
const signedPayload = coseSign1.payload();

// 校验签名
const publicKey = coseKey.header(0); // 读取 Ed25519 密钥
// 校验逻辑...

事件流

看账户变化

const api = await window.cardano.ukey.enable();

// 兼容 Nami 的事件 API
api.experimental.on("accountChange", (addresses) => {
console.log("当前账户已切换为:", addresses);
});

API说明

钱包接口 (CIP-30)

属性/方法说明
name钱包名称 ('UKey Wallet')
icon钱包图标 URL
apiVersionAPI 版本要求
isEnabled()核验是否已启用
enable()请求钱包访问权限

dApp API(启用后)

方法说明
getNetworkId()获取网络 (0=测试网, 1=主网)
getBalance()获取总余额 (CBOR)
getUtxos(amount?, paginate?)获取 UTxOs
getUsedAddresses()获取已使用地址
getUnusedAddresses()获取未使用地址
getChangeAddress()获取找零地址
getRewardAddresses()获取质押地址
signTx(tx, partialSign?)签名交易
signData(addr, payload)签名数据 (CIP-8)
submitTx(tx)确认提交交易

实验性 API

方法说明
experimental.getCollateral()获取抵押 UTxOs
experimental.on(event, cb)订阅事件
experimental.off()取消订阅

类型集

type Cbor = string; // 以十六进制表示的 CBOR

interface Paginate {
page: number;
limit: number;
}

interface Cip30DataSignature {
signature: string; // COSE_Sign1 的十六进制结果
key: string; // COSE_Key 的十六进制结果
}

type NetworkId = 0 | 1; // 0 表示测试网,1 表示主网

事件流

事件说明
accountChange当前账户已切换

处理异常

try {
const api = await window.cardano.ukey.enable();
} catch (error) {
if (error.code === -1) {
console.log("用户拒绝了本次连接");
} else if (error.code === -2) {
console.log("没有返回可用账户");
} else {
console.error("执行报错:", error.message);
}
}

常见异常

错误码说明
-1用户取消了操作
-2未匹配到账户
-3网络参数不正确

使用 Lucid

Lucid 可以简化交易构造和确认提交流程:

npm install lucid-cardano
import { Lucid } from "lucid-cardano";

// 通过 UKey Wallet 初始化 Lucid
const lucid = await Lucid.new(
new Blockfrost("https://cardano-mainnet.blockfrost.io/api", "demo-api-key"),
"Mainnet",
);

// 连接 UKey Wallet 设备
const api = await window.cardano.ukey.enable();
lucid.selectWallet(api);

// 发起 ADA 转账
const tx = await lucid
.newTx()
.payToAddress("addr1demoexample...", { lovelace: 5000000n })
.complete();

const signedTx = await tx.sign().complete();
const txHash = await signedTx.submit();

console.log("交易哈希:", txHash);

使用 Mesh

Mesh 也可以直接使用浏览器钱包能力:

npm install @meshsdk/core
import { BrowserWallet, Transaction } from "@meshsdk/core";

// 建立到 UKey Wallet 的连接
const wallet = await BrowserWallet.enable("ukey");

// 读取钱包信息
const balance = await wallet.getBalance();
const addresses = await wallet.getUsedAddresses();

// 组装并发送交易
const tx = new Transaction({ initiator: wallet }).sendLovelace(
"addr1demoexample...",
"5000000",
);

const unsignedTx = await tx.build();
const signedTx = await wallet.signTx(unsignedTx);
const txHash = await wallet.submitTx(signedTx);

Nami 兼容性

如需兼容已有 Nami 接入,也可以通过 window.cardano.nami 使用同一套能力:

// 通过 Nami 接口调用
const nami = window.cardano.nami;
const api = await nami.enable();

// 与 UKey Wallet 保持一致的 API
const balance = await api.getBalance();