Stylus doesn’t use classical inheritance. Instead, you compose behavior with Rust traits and expose them through the router using #[implements(...)]. This yields Solidity-compatible ABIs with strong type safety.
Think of traits like interfaces, and #[implements(...)] as wiring those interfaces into your contract’s externally callable surface (ABI). There’s no virtual/override; you model reuse via composition and default methods.
#[public] inherent impl with #[implements(...)] to export the traits.#[public] impl Trait for Contract.Rust method names are snake_case; Solidity selectors are camelCase and may overlap across traits. When two methods would collide in the ABI, add:
1#[selector(name = "ActualSolidityName")]1#[selector(name = "ActualSolidityName")]In the example below, ERC-20’s name() remains standard, while an extra branding method is exported as displayName() to avoid colliding with name().
When a call hits your contract, the router checks:
#[public] impl Contract { ... } block)#[implements(...)], in orderThis single example shows:
displayName) to avoid ABI collisions with ERC-20’s name()#[public] inherent block wired with #[implements(...)] (no router conflicts)src/lib.rs1Loading...1Loading...1Loading...1Loading...1Loading...1Loading...#[implements(...)].#[public] inherent block per entrypoint to avoid router conflicts.#[selector(name = "...")] when another trait exposes a similar concept (e.g., displayName vs ERC-20 name).