Jesse A. Green / notebook

Fuel Rust SDK (fuels-rs) — Admin & Architecture Guide

Generated June 2026 from FuelLabs/fuels-rs at b404424

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

This guide is for the people who integrate the Fuel Rust SDK at scale, operate CI that depends on it, contribute to it, or need to reason about its internals and security model. It documents the workspace architecture, every crate's responsibility, the abigen codegen pipeline, the transaction lifecycle, the node‑launching machinery, configuration surfaces, security considerations, and operational concerns.

It is derived from the SDK source at version 0.77.0 (commit b404424). For day‑to‑day usage, see the companion User Guide.

Note

fuels-rs is a library, not a deployable service. "Operations" here means: how it builds, how it talks to nodes, how to run its test suite and CI reliably, how to upgrade it safely, and how to contribute. There is no server to deploy — your application embeds the SDK.


1. Executive Summary

fuels-rs is the Rust SDK for the Fuel blockchain, published to crates.io as fuels. It is a Cargo workspace of 7 published library crates plus example crates, a WASM test crate, end‑to‑end tests, and four internal maintenance binaries.

Fact Value
Workspace version 0.77.0
Rust edition 2024 (MSRV 1.93.0)
License Apache-2.0
Resolver Cargo resolver 2
Target node fuel-core 0.48.x
VM / tx crates fuel-vm / fuel-tx 0.66.x
ABI tooling fuel-abi-types 0.15.3
Published crates fuels, fuels-core, fuels-accounts, fuels-programs, fuels-code-gen, fuels-macros, fuels-test-helpers
Primary consumers Rust developers building apps & contract test harnesses on Fuel

The SDK's value proposition is type‑safe, compile‑time‑checked interaction with Sway programs: a procedural macro (abigen!) turns a JSON ABI into Rust types and methods, so contract calls are checked by rustc rather than failing at runtime.

Important

This repository is the framework, not an application that uses it. Downstream users add fuels = "0.x" to their Cargo.toml. "Installation" means adding the crate and installing the Fuel toolchain (forc, fuel-core) — not running a binary from this repo. The four main.rs files in scripts/ are maintenance tooling, not the product.


2. Architecture

2.1 Workspace layout

