Skip to content

Add support for for the removed attribute in contractLog #2661

@montyly

Description

@montyly

Describe

Following on ApeWorX/silverback#259, it would be great if the removed attribute of events could be accesible through ape's API.

This will allow bot creator to handle more easily re-org risks (see ApeWorX/silverback#259)

Specification

I believe this needs to be done through an update of

def decode_logs(self, logs: Sequence[dict], *events: EventABI) -> Iterator[ContractLog]:
if not logs:
return
abi_inputs = {
encode_hex(keccak(text=abi.selector)): LogInputABICollection(abi) for abi in events
}
def get_abi(_topic: HexStr) -> Optional[LogInputABICollection]:
return abi_inputs[_topic] if _topic in abi_inputs else None
for log in logs:
if log.get("anonymous"):
raise NotImplementedError(
"decoding anonymous logs is not supported with this method"
)
topics = log["topics"]
# web3.py converts topics to HexBytes, data is always a HexStr
if isinstance(log["topics"][0], bytes):
topics = [encode_hex(t) for t in log["topics"]]
elif not topics:
continue
if not (abi := get_abi(topics[0])):
continue
event_arguments = abi.decode(topics, log["data"], use_hex_on_fail=True)
# Since LogABICollection does not have access to the Ecosystem,
# the rest of the decoding must happen here.
converted_arguments: dict = {}
for item in abi.abi.inputs:
_type, key, value = item.canonical_type, item.name, event_arguments[item.name]
if isinstance(value, Struct):
struct_types = _type.lstrip("(").rstrip(")").split(",")
for struct_type, (struct_key, struct_val) in zip(struct_types, value.items()):
value[struct_key] = (
self.decode_address(struct_val)
if struct_type == "address"
else HexBytes(struct_val)
if "bytes" in struct_type
else struct_val
)
converted_arguments[key] = value
elif _type == "address":
converted_arguments[key] = self.decode_address(value)
elif is_array(_type):
sub_type = "[".join(_type.split("[")[:-1])
converted_arguments[key] = (
[self.decode_address(v) for v in value] if sub_type == "address" else value
)
elif isinstance(value, int):
# This allows integers to be comparable with currency-value
# strings, such as "1 ETH".
converted_arguments[key] = CurrencyValueComparable(value)
else:
# No change.
converted_arguments[key] = value
yield ContractLog(
_abi=abi,
block_hash=log.get("blockHash") or log.get("block_hash") or "",
block_number=log.get("blockNumber") or log.get("block_number") or 0,
contract_address=self.decode_address(log["address"]),
event_arguments=converted_arguments,
event_name=abi.event_name,
log_index=log.get("logIndex") or log.get("log_index") or 0,
transaction_hash=log.get("transactionHash") or log.get("transaction_hash") or "",
transaction_index=(
log.get("transactionIndex")
if "transactionIndex" in log
else log.get("transaction_index")
),
)

But I am not yet fully familar with ape, so let me know if I am missing something

Dependencies

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions