Skip to content

v0.34.0

Compare
Choose a tag to compare
@digorithm digorithm released this 19 Jan 02:25
· 423 commits to master since this release
52f631b

What's Changed

New Contributors

Full Changelog: v0.33.0...v0.34.0

Breaking changes

New abigen! macro

This release includes a huge breaking change to how abigen! works and how users will interact with it. The main motivation for this change was a pretty big problem we recently discovered: what happens when you use a Sway library that shares types between contract A and contract B? You'd use a first abigen!() for the contract A and another abigen!() call for contract B. Since both contracts' JSON ABIs include the types coming from the library included... guess what? There's a conflict of generated types: the shared types in the library would be generated twice and, thus, be different types under the eyes of the Rust compiler. Not a good time!

To fix this, we've rebuilt the macro so that it's called only once, and it takes all necessary contracts, predicates, and scripts that you need. Now it looks like this:

abigen!(
    Contract(name="ContractA", abi="contract_a-abi.json"),
    Contract(name="ContractB", abi="contract_b-abi.json"),
    Script(name="SomeScript", abi="some_script-abi.json"),
    Predicate(name="SomePredicate", abi="some_predicate-abi.json"),
    // ...
);

Although it's a big breaking change, it's fairly easy to migrate:

abigen!(
    MyContract,
    "packages/fuels/tests/contracts/contract_test/out/debug/contract_test-abi.json"
);

Becomes

abigen!(
    Contract(name="MyContract", abi="packages/fuels/tests/contracts/contract_test/out/debug/contract_test-abi.json"),
);

Read the updated SDK book for more details about the new abigen!.

New setup_contract_test!

The new abigen! opened up the possibility of improving the old setup_contract_test! macro as well. Similarly to the old abigen! macro, if you had multiple contracts, you'd call setup_contract_test! multiple times, so you'd have many blocks like this:

setup_contract_test!(
    contract_instance,
    wallet,
    "packages/fuels/tests/contracts/contract_test"
);

Now, you can call setup_contract_test! just once, passing all your contracts, scripts, predicates, and deployments, all at once:

setup_contract_test!(
    Wallets("wallet"),
    Abigen(
        name = "TestContract",
        abi = "packages/fuels/tests/contracts/contract_test"
    ),
    Deploy(
        name = "contract_instance",
        contract = "TestContract",
        wallet = "wallet"
    ),
);

Generated types with non-unique names can now be accessed only by qualifying the type path (i.e., abigen_bindings::some_contract_a_mod::SomeNonUniqueType). For more details, read the updated SDK book.

Predicate new send and receive API

Before, transferring the funds to a predicate looked like this:

wallet.transfer(
    predicate_address,
    amount_to_predicate,
    asset_id,
    TxParameters::default(),
).await?;

It started from the wallet, taking the predicate_address. Now, it starts from the predicate itself:

predicate.receive(&wallet, amount_to_predicate, asset_id, None).await?;

Similarly, spending a predicate also started from the wallet, which never really made much sense:

wallet.spend_predicate(
    predicate_address,
    predicate_code,
    amount_to_predicate,
    asset_id,
    receiver.address(),
    Some(predicate_data),
    TxParameters::default(),
).await?;

Now, it's a lot simpler, and it starts from the predicate, with the addition of a new encode_data() that you can use to pass the arguments of a predicate:

predicate
    .encode_data(signatures) // This is a new method; it'll encode the arguments for you.
    .spend(&receiver, amount_to_predicate, asset_id, None)
    .await?;

For more details, check the updated predicates in the latest docs.

Logging from external contracts

If your contract method is calling other contracts you will have to add the appropriate Inputs and Outputs to your transaction. For your convenience, the SDK provides two methods that can set those input and outputs for you: set_contracts(&[&contract_instance, ...]) and set_contract_ids(&[&contract_id, ...]).

set_contracts(&[&contract_instance, ...]) was changed and it now requires contract instances that were created using the abigen macro. When setting the external contracts with this method, logs and require revert errors originating from the external contract can be propagated and decoded by the calling contract. Here is an example:

let response = contract_caller_instance
    .methods()
    .increment_from_contract(lib_contract_id.into(), 42)
    .set_contracts(&[&lib_contract_instance])
    .call()
    .await?;

You can also have the old behavior where you used contact ids with the set_contract_ids(&[&contract_id, ...]) method. Please note that you will not get logs or require errors propagated if you use this approach. Here is an example:

let response = contract_caller_instance
        .methods()
        .increment_from_contract(lib_contract_id.into(), 42)
        .set_contract_ids(&[lib_contract_id.clone()])
        .call()
        .await?;

Better types importing experience

One piece of feedback we've received often is how hard it is to find and import fundamentals types exported by the fuels-rs crate. We're slowly addressing this by moving these types around to places where it makes sense for them to be.

In this release, we're re-exporting types in a single place — users will only care about this single place to pull types: fuels_types::core