Skip to content

Latest commit

 

History

History
91 lines (66 loc) · 3.16 KB

File metadata and controls

91 lines (66 loc) · 3.16 KB

S008 — Event Inconsistency

  • Category: events
  • Severity: Low
  • Rule name: event_inconsistency

What it detects

S008 scans env.events().publish(topics, data) calls and checks:

  1. Topic-count consistency — when the same event name is published with a different number of topics in different places, it reports the mismatch (previous count vs. current count).
  2. Sub-optimal gas patterns — string or String topics that could use symbol_short! for short identifiers are flagged as a gas-optimization suggestion.

Why it matters

Wallets, indexers, and monitoring tools subscribe to events by topic shape. If the same logical event is sometimes published with two topics and sometimes with three, off-chain consumers can't reliably parse it — so wallets and indexers go blind to part of your contract's activity. Inconsistent or string-heavy topics also waste gas. The severity is Low because there is no on-chain fund risk, but the operational impact on integrations is real.

Vulnerable example

#![no_std]
use soroban_sdk::{contract, contractimpl, symbol_short, Address, Env};

#[contract]
pub struct Token;

#[contractimpl]
impl Token {
    pub fn mint(env: Env, to: Address, amount: i128) {
        // Two topics for the "transfer" event here ...
        env.events()
            .publish((symbol_short!("transfer"), to), amount);
    }

    pub fn transfer(env: Env, from: Address, to: Address, amount: i128) {
        from.require_auth();
        // S008: three topics for the same "transfer" event name — inconsistent.
        env.events()
            .publish((symbol_short!("transfer"), from, to), amount);
    }
}

Safe example

#![no_std]
use soroban_sdk::{contract, contractimpl, symbol_short, Address, Env};

#[contract]
pub struct Token;

#[contractimpl]
impl Token {
    pub fn mint(env: Env, to: Address, amount: i128) {
        // Consistent (event, from, to) topic shape across all emitters.
        let zero = Address::from_str(&env, "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF5");
        env.events()
            .publish((symbol_short!("transfer"), zero, to), amount);
    }

    pub fn transfer(env: Env, from: Address, to: Address, amount: i128) {
        from.require_auth();
        env.events()
            .publish((symbol_short!("transfer"), from, to), amount);
    }
}

CVSS-style risk rating

  • Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N
  • Base score: 5.3
  • Rating: Low

There is no on-chain integrity or availability impact; the consequence is degraded observability for off-chain consumers, mapped here as a minor confidentiality/visibility concern. The catalog severity is Low.

How to fix

  1. Standardize each event's topic layout and use the same number and order of topics everywhere it is emitted.
  2. Define a single helper that publishes each event so the shape can't drift.
  3. Prefer symbol_short! for short, fixed topic identifiers to save gas.

Related rules

Related rules: S010, S007

References