fuels-rs/
├── packages/                  ← THE PRODUCT (7 published crates)
│   ├── fuels                  ← umbrella facade + prelude
│   ├── fuels-core             ← types, codec, traits, tx builders
│   ├── fuels-code-gen         ← ABI → Rust code generation (compile-time)
│   ├── fuels-macros           ← proc-macros (abigen!, derives, setup_program_test!)
│   ├── fuels-accounts         ← wallets, signers, provider, predicate
│   ├── fuels-programs         ← contracts, scripts, calls, executables
│   └── fuels-test-helpers     ← launch fuel-core, build test wallets
├── examples/                  ← reference crates (also doc-test sources)
│   ├── contracts, wallets, predicates, providers, codec,
│   │   types, macros, cookbook, debugging, rust_bindings
├── e2e/                       ← integration tests + Sway test fixtures
│   ├── tests/*.rs             ← the real cross-feature test suite
│   └── sway/**                ← ~150 small Sway programs (test fixtures, NOT product)
├── wasm-tests/                ← WASM compatibility tests (cdylib)
├── scripts/                   ← maintenance binaries (NOT shipped)
│   ├── change-log, check-docs, fuel-core-version, versions-replacer
└── docs/                      ← mdbook user documentation

Note

The bulk of the repository's file count — roughly 150 of the 186 "important" folders — is e2e/sway/**: tiny Sway contracts/scripts/predicates used as test fixtures. They are not part of the published SDK. The product surface is entirely in packages/.

2.2 Crate dependency layers

The seven crates form a clean dependency stack. Document and reason about them by responsibility layer, not alphabetically:

        ┌──────────────────────────────────────────────┐
 Layer 5│  fuels  (facade)                              │  umbrella crate + prelude
        └───────────────┬──────────────────────────────┘
                        │ re-exports everything below
        ┌───────────────┴───────────────┐
 Layer 4│ fuels-programs                 │ Contract/Script/Predicate calls,
        │   (contracts, scripts, calls)  │ executables, loaders, tx debug
        └───────────────┬───────────────┘
        ┌───────────────┴───────────────┐
 Layer 3│ fuels-accounts                 │ Provider, Wallet, Predicate,
        │   (provider, wallets, signers) │ signers, keystore, coin cache
        └───────────────┬───────────────┘
        ┌───────────────┴───────────────┐
 Layer 2│ fuels-core                     │ types, codec (ABI enc/dec),
        │   (types, codec, traits)       │ traits, transaction builders
        └───────────────┬───────────────┘
        ┌───────────────┴───────────────────────────────┐
 Layer 1│ fuels-code-gen  +  fuels-macros (compile-time) │ JSON ABI → Rust code
        └────────────────────────────────────────────────┘

 Cross-cutting: fuels-test-helpers (depends on accounts + core) launches nodes & wallets.
Layer Crate(s) Responsibility Who cares
5 — Facade fuels Re‑export everything; provide prelude End users
4 — Programs fuels-programs Deploy/call contracts, run scripts, predicate calls, loaders End users
3 — Accounts fuels-accounts Node connection, wallets, signers, predicates End users + ops
2 — Core fuels-core Types, ABI codec, traits, tx builders Everyone (foundational)
1 — Codegen fuels-code-gen, fuels-macros Compile‑time ABI→Rust Contributors
— Test fuels-test-helpers Launch fuel-core, build wallets Test authors

The dependency flow is strictly downward (no cycles): fuels-programs depends on fuels-accounts and fuels-core; fuels-accounts depends on fuels-core; fuels-core depends on fuels-code-gen and fuels-macros. The facade fuels depends on all of them.

2.3 The facade crate (fuels)

packages/fuels/src/lib.rs contains almost no logic — it is a re‑export hub organised into namespaced modules, plus a prelude:

Module Re‑exports
fuels::tx fuel_tx types: ConsensusParameters, Receipt, TxParameters, StorageSlot, …
fuels::client fuel_core_client FuelClient, pagination types (std only)
fuels::macros fuels_macros::* (abigen!, derives, setup_program_test!)
fuels::programs fuels_programs::*
fuels::core fuels_core::{Configurable, Configurables, codec, constants, offsets, traits}
fuels::crypto fuel_crypto::{Hasher, Message, PublicKey, SecretKey, Signature}
fuels::accounts fuels_accounts::*
fuels::types fuels_core::types::*
fuels::test_helpers fuels_test_helpers::* (std only)
fuels::prelude The curated "import‑everything" set used to bootstrap projects

Tip

When tracing where a prelude symbol actually lives, follow the facade's pub use. For example, Wallet → fuels_accounts::wallet::Wallet, abigen → fuels_macros, ABIEncoder → fuels_core::codec.


3. The Codegen Pipeline (Core IP)

The defining feature of fuels-rs is compile‑time generation of Rust bindings from a Sway program's JSON ABI. This is a two‑crate, compile‑time pipeline.

3.1 fuels-code-gen — the generator

fuels-code-gen turns an ABI into Rust token streams. Public surface (program_bindings):

pub use program_bindings::{Abi, Abigen, AbigenTarget, ProgramType};
  • ProgramType — Contract | Script | Predicate.
  • AbigenTarget — one program to generate (name + ABI + type).
  • Abigen — the engine that produces the TokenStream.
  • Sub‑modules: custom_types (struct/enum generation), resolved_type (Sway→Rust type resolution), generated_code, utils.

It depends on fuel-abi-types (parses/validates the JSON ABI), proc-macro2, quote, syn, and Inflector (identifier casing). Its encode_fn_selector helper computes the length‑prefixed selector bytes:

pub fn encode_fn_selector(name: &str) -> Vec<u8> {
    let bytes = name.as_bytes().to_vec();
    let len = bytes.len() as u64;
    [len.to_be_bytes().to_vec(), bytes].concat()
}

fuels-code-gen has its own lightweight Error(String) type with From impls for serde_json::Error, io::Error, proc_macro2::LexError, and fuel_abi_types::error::Error.

3.2 fuels-macros — the proc‑macro front end

fuels-macros is a proc-macro = true crate that wraps fuels-code-gen and exposes the user‑facing macros:

Macro Kind Purpose
abigen! function‑like Generate bindings for one or more programs
setup_program_test! function‑like Reduce test boilerplate (wallets/abigen/deploy)
#[derive(Tokenizable)] derive Implement Tokenizable for a type
#[derive(Parameterize)] derive Implement Parameterize for a type
#[derive(TryFrom)] derive Decode bytes directly into a type

Internally it is organised into abigen/, derive/, setup_program_test/, and parse_utils/. The setup_program_test! parser lives under setup_program_test/parsing/commands and recognises the Options, Wallets, Abigen, Deploy, and LoadScript commands.

3.3 Generated‑code shape

abigen! emits an abigen_bindings module containing one sub‑module per program (named after the binding's name), each holding that program's custom types and its binding struct. Types that are identical (same name and definition) across programs are lifted into a shared_types module and re‑exported back into each consumer.

Note

Type sharing only triggers when the name and the resolved definition match. Generating all programs in a single abigen! call is therefore important: it is the only way the generator sees all programs at once and can deduplicate shared types and avoid name collisions.

3.4 Lifecycle

forc build  ──►  *.bin (FuelVM bytecode)  +  *-abi.json (JSON ABI)
                                  │
                  abigen!(...) at compile time
                                  │
                fuels-macros ──► fuels-code-gen ──► fuel-abi-types (parse)
                                  │
                          generated Rust types + bindings
                                  │
                        rustc compiles your call sites

The generated code is purely a compile‑time artifact; there is no runtime codegen.


4. The Core Layer (fuels-core)

fuels-core is the foundational crate every other crate depends on. Modules: codec, traits, types, plus top‑level Configurable/Configurables and utilities.

4.1 Codec

fuels-core::codec implements the Fuel ABI argument encoding spec:

Item Role
ABIEncoder Encode Tokens → bytes; configurable via EncoderConfig
ABIDecoder Decode bytes + ParamType → Token; configurable via DecoderConfig
ABIFormatter Human‑readable decoding from a JSON ABI (used in tx debugging)
function_selector Compute function selectors
logs LogDecoder, LogId, LogResult for decoding contract logs
try_from_bytes<T> Decode bytes directly into T: Parameterize + Tokenizable

EncoderConfig/DecoderConfig expose max_depth and max_tokens as resource‑exhaustion guards.

4.2 Traits

Three load‑bearing traits live in fuels-core::traits:

Trait Contract
Tokenizable into_token() / from_token() — convert a Rust value ↔ ABI Token
Parameterize param_type() — describe a type's ABI schema (ParamType)
Signer sign(message) + address() — produce signatures

All abigen!‑generated types implement Tokenizable + Parameterize. The SDK also implements them for built‑in and many foreign types.

4.3 Types

fuels-core::types re‑exports the primitive fuel types from fuel-types (Address, AssetId, Bytes32, ContractId, Nonce, Salt, SubAssetId, Word, …) and adds SDK‑owned wrappers, param_types, transaction_builders, tx_status, tx_response, errors, checksum_address, and method_descriptor.

4.4 Configurables

Configurable/Configurables model deploy‑time/runtime constant overrides. A Configurable is { offset: u64, data: Vec<u8> }; Configurables is a vector of these plus an update_constants_in(&mut [u8]) that patches a binary in place. with_shifted_offsets adjusts offsets (used when code is relocated, e.g. loaders), with checked arithmetic that errors on overflow/underflow.

4.5 The error model

The SDK's unified error type is an enum with five variants:

Variant Meaning
Error::IO(String) Filesystem/network I/O failure
Error::Codec(String) ABI encode/decode failure
Error::Transaction(Reason) Transaction failed (Reason::Failure, Reason::Validation, …)
Error::Provider(String) Node/provider error
Error::Other(String) Everything else

Result<T> is std::result::Result<T, Error>. The error! macro constructs typed errors; Context/with_context add human‑readable context. A prepend_msg combinator (in fuels-programs) prefixes messages while preserving the variant.

Tip

When matching on call failures, the most useful pattern is Err(Error::Transaction(Reason::Failure { .. })) (the contract reverted/execution failed) vs Reason::Validation (the node rejected the tx before execution — bad witnesses, insufficient inputs, etc.).


5. The Accounts Layer (fuels-accounts)

This crate owns everything to do with identity, node connection, and resource selection.

5.1 The account traits

pub trait ViewOnlyAccount: Send + Sync {
    fn address(&self) -> Address;
    fn try_provider(&self) -> Result<&Provider>;
    async fn get_coins(&self, asset_id: AssetId) -> Result<Vec<Coin>>;
    async fn get_asset_balance(&self, asset_id: &AssetId) -> Result<u128>;
    async fn get_balances(&self) -> Result<HashMap<String, u128>>;
    async fn get_spendable_resources(&self, asset_id, amount, excluded) -> Result<Vec<CoinType>>;
    async fn get_asset_inputs_for_amount(...) -> Result<Vec<Input>>;
    fn get_asset_outputs_for_amount(...) -> Vec<Output>;
    async fn adjust_for_fee<Tb: TransactionBuilder>(&self, tb, used_base_amount) -> Result<()>;
    // ...
}

pub trait Account: ViewOnlyAccount {
    fn add_witnesses<Tb: TransactionBuilder>(&self, tb) -> Result<()>;
    async fn transfer(&self, to, amount, asset_id, tx_policies) -> Result<TxResponse>;
    async fn force_transfer_to_contract(&self, to, balance, asset_id, tx_policies) -> Result<TxResponse>;
    async fn withdraw_to_base_layer(&self, to, amount, tx_policies) -> Result<WithdrawToBaseResponse>;
}

Both Wallet and Predicate implement these. adjust_for_fee is the linchpin of fee handling: it computes the missing base‑asset amount (max_fee + reserved − available), pulls additional base inputs if needed, and adds a base‑asset change output.

5.2 The Wallet typestate

Wallet<S = Unlocked<PrivateKeySigner>> is a typestate machine:

pub struct Wallet<S> { state: S, provider: Provider }

pub struct Unlocked<S> { signer: S }   // has a signer → Account + ViewOnlyAccount
pub struct Locked { address: Address } // no signer  → ViewOnlyAccount only
  • Wallet<Unlocked<S>>::new(signer, provider) — a signing wallet (generic over any S: Signer).
  • Wallet::random(rng, provider) — random PrivateKeySigner.
  • wallet.lock() → Wallet<Locked> — drops the signer, keeps the address.

This is a compile‑time guarantee: you cannot call signing operations on a Wallet<Locked> because the methods only exist on Wallet<Unlocked<S>>.

5.3 Signers

fuels-accounts::signers provides:

Signer Module Feature flag
PrivateKeySigner signers::private_key (always)
AWS KMS signer signers::kms signer-aws-kms
Google KMS signer signers::kms signer-google-kms
FakeSigner signers::fake (always)

Derivation constants live in signers::derivation: BIP44_PURPOSE = "44'", COIN_TYPE = "1179993420'", DEFAULT_DERIVATION_PATH = "m/44'/1179993420'/0'/0/0".

5.4 The Provider

Provider wraps a CachedClient<RetryableClient> (and, with coin-cache, an Arc<Mutex<CoinsCache>>). It is the read/submit gateway to a node, layered:

Provider
  └── CachedClient        (caches consensus_parameters / node_info via TtlConfig)
        └── RetryableClient (retries on io::Error per RetryConfig/Backoff)
              └── FuelClient (fuel-core-client; GraphQL over HTTP, cynic-typed)

Construction: Provider::connect(url), Provider::connect_with_fallbacks(&[urls]), Provider::from(socket_addr). The raw FuelClient is reachable via provider.client() for queries the SDK doesn't wrap.

Notable provider responsibilities:

  • Transaction submission — send_transaction, send_transaction_and_await_commit, send_transaction_and_await_status (streaming statuses incl. preconfirmation). Before sending, prepare_transaction_for_sending precomputes the tx, and for predicate‑using transactions estimates and validates predicates.
  • Dry runs — dry_run, dry_run_opt, dry_run_multiple (and the DryRunner trait impl used for gas/variable‑output estimation).
  • Resource queries — get_coins, get_spendable_resources (via ResourceFilter), get_balances, get_contract_balances, paginated at 100 results/request.
  • Cost estimation — estimate_transaction_cost returns TransactionCost { gas_price, metered_bytes_size, total_fee, script_gas, total_gas }, applying a tolerance multiplier.
  • Chain/block/tx queries — chain_info, consensus_parameters, latest_block_height, produce_blocks, get_transaction_by_id, get_message_proof.
  • Caching — TtlConfig, set_cache_ttl, clear_cache.
  • Retry — with_retry_config(RetryConfig).

ResourceFilter and TransactionCost are documented inline (anchored for the user docs):

pub struct ResourceFilter {
    pub from: Address,
    pub asset_id: Option<AssetId>,
    pub amount: u128,
    pub excluded_utxos: Vec<UtxoId>,
    pub excluded_message_nonces: Vec<Nonce>,
}

5.5 The coin cache

With the coin-cache feature, the provider keeps a CoinsCache (default TTL 30 s) keyed by (Address, AssetId). On submit it records the spent coins; on a subsequent spend it excludes recently‑used coins and errors if you try to re‑spend one still in the cache. Failed/squeezed‑out transactions evict their coins.

Note

This is what protects you from accidentally double‑spending a UTXO across rapid back‑to‑back transactions. The cost is a 30‑second window where a just‑submitted coin appears unavailable. Tune via CoinsCache::new(ttl) semantics; disable by building without coin-cache.

5.6 Predicates

Predicate holds { address, code, data, provider }. Its address is derived purely from bytecode (fuel_tx::Input::predicate_owner(code)), so changing code or configurables changes the address (with_configurables re‑derives it). It implements ViewOnlyAccount and Account; its get_asset_inputs_for_amount produces Input::resource_predicate inputs (carrying code + data) rather than signed inputs.

5.7 Keystore

The Keystore (feature keystore) wraps eth-keystore to encrypt/decrypt SecretKeys with a password into a directory. save_key returns a UUID; load_key(uuid, password) recovers it. KeySaved is Zeroize/ZeroizeOnDrop.

5.8 GraphQL schema

fuels-accounts/src/schema/schema.sdl is the GraphQL SDL the cached client uses (via cynic). A test asserts it is byte‑identical to fuel_core_client::SCHEMA_SDL, catching schema drift between the SDK and the node.


6. The Programs Layer (fuels-programs)

This crate turns ABIs and bytecode into deployable/callable programs.

6.1 Contracts

Contract<Code> is generic over its code state (Regular vs Loader):

  • Contract::load_from(path, LoadConfiguration) — load a binary, auto‑load storage slots.
  • Contract::regular(code, salt, storage_slots) — construct manually.
  • contract_id() / state_root() / code_root() — computed without deploying, via compute_contract_id_and_state_root (FuelContract::id(salt, code_root, state_root)).
  • with_salt, with_storage_slots, with_configurables.
  • deploy(&account, TxPolicies), deploy_if_not_exists(...), smart_deploy(...).
  • convert_to_loader(max_words_per_blob) ↔ revert_to_regular().
  • loader_from_blobs(...) / loader_from_blob_ids(...), upload_blobs(...).

LoadConfiguration and StorageConfiguration drive loading; storage autoload reads <name>-storage_slots.json and fails with an Error::Other if the file is missing and autoload is on.

6.2 Calls

fuels-programs::calls is the calling machinery:

Item Role
CallHandler Builds, submits, simulates a call; new_multi_call for bundles
contract_call / script_call The two call kinds
receipt_parser Parse receipts into return values
Execution Simulation context: realistic() vs state_read_only(), .at_height(h)
traits, utils Shared call helpers

Execution defaults to realistic(). state_read_only() disables most validation (fake witnesses, fake gas, extra variable outputs) so unfunded accounts can read state.

6.3 Executables (scripts/predicates as blobs)

Executable<State> (Regular | Loader) handles pre‑uploading script/predicate code:

  • Executable::<Regular>::load_from(path) / from_bytes(code), with_configurables(...).
  • convert_to_loader() validates the code can become a loader, then yields Executable<Loader>.
  • Executable<Loader>::blob() extracts the code blob (minus data section); upload_blob(account) uploads it (idempotent — skips if blob_exists).
  • Configurables are applied to the data section; the blob excludes the data section so the same blob is reused across configurations.

6.4 Transaction debugging

fuels-programs::debug decodes raw FuelVM script bytecode:

pub enum ScriptType {
    ContractCall(Vec<ContractCallData>),
    Loader { script: ScriptCallData, blob_id: [u8; 32] },
    Other(ScriptCallData),
}

ScriptType::detect(script, data) disassembles the script (via fuel_asm), recognises a contract‑call instruction pattern, a loader pattern, or falls back to Other. Combined with ABIFormatter, this reconstructs human‑readable call signatures from on‑chain transactions.

6.5 Responses

fuels-programs::responses defines CallResponse<D> (value, receipts, gas_used, tx_id) and the submit‑response types for the submit/await‑later flow.

6.6 Assembly

fuels-programs::assembly (internal) builds the FuelVM instruction sequences: contract_call (the call‑opcode layout, gas‑forwarding variants), cursor, and script_and_predicate_loader (loader instruction generation, configurable‑section offset math).


7. The Test‑Helpers Layer (fuels-test-helpers)

fuels-test-helpers launches fuel-core and builds wallets/coins for tests.

7.1 Two node back ends

pub struct FuelService { /* ... */ }

