Skip to main content

entrypoint

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.

extern crate alloc;
#[entrypoint]
fn entrypoint(
    calldata: Vec<u8>,
    _: alloc::boxed::Box<dyn stylus_sdk::stylus_core::Host>,
) -> ArbResult {
    // bytes-in, bytes-out programming
}

§Reentrancy

If a contract calls another that then calls the first, it is said to be reentrant. Numerous exploits and hacks in Web3 are attributable to developers misusing or not fully understanding reentrant patterns. Always follow the checks-effects-interactions pattern.

§Storage cache flushing

The SDK’s primary reentrancy safety mechanism is automatic storage cache management. The high-level call functions in stylus_sdk::call (call, delegate_call, and static_call) flush the storage cache before every external call, ensuring that pending writes are persisted to storage before control is handed to another contract:

  • call and delegate_call flush and clear (persist dirty values, then drop the in-memory cache).
  • static_call flushes without clearing (since static calls cannot modify storage, the cache remains valid).

This happens unconditionally for all contracts. When using RawCall directly, the cache is not flushed automatically – if you have pending storage writes that the callee might read, call .flush_storage_cache() to persist dirty values without dropping the cache, or .clear_storage_cache() to persist and drop the cache (matching what call and delegate_call do).

§The reentrant feature flag (deprecated)

The reentrant feature flag is deprecated and will be removed in a future release. Previously, contracts without this flag would automatically revert on reentrant calls via a msg_reentrant() check at the entrypoint. This guard is redundant — reentrancy safety is already provided by the cache flushing described above — and it indiscriminately blocks all reentrant calls, preventing use cases that require them.

§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.