This guide focuses on the transition from the end of tool support for beta 3
to the start of beta 4
.
The team is constantly building. For updates on breaking changes beyond this guide, please refer to our bi-weekly report on GitHub or check announcements in our forum .
Update to the latest version of fuelup
:
fuelup self update
Install the beta-4
toolchain:
fuelup toolchain install beta-4
Set the beta-4
toolchain as your default:
fuelup default beta-4
You will get this output if everything went as intended:
default toolchain set to 'beta-4-aarch64-apple-darwin'
Fuel Wallet version 0.11.0
is not compatible with beta 4. For compatibility with beta-4, please download the non-backwards compatible Fuel Wallet version 0.12.3
.
pnpm install @fuel-wallet@0.12.3
We have already submitted the beta-4 compatible version to the Chrome Web Store, and it is currently under review. Once your users update to this version, they will no longer be able to interact with the contracts you currently have deployed on the beta-3 testnet.
Please follow the instructions provided below:
Integer types no longer implicitly cast to each other. Here are some examples of the changes:
// BEFORE - BETA 3
let y1: u16 = 4u8
// AFTER - BETA 4
let y1: u16 = 4u8.as_u16()
// BEFORE - BETA 3
let y3: u16 = 4u32
// AFTER - BETA 4
let y3: u16 = 4u32.try_as_u16().unwrap()
The standard library introduced read()
, write()
, and try_read()
methods to contract storage. Use try_read()
when possible to avoid potential issues with accessing uninitialized storage:
// BEFORE - BETA 3
let owner = storage.owner;
// AFTER - BETA 4
let owner = storage.owner.try_read().unwrap();
// BEFORE - BETA 3
storage.item_counter += 1;
// AFTER - BETA 4
storage.item_counter.write(storage.item_counter.read() + 1);
Function signatures in the standard library have changed:
// BEFORE - BETA 3
mint_to(amount, recipient);
// AFTER - BETA 4
mint_to(recipient, ZERO_B256, 1_000_000_000);
// BEFORE - BETA 3
transfer(amount, asset_id, recipient);
// AFTER - BETA 4
transfer(recipient, asset_id, amount);
Multi-token support, akin to Ethereum's ERC-1155, has now been natively introduced. This advancement enables the creation and destruction of unique subsidiary tokens within a single contract. These modifications will be incorporated into the standard library as std::token
. Actions involving burning
and minting
now necessitate the sub_id
of the token. Function signatures in the standard library have changed:
pub fn construct_asset_id(contract_id: ContractId, sub_id: SubId) -> AssetId {
sha256((contract_id, sub_id))
}
Additionally, AssetId
doesn't equate to ContractId
. Instead, it's calculated in alignment with the aforementioned changes:
// BEFORE - BETA 3
IncorrectAssetId: ContractId;
// AFTER - BETA 4
IncorrectAssetId: AssetId;
Changes disable_panic_on_overflow()
function to return the flags set
prior to calling the function:
// BEFORE - BETA 3
pub fn disable_panic_on_overflow()
// AFTER - BETA 4
pub fn disable_panic_on_overflow() -> u64
The rawPayload
property has been deprecated from the Receipt
struct.
For more details on the schema modification, please refer to the schema here .
// BEFORE - BETA 3
const receipt = new ReceiptCoder().decode(arrayify(gqlReceipt.rawPayload), 0)[0];
// AFTER - BETA 4
const receipt = assembleReceiptByType(gqlReceipt);
The .simulate()
method replacing .get()
is tailored for read-only calls and testing potential blockchain changes without committing them, while .call()
should be used for actions that modify the blockchain's state, keeping in mind that state-altering methods using .call()
will consume resources.
// BEFORE - BETA 3
let { value } = await contract.functions.get_count().get();
// AFTER - BETA 4
let { value } = await contract.functions.get_count().simulate();
The addResourceInputsAndOutputs
function has been renamed to addResources
, streamlining its name.
// BEFORE - BETA 3
request.addResourceInputsAndOutputs(resources);
// AFTER - BETA 4
request.addResources(resources);
Similarly, addPredicateResourcesInputsAndOutputs
is now more concisely known as addPredicateResources
.
The reason we have a distinct method for adding predicate resources is that the creation of predicate inputs mandates the presence of both the predicate’s bytes and data bytes.
With these methods, there’s no longer a need to manually create and set up an instance of a ScriptTransactionRequest
, simplifying the process further.
// BEFORE - BETA 3
const predicateInputs: TransactionRequestInput[] = predicateUtxos.map((utxo) => ({
id: utxo.id,
type: InputType.Coin,
amount: utxo.amount,
assetId: utxo.assetId,
owner: utxo.owner.toB256(),
txPointer: '0x00000000000000000000000000000000',
witnessIndex: 0,
maturity: 0,
predicate: predicate.bytes,
predicateData: predicate.predicateData,
}));
// AFTER - BETA 4
request.addPredicateResources(predicateUtxos, predicate.bytes, predicate.predicateData)
When providing contract IDs or addresses to contract functions, .into()
is not longer needed:
// BEFORE - BETA 3
let response = contract_methods
.transfer_coins_to_output(1_000_000, contract_id.into(), address.into())
.append_variable_outputs(1)
.call()
.await?;
// AFTER - BETA 4
let response = contract_methods
.transfer_coins_to_output(1_000_000, contract_id, address)
.append_variable_outputs(1)
.call()
.await?;
setup_contract_test
has been changed to setup_program_test
.
The command to generate bindings with Abigen has been modified; previously, it was Abigen(name="...")
, but now it requires the program type and should be written as Abigen(Program_Type(name="..."))
:
// BEFORE - BETA 3
setup_contract_test!(
Wallets("wallet"),
Abigen(name="MyContract", abi="some_folder")
);
// AFTER - BETA 4
setup_program_test!(
Wallets("wallet"),
Abigen(Contract(name = "MyContract", project = "some_folder")
// Other Program Types
// Abigen(Script(name = "MyScript", project = "some_folder"))
// Abigen(Predicate(name = "MyPredicate", project = "some_folder"))
)
);
Now supporting String types, there have been slight modifications if you directly use ParamTypes:
// BEFORE - BETA 3
ParamType::String(len) => Self::decode_string_array(bytes, *len),
ParamType::StdString => Self::decode_std_string(bytes),
// AFTER - BETA 4
ParamType::StringArray(len) => Self::decode_string_array(bytes, *len),
ParamType::String => Self::decode_std_string(bytes),
Contract deployment no longer takes contract binary and deploy configurations as a parameter but is instead loaded in:
// BEFORE - BETA 3
let id = Contract::deploy(
"./out/debug/contract.bin",
&wallet,
DeployConfiguration::default(),
)
.await?;
// AFTER - BETA 4
let storage_config =
StorageConfiguration::load_from("out/debug/contract-storage_slots.json").unwrap();
let load_config = LoadConfiguration::default().set_storage_configuration(storage_config);
let id = Contract::load_from(
"./out/debug/contract.bin", load_config
)?
.deploy(&wallet, TxParameters::default())
.await?;
Now, send_transaction(&tx)
immediately returns the transaction ID, which is used to retrieve the receipts:
// BEFORE - BETA 3
let receipts = self.try_provider()?.send_transaction(&tx).await?;
// AFTER - BETA 4
let tx_id = self.try_provider()?.send_transaction(&tx).await?;
let receipts = provider.get_receipts(&tx_id).await?;
The produce_blocks
function has been updated to no longer need time parameters:
// BEFORE - BETA 3
provider
.produce_blocks(100, Some(Utc.timestamp_opt(100, 0).unwrap()))
.await?;
// AFTER - BETA 4
provider
.produce_blocks(blocks_to_produce.into(), None)
AssetId
and ContractId
are no longer under the tx
package and has since been moved to the prelude
:
// BEFORE - BETA 3
use fuels::{prelude::*, tx::AssetId, tx::ContractId};
// AFTER - BETA 4
use fuels::{prelude::*}
Default parameter functions now start with with_*
instead of set_*
:
/* BEFORE - BETA 3 */
let call_params = CallParameters::default().set_storage_configuration(price);
let call_params = CallParameters::default().set_amount(price);
/* AFTER - BETA 4 */
let call_params = CallParameters::default().with_storage_configuration(price);
let call_params = CallParameters::default().with_amount(price);
Was this page helpful?