impl FuelService {
    pub async fn start(node_config, chain_config, state_config) -> Result<Self>;
    pub async fn stop(&self) -> Result<State>;
    pub fn bound_address(&self) -> SocketAddr;
}
  • Default (binary) — fuel_bin_service spawns the fuel-core binary found on PATH (via which), parses its stderr for Binding GraphQL provider to <addr>, and manages the child process (kill_on_drop). Times out after 30 s waiting for the bound address.
  • fuel-core-lib feature — service.rs runs fuel-core in‑process via CoreFuelService::new_node with a full ServiceConfig (GraphQL query limits, combined DB config, gas‑price config, …).

The binary back end translates NodeConfig into CLI args (--db-type, --poa-instant/--poa-interval-period, --utxo-validation, --historical-execution, --debug, --starting-gas-price, --graphql-request-body-bytes-limit, --native-executor-version, …).

7.2 Node, chain, and state config

pub struct NodeConfig {
    pub max_database_cache_size: Option<usize>,
    pub database_type: DbType,            // InMemory | RocksDb(Option<PathBuf>)
    pub utxo_validation: bool,            // default true
    pub historical_execution: bool,       // default false
    pub debug: bool,                      // default true
    pub block_production: Trigger,        // default Instant
    pub vm_backtrace: bool,
    pub silent: bool,                     // default true
    pub starting_gas_price: u64,          // default 1
    pub graphql_request_body_bytes_limit: u64, // default u64::MAX
}

