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

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`):

```rust
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:

```rust
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](https://docs.fuel.network/docs/specs/abi/argument-encoding/):

| Item | Role |
|------|------|
| `ABIEncoder` | Encode `Token`s → 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

```rust
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:

```rust
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):

```rust
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 `SecretKey`s 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:

```rust
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

```rust
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

```rust
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](#72-node-chain-and-state-config) — `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

```shell
# 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](https://github.com/FuelLabs/fuels-rs/issues/1597) |
| abigen | Renaming Sway imports breaks `abigen!()` | [#1703](https://github.com/FuelLabs/fuels-rs/issues/1703) |
| Errors | Convert a transaction error into contract errors when present | [#1680](https://github.com/FuelLabs/fuels-rs/issues/1680) |
| Bindings | Defined `Vec` alias in Sway breaks the SDK harness | [#1603](https://github.com/FuelLabs/fuels-rs/issues/1603) |
| Provider | Support multiple RPCs in the provider | [#1701](https://github.com/FuelLabs/fuels-rs/issues/1701) |
| Tx | Support unknown policies during tx deserialization | [#1700](https://github.com/FuelLabs/fuels-rs/issues/1700) |
| Node | Set a static gas price via `NodeConfig` | [#1581](https://github.com/FuelLabs/fuels-rs/issues/1581) |
| Refactor | `TransactionBuilder` refactor | [#1661](https://github.com/FuelLabs/fuels-rs/issues/1661) |
| Refactor | Coin cache refactor | [#1196](https://github.com/FuelLabs/fuels-rs/issues/1196) |
| API | Make max estimation fee tolerance configurable in call handlers | [#1591](https://github.com/FuelLabs/fuels-rs/issues/1591) |
| Build | Remove `include_bytes` hack | [#1062](https://github.com/FuelLabs/fuels-rs/issues/1062) |

In‑source signals: `e2e/Cargo.toml` notes a planned removal ([#1375](https://github.com/FuelLabs/fuels-rs/issues/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](https://docs.rs/fuels/latest/fuels/) and the [fuels‑rs book](https://fuellabs.github.io/fuels-rs/latest/).

---

_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. Unofficial; not affiliated with or reviewed by the project._
