Skip to main content

签名和发送交易

Sui 中的交易代表对特定功能的调用(比如调用智能合约函数),该调用会对输入进行执行,从而定义交易的结果。

输入可以是对象引用(可能是一个拥有对象、一个不可变对象或共享对象的引用),也可以是编码值(例如,用作 Move 调用参数的字节向量)。构建交易通常通过使用可编程交易块(PTB)完成,用户对交易进行签名,然后提交执行。

签名是使用钱包拥有的私钥提供的,其公钥必须与交易发送方的 Sui 地址一致。

Sui 使用 SuiKeyPair 生成签名,该签名与意图消息(intent || tx_data 的 bcs 字节的 Blake2b 哈希摘要)的 Blake2b 哈希摘要相对应。目前支持的签名方案有 Ed25519 PureECDSA Secp256k1ECDSA Secp256r1MultisigzkLogin

可以使用 SuiKeyPair 实例化 Ed25519 PureECDSA Secp256k1ECDSA Secp256r1 并用其对交易进行签名。请注意,本指南不适用于 MultisigzkLogin,有关说明,请参阅它们各自的页面(MultisigzkLogin)。

有了签名和交易字节,就可以提交交易以执行。

工作流程

以下高级过程描述了构建、签名和执行链上交易的整体工作流程:

  • 通过创建 TransactionBlock 来构建交易数据,其中包含多个交易链接。有关更多信息,请参见构建可编程交易块
  • SDK 的内置燃气估算和币选择选择燃气币。
  • 对交易进行签名以生成签名
  • 提交 TransactionBlock 及其签名以进行链上执行。
info

如果要使用特定的燃气币,请首先找到要用于支付燃气的燃气币对象 ID,并在 PTB 中明确使用它。如果没有燃气币对象,请使用 splitCoin 交易创建一个燃气币对象。拆分燃气币交易应该是 PTB 中的第一个交易调用。

示例

以下示例演示如何使用 Rust、TypeScript 或 Sui CLI 签署和执行交易。

使用 Sui TypeScript SDK 实例化密钥对以及通过 Sui TypeScript SDK 推导其公钥和 Sui 地址有多种方法。

    import { SuiClient, getFullnodeUrl } from '@mysten/sui.js/client';
import { TransactionBlock } from '@mysten/sui.js/transactions';
import { type Keypair } from '@mysten/sui.js/cryptography';
import { Ed25519Keypair } from '@mysten/sui.js/keypairs/ed25519';
import { Secp256k1Keypair } from '@mysten/sui.js/keypairs/secp256k1';
import { Secp256r1Keypair } from '@mysten/sui.js/keypairs/secp256r1';
import { fromHEX } from '@mysten/bcs';

const kp_rand_0 = new Ed25519Keypair();
const kp_rand_1 = new Secp256k1Keypair();
const kp_rand_2 = new Secp256r1Keypair();

const kp_import_0 = Ed25519Keypair.fromSecretKey(fromHex("0xd463e11c7915945e86ac2b72d88b8190cfad8ff7b48e7eb892c275a5cf0a3e82"));
const kp_import_1 = Secp256k1Keypair.fromSecretKey(fromHex("0xd463e11c7915945e86ac2b72d88b8190cfad8ff7b48e7eb892c275a5cf0a3e82"));
const kp_import_2 = Secp256r1Keypair.fromSecretKey(fromHex("0xd463e11c7915945e86ac2b72d88b8190cfad8ff7b48e7eb892c275a5cf0a3e82"));

// $MNEMONICS refers to 12/15/18/21/24 words from the wordlist, e.g. "retire skin goose will hurry this field stadium drastic label husband venture cruel toe wire". Refer to [Keys and Addresses](/concepts/cryptography/transaction-auth/keys-addresses.mdx) for more.
const kp_derive_0 = Ed25519Keypair.deriveKeypair("$MNEMONICS");
const kp_derive_1 = Secp256k1Keypair.deriveKeypair("$MNEMONICS");
const kp_derive_2 = Secp256r1Keypair.deriveKeypair("$MNEMONICS");

const kp_derive_with_path_0 = Ed25519Keypair.deriveKeypair("$MNEMONICS", "m/44'/784'/1'/0'/0'");
const kp_derive_with_path_1 = Secp256k1Keypair.deriveKeypair("$MNEMONICS", "m/54'/784'/1'/0/0");
const kp_derive_with_path_2 = Secp256r1Keypair.deriveKeypair("$MNEMONICS", "m/74'/784'/1'/0/0");

// replace `kp_rand_0` with the variable names above.
const pk = kp_rand_0.getPublicKey();
const sender = pk.toSuiAddress();

// create an example transaction block.
const txb = new TransactionBlock();
txb.setSender(sender);
txb.setGasPrice(5);
txb.setGasBudget(100);
const bytes = await txb.build();
const serializedSignature = (await keypair.signTransactionBlock(bytes)).signature;

// verify the signature locally
expect(await keypair.getPublicKey().verifyTransactionBlock(bytes, serializedSignature)).toEqual(true);

// define sui client for the desired network.
const client = new SuiClient({ url: getFullnodeUrl('testnet') });

// execute transaction.
let res = client.executeTransactionBlock({
transactionBlock: bytes,
signature: serializedSignature,
});
console.log(res);

注意事项

  1. 本指南演示了如何使用单个私钥进行签名。在设置更复杂的签名策略时,请参阅多重签名
  2. 类似地,本机 zkLogin 不遵循上述步骤,请参阅文档以了解如何推导 zkLogin 地址,并使用临时密钥对生成 zkLogin 签名。
  3. 如果决定实施自己的签名机制而不使用先前的工具,请参阅签名文档,了解每个方案的接受签名规范。
  4. Flag 是一个字节,用于区分签名方案。在签名文档中查看支持的方案及其标志。
  5. execute_transaction_block 端点接受一系列签名,因此应该包含正好一个用户签名,除非使用的是赞助交易,其中可以提供用于 gas 对象的第二个签名。有关更多信息,请参阅赞助交易