Trigger = Instant | Never | Interval { block_time } | Open { period }. ChainConfig and StateConfig are re‑exported from fuel-core-chain-config. The default test chain raises tx size and contract size limits (10 MB tx, 1 MB contract) over the stock testnet config.

7.3 Wallet & coin helpers

Helper Produces
launch_provider_and_get_wallet() 1 funded Wallet + node
launch_custom_provider_and_get_wallets(WalletsConfig, NodeConfig?, ChainConfig?) N wallets + node
setup_test_provider(coins, messages, NodeConfig?, ChainConfig?) a Provider
setup_single_asset_coins(owner, asset, n, amount) Vec<Coin>
setup_multiple_assets_coins(owner, n_assets, coins_per, amount) (Vec<Coin>, Vec<AssetId>)
setup_custom_assets_coins(owner, &[AssetConfig]) Vec<Coin>

WalletsConfig defaults: DEFAULT_NUM_WALLETS = 10, DEFAULT_NUM_COINS = 1, DEFAULT_COIN_AMOUNT = 1_000_000_000. Generated wallet secret keys are deterministic (a padded counter), giving reproducible addresses.

Important

Deterministic test wallets are a feature (reproducibility), not a weakness — but it also means test keys are trivially predictable. Never reuse a test‑helper wallet on a real network.


