RADIX WikiRADIX Wiki

Introduction

Once your development environment is set up, the next step is understanding the Scrypto development workflow: creating packages, writing blueprints, building to WebAssembly, and testing locally. Radix provides two complementary testing approaches – the resim simulator for interactive exploration and the scrypto-test framework for automated testing.

Package Structure

A Scrypto package is a standard Rust crate with Scrypto-specific dependencies. scrypto new-package my-dapp writes seven files, not the three a bare cargo new would give you:

my-dapp/
β”œβ”€β”€ Cargo.toml            # scrypto dependency, scrypto-test dev-dependency, release profile
β”œβ”€β”€ Cargo.lock            # shipped, so --locked builds reproduce
β”œβ”€β”€ rust-toolchain.toml   # the Rust channel this package compiles with
β”œβ”€β”€ .gitignore
β”œβ”€β”€ src/
β”‚   └── lib.rs            # Blueprint definitions
└── tests/
    └── lib.rs            # Test suite β€” both harnesses, pre-wired

The src/lib.rs file contains one or more blueprints – reusable templates that define the structure and logic of on-ledger components. Each blueprint is annotated with the #[blueprint] macro and contains a struct (state) and an impl block (functions and methods). The generated tests/lib.rs is not a placeholder: it ships one test written against each of the two harnesses described below, so the choice is demonstrated before you write a line.

The toolchain file decides which Rust you get

rust-toolchain.toml is written from a template bundled inside the CLI binary, and rustup honours it over your default toolchain. Under radix-clis 1.3.1 it pins:

[toolchain]
channel = "1.92.0"
components = ["rustfmt", "rust-src"]
targets = ["wasm32-unknown-unknown"]
profile = "default"

rust-src is not decoration – scrypto build rebuilds the Rust standard library for the WASM target (see below), which needs the standard library's source on disk. Because the pin travels with the CLI rather than with your machine, installing an older radix-clis quietly hands your package an older compiler: see Version Pins on the install page.

What the generated Cargo.toml sets

The template manifest tunes the release profile for on-ledger size and for safety: opt-level = 'z', link-time optimisation on, a single codegen unit, panic = 'abort', symbols stripped – and overflow-checks = true, so arithmetic overflow panics in release builds instead of wrapping silently. crate-type = ["cdylib", "lib"] produces both the WASM artifact and a linkable library, which is what lets the test harness call your blueprint directly. The file closes with an empty [workspace] stanza that hides the package from any ancestor Cargo workspace; delete it if you mean the package to be a workspace member.

Building

scrypto build is not a thin wrapper over cargo build. The compiler compiles the package twice:

  1. Once with the schema, producing <name>_with_schema.wasm, from which the .rpd (Radix Package Definition) is extracted.
  2. Once without it – the scrypto/no-schema feature – producing the binary that actually gets published, then optimised with wasm-opt. That pass runs by default and is disabled with --disable-wasm-opt.

Both passes are release builds against wasm32-unknown-unknown with -Zbuild-std=std,panic_abort, and the artifacts land in target/wasm32-unknown-unknown/release/. Between the passes the compiler consults a local cache keyed on the hash of the with-schema WASM, so an unchanged package skips the second compile.

The .rpd is the package's ABI – blueprint names, functions, methods and their type signatures – which the Radix Engine uses to validate calls at runtime.

For a build that reproduces, pass --locked or set SCRYPTO_CARGO_LOCKED so the shipped Cargo.lock is used as-is. scrypto test and scrypto coverage accept the same flag and read the same environment variable, which makes it easy to set once across a CI job.

Interactive Testing with resim

The Radix Engine Simulator (resim) is a local ledger emulator that lets you publish packages, instantiate components, and call methods without connecting to any network. It is invaluable for rapid iteration.

Core Commands

# Reset simulator state
resim reset
 
# Create a new account (returns address, public key, private key, owner badge)
resim new-account
 
# Set the active account
resim set-default-account <account_address> <private_key> <owner_badge_address>
 
# Publish a package (returns package address)
resim publish .
 
# Call a blueprint function (e.g. instantiate a component)
resim call-function <package_address> <BlueprintName> <function_name> [args...]
 
# Call a method on an instantiated component
resim call-method <component_address> <method_name> [args...]
 
# Inspect an entity's state
resim show <address>

Typical Workflow

  1. resim reset – start with a clean ledger
  2. resim new-account – create a test account
  3. resim publish . – deploy your package
  4. resim call-function – instantiate a component from your blueprint
  5. resim call-method – interact with the component
  6. resim show – inspect state, balances, and vaults

Automated Testing with scrypto-test

While resim is great for exploration, production packages need automated tests. Radix provides two testing frameworks:

Unit Testing: scrypto-test

The scrypto-test framework uses an invocation-based approach – you call blueprint functions and methods directly in Rust, receiving actual Bucket and Proof objects that you can assert against. At its core is the TestEnvironment struct, which encapsulates a self-contained Radix Engine instance.

use scrypto_test::prelude::*;
 
#[test]
fn test_instantiation() -> Result<(), RuntimeError> {
    let mut env = TestEnvironment::new();
    let package = PackageFactory::compile_and_publish(
        this_package!(),
        &mut env,
        CompileProfile::Fast,
    )?;
    // Call functions, assert on the returned buckets and proofs
    Ok(())
}

Key utilities include BucketFactory and ProofFactory for creating test resources, with strategies like CreationStrategy::DisableAuthAndMint for bypassing auth in test contexts.

Integration Testing: LedgerSimulator

The LedgerSimulator is an in-memory ledger where you interact as an external user submitting transactions, rather than calling methods directly. It applies the same costing limits and auth checks as the real network, which makes it the right harness for end-to-end tests. Build one with LedgerSimulatorBuilder, publish your package, then execute manifests against it.

use scrypto_test::prelude::*;
 
#[test]
fn test_end_to_end() {
    let mut ledger = LedgerSimulatorBuilder::new().build();
    let package_address = ledger.compile_and_publish(this_package!());
    let (public_key, _private_key, account) = ledger.new_allocated_account();
 
    let manifest = ManifestBuilder::new()
        .lock_fee_from_faucet()
        .call_function(package_address, "Hello", "instantiate_hello", manifest_args!())
        .build();
 
    let receipt = ledger.execute_manifest(
        manifest,
        vec![NonFungibleGlobalId::from_public_key(&public_key)],
    );
    receipt.expect_commit_success();
}

Earlier releases of the framework called this type TestRunner. It was renamed to LedgerSimulator, so test code written against older tutorials will not compile against current scrypto-test.

Run all tests with:

scrypto test

This wraps cargo test with the correct Scrypto feature flags and environment.

Code Coverage

A third command completes the set, and it is easy to miss because no tutorial reaches for it: scrypto coverage runs the package's tests and generates an LLVM source-based coverage report over the blueprint code that ran inside them.

scrypto coverage

It asks more of the machine than scrypto build does, and its own implementation states the four assumptions up front: the coverage WASM is built with the nightly toolchain, you do not get to choose which nightly – it uses whichever is on the system – the target is always wasm32-unknown-unknown, the profile is always release, and clang, llvm-cov and llvm-profdata must already be installed and on your PATH. A machine set up only to run scrypto build satisfies none of the last three, which is the usual reason the command fails on first use.

Next Steps

HydrateLast updated 4d agov1.6.010 revisionsVerified Aug 21, 2026