linera-io/linera-protocol · error

event topic does not match DepositInitiated signature

Error message

event topic does not match DepositInitiated signature

What it means

parse_deposit_event requires topics[0] to equal keccak256 of the DepositInitiated(uint256,bytes32,bytes32,bytes32,address,address,uint256,uint256) signature (deposit_event_signature()). Any log whose first topic is a different event signature — including similarly named events from the real contract — is rejected. This prevents confusing other bridge events (withdrawals, finalizations) with deposits.

Source

Thrown at linera-bridge/src/proof/mod.rs:431

    }

    Ok(logs)
}

/// Parses a `DepositInitiated` event from a receipt log.
///
/// Verifies that `topic[0]` matches the event signature, that the log was emitted by
/// the `expected_emitter` (bridge contract address), and ABI-decodes the data fields.
/// The `depositor` field is indexed (stored in `topics[1]`); all other parameters are
/// non-indexed and encoded in the log data.
pub fn parse_deposit_event(log: &ReceiptLog, expected_emitter: Address) -> Result<DepositEvent> {
    ensure!(
        log.address == expected_emitter,
        "log emitter {:?} does not match expected bridge contract {:?}",
        log.address,
        expected_emitter
    );
    ensure!(
        log.topics.first() == Some(&deposit_event_signature()),
        "event topic does not match DepositInitiated signature"
    );
    ensure!(
        log.topics.len() == 2,
        "expected exactly 2 topics (signature + indexed depositor), got {}",
        log.topics.len()
    );
    ensure!(
        log.data.len() == 224,
        "expected 224 bytes of event data (7 x 32), got {}",
        log.data.len()
    );

    // Indexed `depositor` is in topics[1], left-padded to 32 bytes.
    let depositor_topic = log.topics[1];
    ensure!(
        depositor_topic.as_slice()[..12] == [0u8; 12],

View on GitHub (pinned to 6c226ddcb3)

Solutions

  1. Filter at query time by topic0: eth_getLogs(topics=[deposit_event_signature()]) so only DepositInitiated logs arrive
  2. After a contract upgrade, regenerate the signature from the new ABI and redeploy/align the indexer
  3. Verify with cast sig-event 'DepositInitiated(...)' that your expected signature matches the on-chain topic

Example fix

// before
let sig = keccak256("Deposit(uint256,address,uint256)"); // old/short ABI

// after
// keccak256("DepositInitiated(uint256,bytes32,bytes32,bytes32,address,address,uint256,uint256)")
let sig = deposit_event_signature();
let logs = rpc.get_logs(address = BRIDGE, topics = [sig]);
Defensive patterns

Strategy: validation

Validate before calling

// Only offer logs whose topic0 is the DepositInitiated signature
let sig = deposit_event_signature();
if log.topics.first() != Some(&sig) {
    return Ok(None); // different event from the same contract
}
let event = parse_deposit_event(log, bridge_address)?;

Try / catch

match parse_deposit_event(&log, bridge_address) {
    Ok(ev) => Some(ev),
    Err(e) if e.to_string().contains("topic does not match DepositInitiated") => {
        tracing::debug!("skipping non-deposit event from bridge contract"); None
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Feeding every log of the bridge contract into parse_deposit_event: a WithdrawalInitiated or DepositFinalized event also has the bridge as emitter but a different topic0; signature mismatch after the ABI changed (field added/removed) between contract versions.

Common situations: Scanner not filtering by topic0 at the RPC level; contract upgrade altering the event signature while the indexer still hashes the old ABI; fixtures copied from a different event of the same contract.

Related errors


AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22). Data as JSON: /api/errors/73c5c63b8533abb4. Report an issue: GitHub.