linera-io/linera-protocol · error
invalid ABI encoding: depositor topic padding bytes (0..12)
Error message
invalid ABI encoding: depositor topic padding bytes (0..12) must be zero
What it means
In ABI encoding, an indexed address parameter is stored in topics as a 32-byte word that is zero-padded on the left 12 bytes. parse_deposit_event takes topics[1] as the depositor and enforces bytes 0..12 are zero before extracting the 20-byte address. The check at linera-bridge/src/proof/mod.rs:448 fails when those padding bytes are non-zero, i.e. the topic is a full 32-byte value (bytes32) rather than a left-padded address, or the log is malformed/forged.
Source
Thrown at linera-bridge/src/proof/mod.rs:448
);
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],
"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];View on GitHub (pinned to 6c226ddcb3)
Solutions
- Verify the contract ABI: the indexed parameter behind topics[1] must be an address type.
- Print topics[1] hex; if bytes 0..12 contain data, you are decoding a bytes32-valued event or a hostile log — do not truncate, reject the log.
- If the ABI legitimately uses bytes32, change the parser to read the full word as the depositor identity instead of enforcing zero padding.
- Fix test fixtures to build topics via left-padded address encoding (12 zero bytes + 20 address bytes).
Example fix
// before 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"); // after (fixture bug: was writing the raw hash) let depositor_topic = log.topics[1]; ensure!(depositor_topic.as_slice()[..12] == [0u8; 12], "depositor topic is not a left-padded address"); // fixture: topics[1] = B256::pad depositor address via 12 zero bytes + address bytes
Defensive patterns
Strategy: validation
Validate before calling
fn depositor_topic_is_padded_address(topic: &B256) -> bool {
topic.as_slice()[..12] == [0u8; 12]
}
if log.topics.len() == 2 && !depositor_topic_is_padded_address(&log.topics[1]) {
tracing::warn!(topic = ?log.topics[1], "topics[1] is not a left-padded address; rejecting log");
continue;
} Try / catch
match parse_deposit_event(&log, bridge_addr) {
Ok(ev) => Some(ev),
Err(e) if e.to_string().contains("depositor topic padding") => {
// Not a valid address encoding; treat as hostile or foreign log.
tracing::warn!("rejecting log with dirty depositor padding");
None
}
Err(e) => { tracing::error!(error = %e, "deposit parse failed"); None }
} Prevention
- Never mask a padding violation by truncating topics[1]: reject the log.
- Verify the indexed parameter type in the contract ABI is address during deployment checks.
- Generate test topics with proper 12-byte zero padding plus the 20-byte address.
When it happens
Trigger: The contract (or a look-alike) declares the indexed parameter as bytes32 instead of address; a malicious emitter crafts a topic with dirty padding hoping the parser will truncate it; a buggy test fixture copies a hash into topics[1] instead of left-padding an address.
Common situations: Contract upgrade changed depositor from address to bytes32 while keeping the event signature (indexed types are not part of the topic[0] hash for non-canonical cases); decoding an impersonated event from a contract that reuses the signature; fixture-generation code in tests that fills topics with random 32-byte values.
Related errors
- invalid ABI encoding: address padding bytes (128..140) must
- expected exactly 2 topics (signature + indexed depositor), g
- expected 224 bytes of event data (7 x 32), got {}
- transaction {tx_hash} reverted (receipt status 0)
- transaction {tx_hash} not confirmed within {RECEIPT_TIMEOUT:
AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22).
Data as JSON: /api/errors/f72053b96437d552.
Report an issue: GitHub.