⌘K

Send Spend Predicate

Icon Link断言中的签名示例

这是一个更复杂的示例,其中断言接受三个签名并将它们与三个预定义的公钥匹配。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);