Arbitrum Stylus: Effortless, Must-Have Rust/C Contracts.
Article Structure

Arbitrum Stylus brings WebAssembly to Ethereum-scale blockchains, letting developers write smart contracts in Rust, C, or C++ alongside Solidity. It runs on Arbitrum chains as a second execution environment that interoperates with the EVM at the same addresses and in the same block space. In short: you can keep your Solidity where it makes sense and move heavy computation to Rust or C where it’s cheaper and safer.
What Stylus actually is
Stylus extends Arbitrum Nitro with a WASM runtime, metering, and storage APIs. Contracts compiled to WASM can read and write state, emit logs, and call EVM contracts. The runtime enforces determinism, so no syscalls, no floating point, no threads—just pure, predictable execution.
Under the hood, you compile Rust or C to a WASM module linked with the Stylus SDK. The SDK exposes storage types, ABI handling, and cross-environment calls. Once deployed, Stylus and Solidity contracts can call each other like normal, using addresses and ABI encoding you already know.
Why write contracts in Rust or C
Rust offers memory safety and a rich ecosystem. C offers raw control and portability. In Stylus, both benefit from WASM’s speed for CPU-bound tasks. That speed translates to lower gas for heavy workloads.
- Cheaper compute: hashing, signature checks, numerical loops, and parsing data become practical on-chain.
- Language ergonomics: libraries like serde, hashers, curve math, and fixed-point crates are battle-tested.
- Interoperability: call existing Solidity contracts without bridges or wrappers.
- Safety: Rust’s ownership rules eliminate entire bug classes; C stays viable for teams with embedded expertise.
Picture an AMM that prices exotic curves. In Solidity, a 500-iteration Newton solver is too costly. In Stylus, the same math can run at a fraction of the gas while keeping the pool’s storage in the same account.
Core mental model
Think of Stylus as two things at once: a faster compute engine and a first-class citizen of the EVM world. Storage is still key-value on the same chain. Gas is still charged. Transactions can touch Stylus and Solidity contracts in one go. Determinism stays strict, so you can reason about state transitions precisely.
Quick start: Rust flow
You don’t need to rewrite your stack. A minimal setup gets you compiling and deploying fast.
- Install Rust and targets: rustup with the wasm32-unknown-unknown target.
- Install the Stylus toolchain: cargo install cargo-stylus and add the stylus-sdk crate.
- Create a project: cargo stylus new counter and inspect the generated contract.
- Build and test: cargo stylus check, then cargo stylus build –release for a WASM artifact.
- Deploy: cargo stylus deploy –private-key … –rpc https://arb1/… and note the address.
From here, you can call the contract via standard Ethereum tooling. The ABI is exposed through the SDK, so your front end can use the same libraries it uses for Solidity contracts today.
A tiny Rust example
Here’s a reduced example showing storage, events, and an external call. It’s intentionally minimal to reveal the moving parts.
/Cargo.toml: stylus-sdk = "..."
use stylus_sdk::{contract, evm, storage::Value, event};
#[event]
struct Bumped { new_value: u64 }
#[contract]
pub struct Counter {
value: Value<u64>,
}
impl Counter {
pub fn get(&self) -> u64 { self.value }
pub fn bump(&mut self, by: u64) {
let v = self.get() + by;
self.value = v;
Bumped { new_value: v }.emit();
}
pub fn notify(&self, addr: [u8; 20]) {
/Call a Solidity hook: hook(uint256)
let data = alloy_sol_types::sol!("function hook(uint256)")
::hookCall { }.abi_encode(&[self.get().into()]);
let _ = evm::call::call(addr, &data, 0u128);
}
}
This contract keeps a single counter in storage, emits an event on bump, and can call a Solidity hook. The types and ABI encoding come from Rust crates, while evm::call gives you outbound calls into the EVM world.
Writing Stylus in C
For C, you compile to wasm32 and link the Stylus C SDK headers. Storage and ABI helpers are exposed through functions and macros instead of Rust traits.
A simple pattern resembles:
/stylus.h from the SDK provides storage and abi #include "stylus.h" STYLUS_STORAGE(uint64_t, value);void bump(uint64_t by) { uint64_t v = storage_get(&value) + by; storage_set(&value, v); emit_event_u64(v); }
While you get maximal control, you also take responsibility for memory hygiene. The runtime prevents undefined behavior from escaping the module, but logic errors are still on you.
Stylus vs Solidity at a glance
This table summarizes where each approach shines. It’s a guide, not a rulebook; many apps will mix both.
| Aspect | Stylus (Rust/C) | Solidity (EVM) |
|---|---|---|
| Language safety | Rust memory safety; C unsafe but explicit | Managed, but logic-level pitfalls persist |
| Compute cost | Lower for CPU-heavy workloads via WASM | Higher for tight loops and heavy math |
| Ecosystem maturity | New SDKs; vast Rust/C libraries | Deep tooling, auditors, patterns |
| Interoperability | Direct calls to/from EVM in the same tx | Native within EVM; can call Stylus |
| Best use cases | Crypto primitives, data parsing, ML-ish math | Business logic, DeFi orchestration, standards |
Most teams keep governance, token logic, and standard interfaces in Solidity while offloading the expensive math or verification code to a Stylus module living at a sibling address.
Gas, storage, and determinism
Stylus still charges for work, just with a different cost curve. CPU-bound code often gets a sizable discount. Storage remains the dominant cost driver: reading and writing slots on Stylus is priced consistently with EVM expectations.
Determinism rules apply. No floating point, no random, no time-based syscalls. Use integer math and pass in any needed randomness or timestamps via transaction inputs or precompiles. If you need BN254 or BLS curves, Rust crates pair well with the Stylus environment and can outperform their Solidity counterparts by wide margins.
Interop patterns that work
Mixing Stylus and Solidity pays off when you isolate concerns. A clean interface between modules keeps things testable and auditable.
- Compute oracle: a Solidity contract aggregates feeds; a Stylus module normalizes and filters data.
- Verifier offload: Solidity handles proofs’ lifecycle; Stylus verifies the proof bytes and returns a boolean.
- Math coprocessor: AMM core stays Solidity; invariant checks and curve solving live in Rust.
In each case, keep the ABI tight. Define structs and events once, and generate bindings for both worlds so data layouts stay consistent.
Testing and tooling
You can test Rust logic natively for speed and then run integration tests against an Arbitrum node. For ABI-level checks, simulate cross-calls with fixtures that encode/decode payloads exactly as your front end would.
- Unit test pure Rust/C functions locally with standard frameworks.
- Run cargo stylus check to validate WASM constraints early.
- Spin an Arbitrum dev node; deploy both Stylus and Solidity contracts.
- Exercise end-to-end flows via Foundry/Hardhat using the deployed addresses.
This layered approach catches logic bugs before you pay chain costs and lets you iterate on ABI boundaries confidently.
Security notes worth taping to your screen
Rust’s safety nets are powerful, but they don’t protect against economic or protocol flaws. Treat Stylus code with the same rigor you give Solidity.
- Reentrancy: it still exists across environments; guard state transitions.
- Panic handling: avoid aborts; map failures to explicit error codes.
- Serialization: validate lengths and formats on all external inputs.
- Resources: bound loops and memory; WASM metering charges for both.
A micro-scenario: a verifier that decodes calldata into a vector must cap length or you risk paying to allocate enormous buffers. Parse size headers first, then pre-allocate with hard limits.
When to choose Stylus
Choose Stylus when your contract spends most of its gas on raw computation or parsing and you’re comfortable with Rust or C. Keep pure coordination logic and widely audited patterns in Solidity. If you’re migrating, start by moving the hottest function—the one torching gas in your profiler—then measure the savings before expanding scope.
Final pointers
Keep your repository split by environment with shared interfaces. Measure before and after with real calldata. Add integration tests that cross the EVM–WASM boundary, and don’t skip audits just because Rust compiled your code. When done well, Stylus turns previously impractical on-chain ideas—like on-the-fly signature aggregation or high-precision math—into everyday building blocks.


