跳到主要内容

交易支付

此示例演示了 DID Connect 的一个常见且强大的用例:请求用户签署并提交链上交易以进行支付。此模式非常适合电子商务结账、服务订阅、内容购买或任何需要转移代币或资产的场景。

我们将使用 signature 声明来要求用户签署一个预先构建的代币转移交易。

工作原理

该过程涉及应用程序创建一个交易,然后请求用户的钱包进行签名。这确保了用户对其资产保持完全控制,并且应用程序永远不会处理用户的私钥。

以下是典型的流程:

  1. 交易创建

    应用程序的后端确定支付的详细信息(例如,金额、代币类型、接收方地址),并使用像 @ocap/client 这样的库来构建原始交易。

  2. 声明请求

    应用程序启动一个 DID Connect 会话,并向用户请求一个 signature 声明。原始交易数据被嵌入到此声明请求中。

  3. 用户批准

    用户的 DID 钱包接收到请求,解码交易,并显示一个人类可读的摘要(例如,“向‘我的应用’支付 100 ABC 代币”)。然后,用户可以选择使用其私钥批准并签署该交易。

  4. 响应处理

    批准后,钱包将已签名的交易发送回应用程序。然后,应用程序可以验证签名并将交易广播到区块链以完成支付。

整个过程是安全且非托管的,提供了无缝的 Web3 支付体验。

代码示例

让我们构建一个示例,其中我们的应用程序向用户请求支付 100 个原生代币。

1. 配置 WalletAuthenticator

首先,使用你的应用程序的详细信息和链信息来设置 WalletAuthenticator

交易支付认证器设置

javascript
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 字符串,这是钱包所期望的格式。

创建交易签名声明

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

在此示例中:

  • userDiduserPk 在用户连接钱包后由 DID Connect 会话上下文提供。
  • 我们使用 client.encodeTransferV2Tx 来创建一个标准的代币转移交易。
  • to 地址是我们的应用程序钱包地址,资金将被发送到这里。
  • requirement 对象对于良好的用户体验至关重要。它允许钱包解析交易,并向用户准确地显示他们被要求支付的内容,从而防止他们签署恶意或不正确的交易。

3. 处理钱包的响应

在用户在钱包中签署交易后,你的应用程序的回调端点将收到已签名的交易数据。然后你可以再次使用像 @ocap/client 这样的库将其广播到区块链。

有关设置处理程序以处理钱包响应的完整指南,请参阅 处理钱包响应 指南。

这个例子涵盖了一个基本的 Web3 交互。通过利用 signature 声明,你可以安全地请求支付和其他链上操作,而无需托管用户密钥。

要查看声明的另一个实际应用,请查看 NFT 门控访问 示例。