v0.34.0
What's Changed
- feat!: add predicates abigen by @hal3e in #726
- fix: logging with multiple(external) logs by @hal3e in #751
- Remove empty doc section on scripts by @MujkicA in #760
- fix: fix transfer script by @iqdecay in #761
- Add estimate tx dependencies to docs by @MujkicA in #756
- Automatic fee payment with modified inputs by @Salka1988 in #748
- fix: field
time
inHeader
andTransactionResponse
by @cheng404 in #739 - feat!: support logs from external contracts by @hal3e in #762
- fix: do not modify receipts by @hal3e in #777
- refactor: include fuel-abi-types crate by @Salka1988 in #776
- feat!: new
abigen!
,setup_contract_test!
, and handling of shared types by @segfault-magnet in #763 - refactor!: reorganize types by @hal3e in #779
- Bump CI forc to 0.33 by @MujkicA in #782
- Bump versions to 0.34.0 by @digorithm in #787
- Remove --no-verify flag by @digorithm in #788
- Bring back --no-verify flag by @digorithm in #789
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