断言可以用于验证交易。这意味着断言可以保护资产,仅当断言条件满足时才允许它们的转移。
本指南将演示如何使用断言发送和花费资金。
考虑以下断言:
predicate;
fn main(input_address: b256) -> bool {
let valid_address = 0xfc05c23a8f7f66222377170ddcbfea9c543dff0dd2d2ba4d0478a4521423a9d4;
input_address == valid_address
}
这个断言接受一个类型为 b256
的地址,并将其与相同类型的硬编码地址进行比较。如果两个地址相等,断言返回 true,否则返回 false。
让我们使用上面的断言来验证我们的交易。
一旦你编译了断言(forc build
),你将获得两个重要的工件:JSON ABI 和断言的二进制代码。这些需要用来实例化一个新的断言。
在这里我们还要传入断言的数据。注意我们断言示例中的 main
函数需要一个名为 input_address
类型为 b256
的参数。我们将把这个参数传递给 Predicate
构造函数,同时传入字节码和 JSON ABI。
const inputAddress = '0xfc05c23a8f7f66222377170ddcbfea9c543dff0dd2d2ba4d0478a4521423a9d4';
const predicate = new Predicate({
bytecode: bin,
provider,
abi,
inputData: [inputAddress],
});
注意:如果你想在实例化
Predicate
后传入断言数据,或者想使用与构造函数中传入的不同的数据,你将不得不创建一个新的Predicate
实例。
有了断言实例化后,我们可以将资金转移到它的地址。这要求我们有足够的资金的钱包。如果你对如何使用 SDK 中的钱包不确定,我们建议查阅我们的 钱包 指南。
const amountToPredicate = 1000;
const amountToReceiver = 200;
const tx = await walletWithFunds.transfer(predicate.address, amountToPredicate, baseAssetId, {
gasLimit: 1000,
});
let { isStatusSuccess } = await tx.waitForResult();
expect(isStatusSuccess).toBeTruthy();
现在我们的断言持有资金,我们可以使用它来验证交易,从而执行我们的转账。我们可以通过以下方式实现:
const receiverWallet = WalletUnlocked.generate({
provider,
});
const receiverInitialBalance = await receiverWallet.getBalance();
const tx2 = await predicate.transfer(
receiverWallet.address.toB256(),
amountToReceiver,
baseAssetId
);
({ isStatusSuccess } = await tx2.waitForResult());
expect(isStatusSuccess).toBeTruthy();
const receiverFinalBalance = await receiverWallet.getBalance();
expect(receiverFinalBalance.gt(receiverInitialBalance)).toBeTruthy();
({ isStatusSuccess } = await tx2.waitForResult());
expect(isStatusSuccess).toBeTruthy();
请注意,转移方法有两个参数:收件人的地址和拟转移的金额。
一旦断言基于其预定义条件解析出一个返回值 true
,我们的断言成功地通过转账将资金转移到目标钱包。
在类似的方法中,你可以使用 createTransfer
方法,它返回一个 ScriptTransactionRequest
。然后,我们可以通过调用 sendTransaction
方法提交此交易请求。
如果你需要在实际提交到节点之前知道交易 ID,这可能会有用。
const transactionRequest = await predicate.createTransfer(
receiverWallet.address,
amountToReceiver,
baseAssetId,
{
gasLimit: 1000,
}
);
const chainId = provider.getChainId();
const txId = transactionRequest.getTransactionId(chainId);
const res = await predicate.sendTransaction(transactionRequest);
await res.waitForResult();
试图转发断言持有的全部金额会导致错误,因为没有剩余资金来支付交易费用。尝试这样做会导致错误消息,如:
const errorMsg = 'not enough coins to fit the target';
当断言无法验证时会发生什么?回想一下,我们的断言只有在 input_address
匹配硬编码的 valid_address
时才会验证。因此,如果我们设置与 valid_address
不同的数据,断言将无法验证。
当断言无法验证时,SDK 抛出的错误如下所示:
const errorMsg = 'PredicateVerificationFailed';
在某些情况下,您可能希望在提交执行之前预分配断言交易。为此,您可以在 Predicate
类上使用 createTransfer
方法。
在以下示例中,我们正在预先配置一个交易,以便在实际提交交易之前知道交易 ID。
// Prepare the transaction
const preparedTx = await predicate.createTransfer(
receiverWallet.address,
transferAmount,
baseAssetId
);
// Get the transaction ID before sending the transaction
const txId = preparedTx.getTransactionId(provider.getChainId());
// Send the transaction
const res = await predicate.sendTransaction(preparedTx);
await res.waitForResult();