stylus_sdk::prelude

Attribute Macro entrypoint

Source
#[entrypoint]
Expand description

Defines the entrypoint, which is where Stylus execution begins. Without it the contract will fail to pass cargo stylus check. Most commonly this macro is used to annotate the top level storage struct.

sol_storage! {
    #[entrypoint]
    pub struct Contract {
        // ...
    }

    // only one entrypoint is allowed
    pub struct SubStruct {
        // ...
    }
}

The above will make the public methods of Contract the first to consider during invocation. See #[public] for more information on method selection.

§Bytes-in, bytes-out programming

A less common usage of #[entrypoint] is for low-level, bytes-in bytes-out programming. When applied to a free-standing function, a different way of writing smart contracts becomes possible, wherein the Stylus SDK’s macros and storage types are entirely optional.

#[entrypoint]
fn entrypoint(calldata: Vec<u8>) -> ArbResult {
    // bytes-in, bytes-out programming
}

§Reentrancy

If a contract calls another that then calls the first, it is said to be reentrant. By default, all Stylus programs revert when this happens. However, you can opt out of this behavior by recompiling with the reentrant flag.

stylus_sdk = { version = "0.3.0", features = ["reentrant"] }

This is dangerous, and should be done only after careful review – ideally by 3rd-party auditors. Numerous exploits and hacks have in Web3 are attributable to developers misusing or not fully understanding reentrant patterns.

If enabled, the Stylus SDK will flush the storage cache in between reentrant calls, persisting values to state that might be used by inner calls. Note that preventing storage invalidation is only part of the battle in the fight against exploits. You can tell if a call is reentrant via msg::reentrant, and condition your business logic accordingly.

§TopLevelStorage

The #[entrypoint] macro will automatically implement the TopLevelStorage trait for the annotated struct. The single type implementing TopLevelStorage is special in that mutable access to it represents mutable access to the entire program’s state. This has implications for calls via sol_interface.