这是一个更复杂的示例,其中断言接受三个签名并将它们与三个预定义的公钥匹配。ec_recover_address
函数用于从签名中恢复公钥。如果三个中提取的公钥中有两个与预定义的公钥匹配,则可以花费资金。请注意,签名顺序必须与预定义的公钥顺序相匹配。
predicate;
use std::{b512::B512, constants::ZERO_B256, ecr::ec_recover_address, inputs::input_predicate_data};
fn extract_public_key_and_match(signature: B512, expected_public_key: b256) -> u64 {
if let Result::Ok(pub_key_sig) = ec_recover_address(signature, ZERO_B256)
{
if pub_key_sig == Address::from(expected_public_key) {
return 1;
}
}
0
}
fn main(signatures: [B512; 3]) -> bool {
let public_keys = [
0xd58573593432a30a800f97ad32f877425c223a9e427ab557aab5d5bb89156db0,
0x14df7c7e4e662db31fe2763b1734a3d680e7b743516319a49baaa22b2032a857,
0x3ff494fb136978c3125844625dad6baf6e87cdb1328c8a51f35bda5afe72425c,
];
let mut matched_keys = 0;
matched_keys = extract_public_key_and_match(signatures[0], public_keys[0]);
matched_keys = matched_keys + extract_public_key_and_match(signatures[1], public_keys[1]);
matched_keys = matched_keys + extract_public_key_and_match(signatures[2], public_keys[2]);
matched_keys > 1
}
让我们使用 SDK 与断言交互。首先,让我们创建三个具有特定密钥的钱包。它们的哈希公钥已硬编码在断言中。然后我们创建接收方钱包,我们将使用它来花费断言资金。
let secret_key1: SecretKey =
"0x862512a2363db2b3a375c0d4bbbd27172180d89f23f2e259bac850ab02619301".parse()?;
let secret_key2: SecretKey =
"0x37fa81c84ccd547c30c176b118d5cb892bdb113e8e80141f266519422ef9eefd".parse()?;
let secret_key3: SecretKey =
"0x976e5c3fa620092c718d852ca703b6da9e3075b9f2ecb8ed42d9f746bf26aafb".parse()?;
let mut wallet = WalletUnlocked::new_from_private_key(secret_key1, None);
let mut wallet2 = WalletUnlocked::new_from_private_key(secret_key2, None);
let mut wallet3 = WalletUnlocked::new_from_private_key(secret_key3, None);
let mut receiver = WalletUnlocked::new_random(None);
接下来,让我们添加一些硬币,启动一个提供程序,并将其与钱包连接起来。
let asset_id = AssetId::zeroed();
let num_coins = 32;
let amount = 64;
let initial_balance = amount * num_coins;
let all_coins = [&wallet, &wallet2, &wallet3, &receiver]
.iter()
.flat_map(|wallet| {
setup_single_asset_coins(wallet.address(), asset_id, num_coins, amount)
})
.collect::<Vec<_>>();
let provider = setup_test_provider(all_coins, vec![], None, None).await?;
[&mut wallet, &mut wallet2, &mut wallet3, &mut receiver]
.iter_mut()
.for_each(|wallet| {
wallet.set_provider(provider.clone());
});
现在我们可以使用断言 abigen 为我们创建一个断言编码器实例。要现在花费锁定在断言中的资金,我们必须提供两个签名,其公钥与我们在断言中定义的公钥相匹配。在这个示例中,签名是从一个零数组生成的。
abigen!(Predicate(
name = "MyPredicate",
abi = "e2e/sway/predicates/signatures/out/release/signatures-abi.json"
));
let predicate_data = MyPredicateEncoder::default().encode_data(signatures)?;
let code_path = "../../e2e/sway/predicates/signatures/out/release/signatures.bin";
let predicate: Predicate = Predicate::load_from(code_path)?
.with_provider(provider)
.with_data(predicate_data);
接下来,我们将一些资产从一个钱包转移到创建的断言中。我们还确认资金确实已转移。
let amount_to_predicate = 512;
wallet
.transfer(
predicate.address(),
amount_to_predicate,
asset_id,
TxPolicies::default(),
)
.await?;
let predicate_balance = predicate.get_asset_balance(&asset_id).await?;
assert_eq!(predicate_balance, amount_to_predicate);
我们可以使用 Account 特性中的 transfer
方法来转移资产。如果断言数据正确,则 receiver
钱包将获得资金,我们将验证金额是否正确。
predicate
.transfer(
receiver.address(),
amount_to_predicate,
asset_id,
TxPolicies::default(),
)
.await?;
let receiver_balance_after = receiver.get_asset_balance(&asset_id).await?;
assert_eq!(
initial_balance + amount_to_predicate,
receiver_balance_after
);
let predicate_balance = predicate.get_asset_balance(&asset_id).await?;
assert_eq!(predicate_balance, 0);