{"record":{"id":"a36d848308ecbd60","repo":"linera-io/linera-protocol","slug":"invalid-abi-encoding-address-padding-bytes-128","errorCode":null,"errorMessage":"invalid ABI encoding: address padding bytes (128..140) must be zero","messagePattern":"invalid ABI encoding: address padding bytes \\(128\\.\\.140\\) must be zero","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"linera-bridge/src/proof/mod.rs","lineNumber":457,"sourceCode":"    );\n    ensure!(\n        log.data.len() == 224,\n        \"expected 224 bytes of event data (7 x 32), got {}\",\n        log.data.len()\n    );\n\n    // Indexed `depositor` is in topics[1], left-padded to 32 bytes.\n    let depositor_topic = log.topics[1];\n    ensure!(\n        depositor_topic.as_slice()[..12] == [0u8; 12],\n        \"invalid ABI encoding: depositor topic padding bytes (0..12) must be zero\"\n    );\n    let depositor = Address::from_slice(&depositor_topic.as_slice()[12..32]);\n\n    let d = &log.data;\n\n    // ABI encodes addresses as left-padded 32-byte words; the first 12 bytes must be zero.\n    ensure!(\n        d[128..140] == [0u8; 12],\n        \"invalid ABI encoding: address padding bytes (128..140) must be zero\"\n    );\n\n    let mut chain_id_bytes = [0u8; 32];\n    chain_id_bytes.copy_from_slice(&d[32..64]);\n    let mut application_id_bytes = [0u8; 32];\n    application_id_bytes.copy_from_slice(&d[64..96]);\n    let mut account_owner_bytes = [0u8; 32];\n    account_owner_bytes.copy_from_slice(&d[96..128]);\n\n    Ok(DepositEvent {\n        source_chain_id: U256::from_be_slice(&d[0..32]),\n        target_chain_id: ChainId(CryptoHash::from(chain_id_bytes)),\n        target_application_id: ApplicationId::new(CryptoHash::from(application_id_bytes)),\n        target_account_owner: AccountOwner::from(account_owner_bytes),\n        depositor,\n        token: Address::from_slice(&d[140..160]),","sourceCodeStart":439,"sourceCodeEnd":475,"githubUrl":"https://github.com/linera-io/linera-protocol/blob/6c226ddcb332ef55118dc8d0aafbd093d5420899/linera-bridge/src/proof/mod.rs#L439-L475","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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.","If the ABI reordered fields, recompute every offset (0, 32, 64, 96, 128, 160, 192) — do not patch just this one check.","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.","Add a regression test that decodes a known-good mainnet receipt so ABI drift is caught before release."],"exampleFix":"// before\nensure!(d[128..140] == [0u8; 12], \"invalid ABI encoding: address padding bytes (128..140) must be zero\");\n\n// after (ABI changed: token is bytes32 at 128..160, amount moved to 160..192)\n// remove the padding check for this word and read it whole:\nlet token = B256::from_slice(&d[128..160]);","handlingStrategy":"validation","validationCode":"fn token_word_is_padded_address(data: &[u8]) -> bool {\n    data.len() == 224 && data[128..140] == [0u8; 12]\n}\n\nif !token_word_is_padded_address(&log.data) {\n    tracing::warn!(\"data word 4 is not a left-padded address; ABI mismatch\");\n    continue;\n}","typeGuard":null,"tryCatchPattern":"match parse_deposit_event(&log, bridge_addr) {\n    Ok(ev) => Some(ev),\n    Err(e) if e.to_string().contains(\"address padding bytes (128..140)\") => {\n        tracing::warn!(\"token field not address-encoded; skipping log\");\n        None\n    }\n    Err(e) => { tracing::error!(error = %e, \"deposit parse failed\"); None }\n}","preventionTips":["Treat padding-check failures as ABI drift alarms; audit the full field layout before changing any offset.","Lock parser and contract versions; add a canary test decoding one real mainnet deposit receipt per release.","Keep the offset constants (0,32,64,96,128,160,192) in one place so ABI edits stay coherent."],"tags":["ethereum","evm","abi","encoding","rust","linera-bridge"],"backgroundTag":"evm-event-abi-mismatch","analyzedSha":"6c226ddcb332ef55118dc8d0aafbd093d5420899","analyzedAt":"2026-08-22T22:49:09.787Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}