当一个交易包含一个可花费的输入(例如一个硬币)时,它必须包含该硬币所有者的签名才能被花费。如果硬币所有者也提交了交易,那么这是直截了当的。但是,如果需要外部地址对交易进行签名,则交易必须包含多个签名。在 SDK 中,可以通过在交易请求上调用 addAccountWitnesses
来添加帐户签名到交易中。
考虑一个需要两个签名才能花费的脚本:
script;
use std::{b512::B512, ecr::ec_recover_address, tx::{tx_id, tx_witness_data}};
fn main(signer: b256) -> bool {
let witness_data: B512 = tx_witness_data(1);
let address: b256 = ec_recover_address(witness_data, tx_id()).unwrap().bits();
return address == signer;
}
在上面的代码片段中,我们使用内置的 Sway 函数 tx_witness_data()
来检索见证签名和 tx_id()
来获取交易哈希。然后,我们检索签名地址以验证脚本。
我们可以通过从调用范围创建一个交易请求来在 SDK 中与此脚本进行交互。对于合约也是一样。考虑以下脚本:
// #import { Script };
const script = new Script(bytecode, abi, sender);
const { value } = await script.functions
.main(signer.address.toB256())
.addTransfer({
destination: receiver.address,
amount: amountToReceiver,
assetId: baseAssetId,
})
.addSigners(signer)
.call<BN>();
同样的方法也可以用于断言,通过实例化并将其添加到交易请求中。考虑以下断言:
predicate;
use std::{b512::B512, ecr::ec_recover_address, tx::{tx_id, tx_witness_data}};
fn main(signer: b256) -> bool {
let witness_data: B512 = tx_witness_data(1);
let address: b256 = ec_recover_address(witness_data, tx_id()).unwrap().bits();
return address == signer;
}
我们可以通过以下实现在 SDK 中与此断言进行交互:
// #import { Predicate, ScriptTransactionRequest };
// Create and fund the predicate
const predicate = new Predicate<[string]>({
bytecode,
abi,
provider,
inputData: [signer.address.toB256()],
});
const tx1 = await sender.transfer(predicate.address, 200_000, baseAssetId);
await tx1.waitForResult();
// Create the transaction request
const request = new ScriptTransactionRequest();
request.addCoinOutput(receiver.address, amountToReceiver, baseAssetId);
// Get the predicate resources and add them and predicate data to the request
const resources = await predicate.getResourcesToSpend([
{
assetId: baseAssetId,
amount: amountToReceiver,
},
]);
request.addResources(resources);
request.addWitness('0x');
// Add witnesses including the signer
// Estimate the predicate inputs
const txCost = await provider.getTransactionCost(request, {
signatureCallback: (tx) => tx.addAccountWitnesses(signer),
resourcesOwner: predicate,
});
request.updatePredicateGasUsed(txCost.estimatedPredicates);
request.gasLimit = txCost.gasUsed;
request.maxFee = txCost.maxFee;
await predicate.fund(request, txCost);
await request.addAccountWitnesses(signer);
// Send the transaction
const res = await provider.sendTransaction(request);
await res.waitForResult();