此示例演示了 DID Connect 的一个常见且强大的用例:请求用户签署并提交链上交易以进行支付。此模式非常适合电子商务结账、服务订阅、内容购买或任何需要转移代币或资产的场景。
我们将使用 signature 声明来要求用户签署一个预先构建的代币转移交易。
工作原理
该过程涉及应用程序创建一个交易,然后请求用户的钱包进行签名。这确保了用户对其资产保持完全控制,并且应用程序永远不会处理用户的私钥。
以下是典型的流程:
交易创建
应用程序的后端确定支付的详细信息(例如,金额、代币类型、接收方地址),并使用像
@ocap/client这样的库来构建原始交易。声明请求
应用程序启动一个 DID Connect 会话,并向用户请求一个
signature声明。原始交易数据被嵌入到此声明请求中。用户批准
用户的 DID 钱包接收到请求,解码交易,并显示一个人类可读的摘要(例如,“向‘我的应用’支付 100 ABC 代币”)。然后,用户可以选择使用其私钥批准并签署该交易。
响应处理
批准后,钱包将已签名的交易发送回应用程序。然后,应用程序可以验证签名并将交易广播到区块链以完成支付。
整个过程是安全且非托管的,提供了无缝的 Web3 支付体验。
代码示例
让我们构建一个示例,其中我们的应用程序向用户请求支付 100 个原生代币。
1. 配置 WalletAuthenticator
首先,使用你的应用程序的详细信息和链信息来设置 WalletAuthenticator。
交易支付认证器设置
import { WalletAuthenticator } from '@did-connect/lib';
import { fromRandom } from '@ocap/wallet';
// 你的应用程序钱包
const appWallet = fromRandom();
const auth = new WalletAuthenticator({
wallet: appWallet,
baseUrl: 'https://yourapp.com',
appInfo: {
name: '我的超棒应用',
description: '一个需要支付的应用。',
icon: 'https://yourapp.com/logo.png',
link: 'https://yourapp.com',
},
chainInfo: {
host: 'https://beta.abtnetwork.io/api',
id: 'beta',
},
});2. 定义签名声明
接下来,定义要请求的 claims。我们将使用单个 signature 声明。在声明函数内部,我们将构建交易。
这需要使用 @ocap/client 来编码交易,并使用 @ocap/util 将生成的缓冲区转换为 Base58 字符串,这是钱包所期望的格式。
创建交易签名声明
import Client from '@ocap/client';
import { fromPublicKey } from '@ocap/wallet';
import { toBase58 } from '@ocap/util';
const client = new Client('https://beta.abtnetwork.io/api');
const NATIVE_TOKEN_ADDRESS = 'z35nB2SA6xxBuoaiuUXUw6Gah2SNU3UzqdgEt'; // ArcBlock 链上的原生代币
// 为 Express.js 处理程序定义声明
const claims = {
signature: async ({ userDid, userPk }) => {
// 1. 构建交易对象
const txPayload = {
tx: {
from: userDid,
pk: userPk,
itx: {
to: appWallet.address, // 将款项发送到应用的地址
tokens: [
{
address: NATIVE_TOKEN_ADDRESS,
value: '100000000000000000000', // 100 个代币(18 位小数)
},
],
},
},
wallet: fromPublicKey(userPk),
};
// 2. 将交易编码到缓冲区中
const encoded = await client.encodeTransferV2Tx(txPayload);
// 3. 为钱包返回声明对象
return {
type: 'fg:t:transaction', // 指定一个原生框架交易
data: toBase58(encoded.buffer), // 交易数据必须是 Base58 编码的
description: '签署此交易以完成您的 100 个代币的支付。',
// requirement 对象用于钱包向用户显示清晰的摘要
requirement: {
tokens: [
{
address: NATIVE_TOKEN_ADDRESS,
value: '100000000000000000000',
},
],
},
};
},
};
// 在你的路由处理程序中,你将生成请求 URL
// const signed = await auth.sign({ context: { userDid, userPk }, claims });在此示例中:
userDid和userPk在用户连接钱包后由 DID Connect 会话上下文提供。- 我们使用
client.encodeTransferV2Tx来创建一个标准的代币转移交易。 to地址是我们的应用程序钱包地址,资金将被发送到这里。requirement对象对于良好的用户体验至关重要。它允许钱包解析交易,并向用户准确地显示他们被要求支付的内容,从而防止他们签署恶意或不正确的交易。
3. 处理钱包的响应
在用户在钱包中签署交易后,你的应用程序的回调端点将收到已签名的交易数据。然后你可以再次使用像 @ocap/client 这样的库将其广播到区块链。
有关设置处理程序以处理钱包响应的完整指南,请参阅 处理钱包响应 指南。
这个例子涵盖了一个基本的 Web3 交互。通过利用 signature 声明,你可以安全地请求支付和其他链上操作,而无需托管用户密钥。
要查看声明的另一个实际应用,请查看 NFT 门控访问 示例。