8. System Requirements

Concern Requirement
Rust toolchain stable, MSRV 1.93.0, edition 2024
forc To compile Sway programs and produce ABIs/binaries
fuel-core On PATH (binary back end) or the fuel-core-lib feature
WASM (optional) wasm32-unknown-unknown target + wasm-pack
OS Any Tier‑1 Rust platform; fuel-core binaries for Linux/macOS
Network Outbound HTTP/GraphQL to the target node; testnet faucet for funding

9. Configuration Reference

There are no environment variables or config files the SDK reads at runtime in your application — configuration is via Rust builder types. The relevant surfaces:

9.1 Transaction policies (TxPolicies)

Setter Effect
with_tip(u64) Block‑producer tip
with_witness_limit(u64) Max witness data size
with_maturity(u32) Earliest inclusion block
with_expiration(u32) Latest inclusion block
with_max_fee(u64) Fee ceiling
with_script_gas_limit(u64) Script gas cap (auto‑estimated if unset)

9.2 Call parameters (CallParameters)

Setter Effect
with_amount(u64) Coins forwarded to the call
with_asset_id(AssetId) Asset forwarded
with_gas_forwarded(u64) Gas forwarded to the call (bounded by tx limit)

9.3 Codec limits

Type Fields
EncoderConfig max_depth, max_tokens
DecoderConfig max_depth, max_tokens

