Repository: ethereum/web3.py

Issue:
web3py cannot match Event ABIs when indexed arguments are not placed first
* Version: 6.15.1
* Python: 3.10
* OS: macOS
* `pip freeze` output

```
eth_abi                   5.0.1
eth-account               0.11.0
eth-bloom                 3.0.0
eth-hash                  0.5.2
eth-keyfile               0.7.0
eth-keys                  0.5.0
eth-retry                 0.1.19
eth-rlp                   1.0.1
eth-typing                3.5.2
eth-utils                 2.3.1
web3                      6.15.1
```


### What was wrong?

Somewhere in the library stack, `.process_log()` on Contract instances assume that ABI Event definitions always begin with their indexed arguments. 

Circle's [TokenMessenger Contract](https://github.com/circlefin/evm-cctp-contracts/blob/master/src/TokenMessenger.sol#L45) contains an event called `DepositForBurn()` where an indexed argument appears after an unindexed one.  (See also [the ABI](https://raw.githubusercontent.com/circlefin/evm-cctp-contracts/master/docs/abis/cctp/TokenMessenger.json) for the contract)

The correct hashing method of this Event would be `DepositForBurn(uint64,address,uint256,address,bytes32,uint32,bytes32,bytes32)`, or `0x2fa9ca894982930190727e75500a97d8dc500233a5065e0f3126c48fbe0343c0` (evidenced by [any txn](https://arbiscan.io/tx/0x51d5c2d87cdf8b7dc560c807521869f47ca8d7a1ad879c0237747ec45f5d1bfb#eventlog) that emits the event)

However, when trying to process any log using `contract.events.DepositForBurn().process_log(event)`, web3py throws a `MismatchedABI` exception. 
Debugging that call, it has somehow resolved topic0 to `0xfe7cd5fd79e991f2a72bb5f9aa66d76845cd7d1b8f205b6a264148cf0d1f8876`, which happens to be the keccak of the event signature if indexed params are assumed to be first, like:
`DepositForBurn(uint64,address,address,uint256,bytes32,uint32,bytes32,bytes32)`

### How can it be fixed?

Unfortunately, I was unable to properly trace whether web3py, eth-abi, or eth-utils is altering the evaluated ABI in this manner.  However, retaining exact order as published in the ABI will likely correct this issue.


Discussion:

Resolving patch:
diff --git a/web3/_utils/events.py b/web3/_utils/events.py
--- a/web3/_utils/events.py
+++ b/web3/_utils/events.py
@@ -68,6 +68,9 @@
 from web3._utils.normalizers import (
     BASE_RETURN_NORMALIZERS,
 )
+from web3._utils.type_conversion import (
+    to_hex_if_bytes,
+)
 from web3.datastructures import (
     AttributeDict,
 )
@@ -228,8 +231,11 @@ def get_event_data(
         log_topics = log_entry["topics"]
     elif not log_entry["topics"]:
         raise MismatchedABI("Expected non-anonymous event to have 1 or more topics")
-    # type ignored b/c event_abi_to_log_topic(event_abi: Dict[str, Any])
-    elif event_abi_to_log_topic(event_abi) != log_entry["topics"][0]:  # type: ignore
+    elif (
+        # type ignored b/c event_abi_to_log_topic(event_abi: Dict[str, Any])
+        to_hex(event_abi_to_log_topic(event_abi))  # type: ignore
+        != to_hex_if_bytes(log_entry["topics"][0])
+    ):
         raise MismatchedABI("The event signature did not match the provided ABI")
     else:
         log_topics = log_entry["topics"][1:]


Test patch:
diff --git a/tests/core/contracts/test_extracting_event_data.py b/tests/core/contracts/test_extracting_event_data.py
--- a/tests/core/contracts/test_extracting_event_data.py
+++ b/tests/core/contracts/test_extracting_event_data.py
@@ -143,6 +143,115 @@ def test_event_data_extraction(
     assert event_data["event"] == event_name
 
 
+def test_event_data_with_ordered_indexed_inputs(w3):
+    event_abi = {
+        "anonymous": False,
+        "inputs": [
+            {
+                "indexed": True,
+                "internalType": "uint64",
+                "name": "nonce",
+                "type": "uint64",
+            },
+            {
+                "indexed": True,
+                "internalType": "address",
+                "name": "burnToken",
+                "type": "address",
+            },
+            {
+                "indexed": False,
+                "internalType": "uint256",
+                "name": "amount",
+                "type": "uint256",
+            },
+            {
+                "indexed": True,
+                "internalType": "address",
+                "name": "depositor",
+                "type": "address",
+            },
+            {
+                "indexed": False,
+                "internalType": "bytes32",
+                "name": "mintRecipient",
+                "type": "bytes32",
+            },
+            {
+                "indexed": False,
+                "internalType": "uint32",
+                "name": "destinationDomain",
+                "type": "uint32",
+            },
+            {
+                "indexed": False,
+                "internalType": "bytes32",
+                "name": "destinationTokenMessenger",
+                "type": "bytes32",
+            },
+            {
+                "indexed": False,
+                "internalType": "bytes32",
+                "name": "destinationCaller",
+                "type": "bytes32",
+            },
+        ],
+        "name": "DepositForBurn",
+        "type": "event",
+    }
+    log_entry = {
+        "name": "DepositForBurn",
+        "topics": (
+            "0x2fa9ca894982930190727e75500a97d8dc500233a5065e0f3126c48fbe0343c0",
+            w3.to_bytes(
+                hexstr="0x0000000000000000000000000000000000000000000000000000000000014f45"  # noqa: E501
+            ),
+            w3.to_bytes(
+                hexstr="0x" + "af88d065e77c8cC2239327C5EDb3A432268e5831".zfill(64)
+            ),
+            w3.to_bytes(
+                hexstr="0x" + "02Ae4716B9D5d48Db1445814b0eDE39f5c28264B".zfill(64)
+            ),
+        ),
+        "data": w3.to_bytes(
+            hexstr="0x00000000000000000000000000000000000000000000000000000002962f766700000000000000000000000065f2145693be3e75b8cfb2e318a3a74d057e6c7b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bd3fa81b58ba92a82136038b25adec7066af31550000000000000000000000000000000000000000000000000000000000000000"  # noqa: E501
+        ),
+        "logIndex": 1,
+        "transactionIndex": 1,
+        "transactionHash": "1234",
+        "address": "0x19330d10d9cc8751218eaf51e8885d058642e08a",
+        "blockHash": "",
+        "blockNumber": "",
+    }
+    event_data = get_event_data(w3.codec, event_abi, log_entry)
+    expected = {
+        "args": {
+            "nonce": 85829,
+            "burnToken": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
+            "depositor": "0x02Ae4716B9D5d48Db1445814b0eDE39f5c28264B",
+            "amount": 11109627495,
+            "mintRecipient": b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00e\xf2\x14V\x93\xbe>u\xb8\xcf\xb2\xe3\x18\xa3\xa7M\x05~l{",  # noqa: E501
+            "destinationDomain": 0,
+            "destinationTokenMessenger": b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbd?\xa8\x1bX\xba\x92\xa8!6\x03\x8b%\xad\xecpf\xaf1U",  # noqa: E501
+            "destinationCaller": b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",  # noqa: E501
+        },
+        "event": "DepositForBurn",
+        "logIndex": 1,
+        "transactionIndex": 1,
+        "transactionHash": "1234",
+        "address": "0x19330d10d9cc8751218eaf51e8885d058642e08a",
+        "blockHash": "",
+        "blockNumber": "",
+    }
+
+    assert event_data["args"] == expected["args"]
+    assert event_data["blockHash"] == expected["blockHash"]
+    assert event_data["blockNumber"] == expected["blockNumber"]
+    assert event_data["transactionIndex"] == expected["transactionIndex"]
+    assert is_same_address(event_data["address"], expected["address"])
+    assert event_data["event"] == expected["event"]
+
+
 @pytest.mark.parametrize(
     "call_args,expected_args",
     (