stylus_tools/
wasm.rs

1// Copyright 2025, Offchain Labs, Inc.
2// For licensing, see https://github.com/OffchainLabs/stylus-sdk-rs/blob/main/licenses/COPYRIGHT.md
3
4//! Tools for processing Wasm bytecode for Stylus contracts.
5
6use std::{fs, io, path::Path};
7
8use alloy::primitives::B256;
9use wasmparser::BinaryReaderError;
10
11use crate::utils::wasm;
12
13/// Maximum brotli compression level used for Stylus contracts.
14pub const BROTLI_COMPRESSION_LEVEL: u32 = 11;
15
16/// EOF prefix used in Stylus compressed WASMs on-chain
17pub const EOF_PREFIX_NO_DICT: &str = "EFF00000";
18
19/// Name of the custom wasm section that is added to contracts deployed with cargo stylus
20/// to include a hash of the Rust project's source files for reproducible verification of builds.
21pub const PROJECT_HASH_SECTION_NAME: &str = "project_hash";
22
23// TODO: process_wasm() from memory
24pub fn process_wasm_file(
25    filename: impl AsRef<Path>,
26    project_hash: [u8; 32],
27) -> Result<ProcessedWasm, ProcessWasmFileError> {
28    let wasm = fs::read(filename).map_err(ProcessWasmFileError::Read)?;
29    let wasm = wasm::remove_dangling_references(wasm)?;
30    let wasm = wasm::strip_user_metadata(wasm).map_err(ProcessWasmFileError::StripUserMetadata)?;
31    let wasm = wasm::add_custom_section(wasm, PROJECT_HASH_SECTION_NAME, project_hash)
32        .map_err(ProcessWasmFileError::AddProjectHash)?;
33    let wasm = wasmer::wat2wasm(&wasm)
34        .map_err(ProcessWasmFileError::Wat2Wasm)?
35        .to_vec();
36
37    let code = wasm::brotli_compress(wasm.as_slice(), BROTLI_COMPRESSION_LEVEL)
38        .map_err(ProcessWasmFileError::BrotliCompress)?;
39    let code = wasm::add_prefix(code, EOF_PREFIX_NO_DICT);
40
41    Ok(ProcessedWasm { wasm, code })
42}
43
44#[derive(Debug)]
45pub struct ProcessedWasm {
46    pub wasm: Vec<u8>,
47    pub code: Vec<u8>,
48}
49
50impl ProcessedWasm {
51    pub fn codehash(&self) -> B256 {
52        alloy::primitives::keccak256(&self.code)
53    }
54}
55
56#[derive(Debug, thiserror::Error)]
57pub enum ProcessWasmFileError {
58    #[error("error reading wasm file: {0}")]
59    Read(io::Error),
60    #[error("error removing dangling references: {0}")]
61    RemoveDanglingReferences(#[from] wasm::RemoveDanglingReferencesError),
62    #[error("error adding project hash to wasm file as a custom section: {0}")]
63    AddProjectHash(BinaryReaderError),
64    #[error("error stripping user metadata: {0}")]
65    StripUserMetadata(BinaryReaderError),
66    #[error("error converting Wat to Wasm: {0}")]
67    Wat2Wasm(wat::Error),
68    #[error("failed to compress Wasm bytes")]
69    BrotliCompress(io::Error),
70}