linera-io/linera-protocol · error

invalid ABI encoding: address padding bytes (128..140) must

Error message

invalid ABI encoding: address padding bytes (128..140) must be zero

What it means

After the 224-byte length check, parse_deposit_event treats data word 4 (bytes 128..160) as the `token` address, which ABI-encodes as a 32-byte word left-padded with 12 zero bytes. The ensure at linera-bridge/src/proof/mod.rs:457 fails when bytes 128..140 are non-zero, meaning that word is not a left-padded address — typically because the field is actually a bytes32 in the emitting contract, or the word offsets have shifted due to an ABI change.

Source

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

    );
    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],
        "invalid ABI encoding: depositor topic padding bytes (0..12) must be zero"
    );
    let depositor = Address::from_slice(&depositor_topic.as_slice()[12..32]);

    let d = &log.data;

    // ABI encodes addresses as left-padded 32-byte words; the first 12 bytes must be zero.
    ensure!(
        d[128..140] == [0u8; 12],
        "invalid ABI encoding: address padding bytes (128..140) must be zero"
    );

    let mut chain_id_bytes = [0u8; 32];
    chain_id_bytes.copy_from_slice(&d[32..64]);
    let mut application_id_bytes = [0u8; 32];
    application_id_bytes.copy_from_slice(&d[64..96]);
    let mut account_owner_bytes = [0u8; 32];
    account_owner_bytes.copy_from_slice(&d[96..128]);

    Ok(DepositEvent {
        source_chain_id: U256::from_be_slice(&d[0..32]),
        target_chain_id: ChainId(CryptoHash::from(chain_id_bytes)),
        target_application_id: ApplicationId::new(CryptoHash::from(application_id_bytes)),
        target_account_owner: AccountOwner::from(account_owner_bytes),
        depositor,
        token: Address::from_slice(&d[140..160]),

View on GitHub (pinned to 6c226ddcb3)

Solutions

  1. Confirm from the contract ABI that field 5 (offset 128) is an address; if it is bytes32, remove the padding check and read the full word.
  2. If the ABI reordered fields, recompute every offset (0, 32, 64, 96, 128, 160, 192) — do not patch just this one check.
  3. Reject the receipt as invalid rather than masking: a non-zero-padded address word in a signature-matched log means the emitter is not the contract the parser was written for.
  4. Add a regression test that decodes a known-good mainnet receipt so ABI drift is caught before release.

Example fix

// before
ensure!(d[128..140] == [0u8; 12], "invalid ABI encoding: address padding bytes (128..140) must be zero");

// after (ABI changed: token is bytes32 at 128..160, amount moved to 160..192)
// remove the padding check for this word and read it whole:
let token = B256::from_slice(&d[128..160]);
Defensive patterns

Strategy: validation

Validate before calling

fn token_word_is_padded_address(data: &[u8]) -> bool {
    data.len() == 224 && data[128..140] == [0u8; 12]
}

if !token_word_is_padded_address(&log.data) {
    tracing::warn!("data word 4 is not a left-padded address; ABI mismatch");
    continue;
}

Try / catch

match parse_deposit_event(&log, bridge_addr) {
    Ok(ev) => Some(ev),
    Err(e) if e.to_string().contains("address padding bytes (128..140)") => {
        tracing::warn!("token field not address-encoded; skipping log");
        None
    }
    Err(e) => { tracing::error!(error = %e, "deposit parse failed"); None }
}

Prevention

When it happens

Trigger: The token field in the contract's event is declared bytes32 rather than address; an earlier field's size changed so all following offsets shifted and word 4 now covers different data; a forged or corrupt receipt whose data section is not valid ABI for the expected layout.

Common situations: Contract redeployed changing token from address to bytes32 (or vice versa) without updating the parser; parser offsets edited for a new field order but the padding check still hard-codes 128..140; decoding receipts from a mismatched chain fork where the event layout differs.

Related errors


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