Skip to main content
ouroborai deploys four Rust smart contracts to Arbitrum using Stylus — Arbitrum’s execution environment that compiles Rust (and other languages) to WASM and runs it natively alongside the EVM. The result is 10-100x gas savings over equivalent Solidity for computation-heavy workloads like multi-DEX route comparison and cross-protocol health scanning.

Why Stylus

Stylus contracts execute as WASM inside the Arbitrum Nitro VM. This matters for an AI agent platform because:
  • Gas efficiency — iterating over DEX quotes or scanning lending positions across protocols involves tight loops and branching logic that WASM handles far more cheaply than the EVM.
  • Rust safetyno_std environment with no heap allocator footguns, plus the full Rust type system for bitmask flags, bounds checking, and access control.
  • Interop — Stylus contracts live at regular Ethereum addresses and are callable from Solidity, viem, or any EVM-compatible client.

Contract Suite

Agent Registry

On-chain registry for agent instances with a capabilities bitmask, reputation scoring, and governance controls.

Route Optimizer

Dynamic DEX registry with Uniswap V3 and AMM V2 dispatch, fee-aware quote comparison, and multi-hop routing.

Liquidation Monitor

Multi-protocol health scanner for lending and perp positions with dynamic protocol registries and tracked account management.

TimeBoost Vault

Bid funding and resale payments for Arbitrum express lane access, integrated with the off-chain TimeBoost bidder.

Stylus SDK 0.10.0

All contracts target stylus-sdk 0.10.0. Key patterns used throughout:
Storage uses sol_storage! with Solidity-style types:
sol_storage! {
    #[entrypoint]
    pub struct MyContract {
        address owner;
        uint256 counter;
        mapping(uint256 => address) registry;
        mapping(uint256 => bool) active;
    }
}
Use address, uint256, bool, and mapping(K => V) — not StorageAddress or StorageMap.
Events are defined with sol! and emitted via self.vm().log():
sol! {
    event AgentRegistered(address indexed owner, uint256 indexed id);
}

self.vm().log(AgentRegistered { owner: caller, id });
self.vm().msg_sender() returns the caller address. All owner-gated methods follow a common guard pattern:
fn only_owner(&self) -> Result<(), Vec<u8>> {
    if self.vm().msg_sender() != self.owner.get() {
        return Err(b"not owner".to_vec());
    }
    Ok(())
}
Methods that accept &mut references to non-ABI types must live in a separate impl block (not marked #[public]). The Stylus ABI generator requires all public methods to use ABI-compatible parameter types.

no_std Environment

Stylus contracts compile with #![no_std]. This means:
  • No standard library collections — use alloc::vec::Vec (requires extern crate alloc;).
  • No String — error messages use Vec<u8> (e.g. b"not owner".to_vec()).
  • No filesystem, networking, or threads.
The sol_storage! macro internally needs the vec! macro. Always include use alloc::vec; and use alloc::vec::Vec; at the top of your contract.

Off-Chain Integration

The agent’s TypeScript adapters interact with these contracts via viem v2 readContract / writeContract calls. The typical flow:
  1. Agent runner identifies an intent (e.g. “find the best swap route”).
  2. The corresponding adapter calls the Stylus contract on-chain to compute the result (e.g. RouteOptimizer.find_best_route).
  3. The adapter interprets the result and either returns data to the user or chains into a follow-up transaction.
This keeps heavy computation on-chain (benefiting from Stylus gas savings) while the agent orchestration layer stays off-chain for flexibility.

Running Tests

All four contracts share a single Cargo workspace. Run the full suite with:
cargo test --features stylus-test --manifest-path contracts/Cargo.toml
Tests use stylus_test::TestVM for mocking sender addresses, call data, and static call responses. See each contract page for test coverage details.