账户权限管理交易示例

以 2-of-3 多签账户为例,演示如何配置权限、构建交易、收集签名、检查权重并广播。

本文用一个 2-of-3 Owner 权限账户演示完整多签流程。Alice、Bob、Carol 三个地址共同控制账户,任意两方签名即可授权转账;任意一方单独签名都不能通过校验。

流程分为五步:配置权限、构建待签交易、收集签名、广播前检查签名权重、广播交易。

📘

前置阅读

场景

目标账户的 Owner 权限配置如下:

threshold: 2
keys:
  - Alice, weight: 1
  - Bob, weight: 1
  - Carol, weight: 1

Alice + Bob、Alice + Carol、Bob + Carol 都能授权交易;单个签名者不能授权。

第 1 步:配置 2-of-3 权限

第一次配置多签时,需要提交 AccountPermissionUpdateContract。这笔交易必须由账户当前生效的 Owner 权限签名;如果账户仍是默认单签状态,通常由原始账户私钥签名。

const updateTxn = await tronWeb.transactionBuilder.updateAccountPermissions(
  "TAccount...XX",   // owner_address: 要更新权限的账户
  {
    threshold: 2,
    keys: [
      { address: "TAlice...AA", weight: 1 },
      { address: "TBob1...BB",  weight: 1 },
      { address: "TCarol...CC", weight: 1 }
    ]
  },
  null,              // witness permission: 普通非 SR 账户传 null
  []                 // active permissions: 本示例不创建 Active 权限
);

const signedUpdate = await tronWeb.trx.sign(updateTxn, originalOwnerKey);
const updateResult = await tronWeb.trx.sendRawTransaction(signedUpdate);
console.log(updateResult.txid);

交易确认并固化后,账户 Owner 权限即变为 2-of-3 多签。

第 2 步:构建待共签交易

假设多签账户要向供应商转账 100 TRX。任意签名者都可以先构建一笔未完成签名的交易:

const txn = await tronWeb.transactionBuilder.sendTrx(
  "TVendor...DD",    // 接收方
  100_000_000,       // 100 TRX,单位为 sun
  "TAccount...XX"    // 发送方:多签账户
);

// 显式指定使用 Owner 权限签名。省略时通常也会走 Owner,但多签流程建议明确写出。
txn.raw_data.contract[0].Permission_id = 0;

Permission_id = 0 表示这笔交易使用 Owner 权限校验。若要使用 Active 权限,应填写对应的 Permission_id(通常为 2 到 9),并确保该 Active 权限的 operations 位图允许当前合约类型。

第 3 步:收集签名

多签签名可以逐个追加。每个签名者拿到同一笔交易对象,用自己的私钥签名后,把部分签名交易交给下一位签名者。

Alice 先签名:

const signedByAlice = await tronWeb.trx.multiSign(txn, aliceKey, 0);
// signedByAlice.signature 现在包含 Alice 的签名

第三个参数 0 仍是 Permission_id,必须与交易希望使用的权限一致。

Bob 在 Alice 已签名的交易上继续追加签名:

const signedByAliceAndBob = await tronWeb.trx.multiSign(signedByAlice, bobKey, 0);
// signedByAliceAndBob.signature 现在包含 Alice 和 Bob 两个签名

此时签名权重为 1 + 1 = 2,已达到 Owner 权限阈值。Carol 不需要再签名。

第 4 步:广播前检查签名权重

广播前可以调用 wallet/getsignweight 检查交易是否已经满足权限阈值。这个接口不会广播交易,只返回当前签名集合的校验结果。

BASE_URL=https://api.trongrid.io
POST ${BASE_URL}/wallet/getsignweight
{
  "transaction": <signedByAliceAndBob 序列化结果>
}

典型响应如下:

{
  "approved_list": ["TAlice...AA", "TBob1...BB"],
  "current_weight": 2,
  "permission": {
    "threshold": 2,
    "keys": [...]
  },
  "result": {
    "code": "ENOUGH_PERMISSION"
  }
}

current_weight 大于或等于 permission.threshold,且 result.codeENOUGH_PERMISSION 时,交易可以广播。若仍缺签名,通常会返回 NOT_ENOUGH_PERMISSION。如果签名格式错误、权限不匹配或签名者不在目标权限的 keys 列表中,应先修正交易对象再广播。

第 5 步:广播交易

const result = await tronWeb.trx.sendRawTransaction(signedByAliceAndBob);
console.log(result.txid);

转账进入区块后,建议等待区块固化再视为最终完成。区块固化机制参见共识与 DPoS

💰

多签附加费

当一笔交易携带多个签名时, TRON 会对第一个签名之外的每个额外签名收取多签附加费。主网默认值为每个额外签名 1 TRX,由链参数 #23 getMultiSignFee 控制。上面的 2 签名交易除普通转账成本外,还会额外支付 1 TRX。

常见变体

Carol 替代 Bob 签名

Alice + Carol 与 Alice + Bob 等价。只要签名者都在 Owner 权限的 keys 列表中,且权重总和达到 2,交易即可通过。

添加第三个签名

Alice、Bob 已经达到阈值后,再追加 Carol 的签名不会让交易失败。总权重变为 3,仍然满足阈值。

不过,多出的签名会带来额外多签附加费。对高频业务路径而言,应避免收集超过阈值所需的签名。

出现权限外签名

如果一个不在 Owner 权限 keys 列表中的地址签了这笔交易,节点不会把它当成 0 权重忽略,而是会拒绝整笔交易。重复签名者、签名数量超过权限密钥数量等情况也会导致校验失败。

因此,多签系统在传递交易对象时应控制签名者集合,并在广播前调用 wallet/getsignweight

使用 Active 权限授权日常操作

日常付款不一定要动用 Owner 权限。可以创建一个只允许 TransferContract 的 Active 权限,并把 Permission_id 设置为该 Active 权限的 ID。这样,日常转账可由热密钥完成,权限变更、合约部署等高风险操作仍由 Owner 多签控制。

Active 权限配置参见账户权限管理

API

API说明
wallet/accountpermissionupdate配置或更新账户权限
wallet/getsignweight检查部分签名交易的当前权重
wallet/getapprovedlist查看已经签名的地址
wallet/broadcasttransaction广播完整签名交易

相关资源