Predicate data

Let's consider the following predicate example:

predicate;

use std::inputs::input_predicate_data;

fn main() -> bool {
    let guessed_number: u64 = input_predicate_data(0);
    if guessed_number == 42 {
        return true;
    }
    false
}

With the Fuel Rust SDK, You can encode and send the predicate data through Predicate's encode_data():

        let predicate_data: Vec<u8> = predicate.encode_data(42_u64)?;

Keep on reading for the full example.

Notice how this predicate uses input_predicate_data(), a way for the predicate code to read the data the caller passed to it.

Like everything else in the FuelVM, this data follows the ABI encoding/decoding specification. When using the Fuel Rust SDK to pass data to this predicate, you must encode it properly.

Here's how you can do it. First, we set up the wallets, node, and predicate code:

        let provider_config = Config {
            utxo_validation: true,
            ..Config::local_node()
        };

        let wallets_config = WalletsConfig::new_multiple_assets(
            2,
            vec![AssetConfig {
                id: AssetId::default(),
                num_coins: 1,
                coin_amount: 1_000,
            }],
        );

        let wallets =
            &launch_custom_provider_and_get_wallets(wallets_config, Some(provider_config), None)
                .await;

        let first_wallet = &wallets[0];
        let second_wallet = &wallets[1];

        let predicate = Predicate::load_from( "../../packages/fuels/tests/predicates/predicate_data_example/out/debug/predicate_data_example.bin")?;

        let predicate_code = predicate.code();
        let predicate_address = predicate.address();

Next, we lock some assets in this predicate using the first wallet:

        // First wallet transfers amount to predicate.
        let _result = first_wallet
            .transfer(
                predicate_address,
                500,
                AssetId::default(),
                TxParameters::default(),
            )
            .await?;

        // Check predicate balance.
        let balance = first_wallet
            .get_provider()?
            .get_asset_balance(predicate_address, AssetId::default())
            .await?;

        assert_eq!(balance, 500);

Then, we try to unlock the amount and spend it using the second wallet, effectively sending the previously locked value to itself.

The predicate expects the data sent to it to be a u64 type with the value 42.

        // We use the Predicate's `encode_data()` to encode the data we want to
        // send to the predicate.

        let predicate_data: Vec<u8> = predicate.encode_data(42_u64)?;

        let amount_to_unlock = 500;

        let _result = second_wallet
            .spend_predicate(
                predicate_address,
                predicate_code,
                amount_to_unlock,
                AssetId::default(),
                second_wallet.address(),
                Some(predicate_data),
                TxParameters::default(),
            )
            .await?;

        // Predicate balance is zero.
        let balance = first_wallet
            .get_provider()?
            .get_asset_balance(predicate_address, AssetId::default())
            .await?;

        assert_eq!(balance, 0);

        // Second wallet balance is updated.
        let balance = second_wallet.get_asset_balance(&AssetId::default()).await?;
        assert_eq!(balance, 1500);

Note: if the data you're encoding is already a Vec<u8>, e.g., in the send and spend examples, then you don't need to call encode_predicate_data(), passing it as-is works.