Repository: ApeWorX/ape

Issue:
`ContractEvent.from_receipt` does not check `address` of log
Noticed that when the logs from a `ReceiptAPI` object is passed into `EcosystemAPI.decode_logs`, it is not parsed to ensure only logs matching the `ContractEvent`'s address are passed in:
https://github.com/ApeWorX/ape/blob/15eccaf6d621b25433ef888926d6b87aec908b35/src/ape/contracts/base.py#L786

Easy workaround is to filter out logs that do not match with `ContractEvent.contract.address`

Hints from issue comments:
@linear: <p><a href="https://linear.app/apeworx/issue/APE-1914/contracteventfrom-receipt-does-not-check-address-of-log">APE-1914 `ContractEvent.from_receipt` does not check `address` of log</a></p>

Solution patch:
diff --git a/src/ape/contracts/base.py b/src/ape/contracts/base.py
index fa778b8b5..c6532a214 100644
--- a/src/ape/contracts/base.py
+++ b/src/ape/contracts/base.py
@@ -783,7 +783,18 @@ class ContractEvent(BaseInterfaceModel):
         ecosystem = self.provider.network.ecosystem
 
         # NOTE: Safe to use a list because a receipt should never have too many logs.
-        return list(ecosystem.decode_logs(receipt.logs, self.abi))
+        return list(
+            ecosystem.decode_logs(
+                # NOTE: Filter out logs that do not match this address (if address available)
+                #       (okay to be empty list, since EcosystemAPI.decode_logs will return [])
+                [
+                    log
+                    for log in receipt.logs
+                    if log["address"] == getattr(self.contract, "address", log["address"])
+                ],
+                self.abi,
+            )
+        )
 
     def poll_logs(
         self,


Test patch:
diff --git a/tests/functional/test_contract_event.py b/tests/functional/test_contract_event.py
index 0b5ac112b..c32be00ac 100644
--- a/tests/functional/test_contract_event.py
+++ b/tests/functional/test_contract_event.py
@@ -33,7 +33,7 @@ def assert_log_values(owner):
     return _assert_log_values
 
 
-def test_from_receipts(owner, contract_instance, assert_log_values):
+def test_from_receipt(owner, contract_instance, assert_log_values):
     event_type = contract_instance.NumberChange
 
     # Invoke a transaction 3 times that generates 3 logs.
@@ -46,7 +46,7 @@ def test_from_receipts(owner, contract_instance, assert_log_values):
         assert len(logs) == 1
         assert_log_values(logs[0], num)
 
-        # Also verify can we logs the other way
+        # Also verify can we decode logs the other way
         logs = receipt.decode_logs(event_type)
         assert len(logs) == 1
         assert_log_values(logs[0], num)
@@ -56,6 +56,16 @@ def test_from_receipts(owner, contract_instance, assert_log_values):
     assert_receipt_logs(receipt_2, 3)
 
 
+def test_from_receipt_different_contract(
+    owner, vyper_contract_instance, solidity_contract_instance, assert_log_values
+):
+    # NOTE: Ths event type is similar but defined on a different contract.
+    event_type = solidity_contract_instance.NumberChange
+    receipt = vyper_contract_instance.setNumber(1, sender=owner)
+    logs = event_type.from_receipt(receipt)
+    assert len(logs) == 0
+
+
 def test_from_event_type(contract_instance, owner, assert_log_values):
     event_type = contract_instance.NumberChange
     start_num = 6