9.4 Node config (test helpers)

See §7.2 — NodeConfig, Trigger, DbType, plus ChainConfig/StateConfig from fuel-core-chain-config.

9.5 Retry config

RetryConfig::new(max_attempts, Backoff) where Backoff ∈ { Linear, Exponential, Fixed }(Duration).

9.6 Default constants (selected)

Constant Value Crate
DEFAULT_NUM_WALLETS 10 test-helpers
DEFAULT_NUM_COINS 1 test-helpers
DEFAULT_COIN_AMOUNT 1_000_000_000 test-helpers
DEFAULT_DERIVATION_PATH m/44'/1179993420'/0'/0/0 accounts
DEFAULT_MAX_FEE_ESTIMATION_TOLERANCE 0.50 programs
Coin cache TTL 30 s accounts
Pagination page size 100 accounts

10. Security Analysis

fuels-rs is a client library for a blockchain; its security surface is about key handling, transaction safety, and trust boundaries — not network‑exposed endpoints.

10.1 Key material

  • PrivateKeySigner holds the secret key in process memory. SecretKey (from fuel-crypto) and the keystore's KeySaved are Zeroize/ZeroizeOnDrop, so they scrub on drop — but copies you make are your responsibility.
  • Keystore encrypts keys at rest with a password via eth-keystore. The master password and the encrypted file together are sufficient to recover the key.
  • KMS signers (AWS/Google) keep the key in the HSM/KMS; the SDK never sees the private key. This is the recommended posture for production services.
  • Locked wallets (Wallet<Locked>) carry no signer — use them for read‑only paths to minimise the time keys are resident in memory. The docs explicitly recommend minimising Wallet<Unlocked<S>> usage.

Caution

Deterministic test wallets (predictable keys derived from a counter) and FakeSigner (impersonation when utxo_validation = false) are test‑only mechanisms. Using either against a real network is a critical mistake.

10.2 Transaction safety

  • force_transfer_to_contract can permanently lose funds if the receiving contract doesn't account for them — flagged CAUTION in source.
  • Payability enforcement — call_params returns a Result and refuses to forward a non‑zero amount to a non‑#[payable] method, preventing a class of accidental loss.
  • Coin cache prevents accidental double‑spend of in‑flight UTXOs.
  • Builder immutability — once a transaction is built, it can't be mutated, so the transaction ID can't silently change after signing.
  • Predicate validation — the provider estimates and validates predicates before submitting predicate‑spending transactions.

10.3 Input parsing / untrusted data

The codec enforces max_depth/max_tokens limits to bound resource use when decoding untrusted ABI data. The tx‑debug decoder (ScriptType::detect, ContractCallData::decode) is written defensively: it returns typed errors (not panics) on malformed scripts, truncated data sections, invalid UTF‑8 function selectors, and bad call‑data offsets (see its extensive negative tests).

10.4 Schema/version pinning

The SDK pins a supported fuel-core version (SUPPORTED_FUEL_CORE_VERSION) and asserts its bundled GraphQL SDL matches fuel-core-client's. Running against a mismatched node can produce subtle consensus‑parameter or schema errors; pin SDK and node together.

10.5 Supply chain

The workspace pins exact dependency versions in the root Cargo.toml [workspace.dependencies]. KMS, keystore, and node‑lib dependencies are gated behind optional features, so a default build pulls a smaller surface. Audit the enabled feature set when integrating.


11. Operations

11.1 Building & testing the workspace

# Build all Sway test fixtures first (required for the Rust tests):
forc build --release --path e2e

# Run the whole suite:
cargo test

# All targets + features:
cargo test --all-targets --all-features

# WASM tests:
cd packages/wasm-tests && wasm-pack test --node

Warning

The Rust integration tests reference compiled Sway artifacts under e2e/sway/**/out/release/. If you skip forc build --release --path e2e, tests fail to find *.bin/*-abi.json. After pulling changes, rebuild fixtures.

11.2 CI considerations

  • Install fuelup and a pinned toolchain so forc and fuel-core are available and version‑matched to the SDK.
  • Alternatively enable fuel-core-lib to avoid needing a fuel-core binary (heavier build, no external process).
  • The repo ships a scripts/check-docs binary that verifies every {{#include …:anchor}} in docs/src resolves to a real ANCHOR in the examples/tests, and that every doc file is listed in SUMMARY.md. Run it to catch documentation drift.
  • scripts/fuel-core-version (a clap CLI) and scripts/versions-replacer (an argh CLI) keep the pinned fuel-core version and workspace versions consistent.

11.3 Maintenance binaries

Binary (scripts/) Tooling Purpose
change-log octocrab, dialoguer Generate changelog entries from GitHub
check-docs regex Validate mdbook include anchors & SUMMARY coverage
fuel-core-version clap, toml Read/update the pinned fuel-core version
versions-replacer argh, cargo_metadata Replace workspace version strings

These are publish = false — not part of the released SDK.

11.4 Upgrading the SDK

  1. Bump the fuels version in your Cargo.toml; run cargo update -p fuels.
  2. Align your fuel-core/forc toolchain with the SDK's supported fuel-core (use fuelup).
  3. Rebuild Sway artifacts (forc build --release) since ABI/binary formats can change between forc versions.
  4. Run your test suite; watch for Reason::Validation errors (consensus‑parameter changes) and codec changes.

Note

A ScriptCallData field comment in source flags a planned rename (data_section_offset → data_section_offset/configurable_section_offset) tied to Sway binary‑format changes (sway 0.66.5 vs 0.66.6+). Expect such churn around forc/sway upgrades; pin toolchains in CI.


12. Repository / Module Reference (for contributors)

Crate Key modules Notes
fuels lib.rs (facade + prelude) ~almost no logic; re‑exports
fuels-core codec, traits, types, Configurables, utils::{constants, offsets} Foundation
fuels-code-gen program_bindings::{abigen, custom_types, resolved_type, generated_code}, error, utils ABI→Rust
fuels-macros abigen, derive, setup_program_test, parse_utils proc‑macros
fuels-accounts account, wallet, provider, predicate, signers::{private_key, kms, fake, derivation}, keystore, coin_cache, schema Identity + node
fuels-programs contract::{regular, loader, storage}, calls::{call_handler, contract_call, script_call, receipt_parser}, executable, responses, debug, assembly Programs
fuels-test-helpers service, fuel_bin_service, accounts, node_types, wallets_config, utils Test infra

Contribution flow

  1. Ensure an issue tracks the change; discuss large changes first.
  2. Branch from master; write code + tests.
  3. Run forc build --release --path e2e then cargo test.
  4. Add a breaking label to the PR if it contains breaking changes.
  5. Link the PR to its issue (close #123 / ref #456); CI (GitHub Actions) runs on authorized PRs.

Useful entry points for new contributors: Good First Issues and Help Wanted labels on the repo.


13. Improvements & Tech Debt (from the codebase & issue tracker)

These reflect open issues and in‑source TODOs at the documented commit.

Area Item Source
Errors Add context to errors throughout the SDK #1597
abigen Renaming Sway imports breaks abigen!() #1703
Errors Convert a transaction error into contract errors when present #1680
Bindings Defined Vec alias in Sway breaks the SDK harness #1603
Provider Support multiple RPCs in the provider #1701
Tx Support unknown policies during tx deserialization #1700
Node Set a static gas price via NodeConfig #1581
Refactor TransactionBuilder refactor #1661
Refactor Coin cache refactor #1196
API Make max estimation fee tolerance configurable in call handlers #1591
Build Remove include_bytes hack #1062

In‑source signals: e2e/Cargo.toml notes a planned removal (#1375) where ScriptTransaction/CreateTransaction use fuel_tx::Input without re‑exporting/converting it to a fuels‑owned type. The executable.rs loader has a #[deprecated] data_offset_in_code in favour of configurables_offset_in_code.


14. Quick Reference

Crate map (by responsibility)

fuels                facade + prelude
├─ fuels-programs     deploy/call contracts, scripts, predicates, loaders
├─ fuels-accounts     Provider, Wallet, Predicate, signers, keystore, coin-cache
├─ fuels-core         types, codec (ABI), traits, tx builders, Configurables, errors
├─ fuels-code-gen     ABI → Rust (compile-time)        ┐ codegen
├─ fuels-macros       abigen!/derives/setup_program_test ┘
└─ fuels-test-helpers FuelService, wallet/coin setup

Transaction lifecycle

build inputs/outputs (account.get_asset_inputs/outputs_for_amount)
   → TransactionBuilder (Script/Create/Blob)  [add_signer, with_tx_policies]
   → account.adjust_for_fee(&mut tb, used_base)
   → tb.build(&provider)            (resolves witnesses, predicate offsets; immutable)
   → provider.prepare_transaction_for_sending (precompute, estimate/validate predicates)
   → provider.send_transaction[_and_await_commit]
   → TxStatus / receipts → CallHandler.get_response → CallResponse<D>

Error variants

Error::{ IO | Codec | Transaction(Reason::{Failure, Validation, …}) | Provider | Other }

Pinned versions

Dependency Version
fuels (this SDK) 0.77.0
fuel-core* 0.48.0
fuel-vm / fuel-tx / fuel-types 0.66.2
fuel-abi-types 0.15.3
Rust edition / MSRV 2024 / 1.93.0

For the always‑current API, see docs.rs/fuels and the fuels‑rs book.