ApeWorX / silverback

Blockchain automation library, and SDK for the Silverback Platform
https://apeworx.io/silverback
Apache License 2.0
88 stars 10 forks source link

Subscribe only to event signature #99

Open elier opened 3 months ago

elier commented 3 months ago

Overview

I would like to subscribe to events independently of the contract address.

Specification

This is what is supported today to listen only to USDC_WETH swaps.

USDC_WETH = Contract('0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc')

@app.on_(USDC_WETH.Swap)
def handle_swaps(event):
    print(f"Swap: {event}")

This is what I would like to do to listen to any swap:

ANY = ... <= Load something here

@app.on_(ANY.Swap)
def handle_swaps(event):
    print(f"Swap: {event}")
linear[bot] commented 3 months ago

SBK-490 Subscribe only to event signature

elier commented 3 months ago

I tried by removing "address=contract_address" but it crashes even though address argument is optional in poll_logs.

Fragment from PollingRunner:

        async for event in async_wrap_iter(
            self.provider.poll_logs(
                # NOTE: No start block because we should begin polling from head
                address=contract_address,
                new_block_timeout=new_block_timeout,
                events=[event_abi],
            )
        ):
            await self._checkpoint(last_block_seen=event.block_number)
            await self._handle_task(await event_log_task_kicker.kiq(event))
            await self._checkpoint(last_block_processed=event.block_number)
fubuloubu commented 3 months ago

Hmm, would this look like the UX you are after?

from ape import project

# Set up this dependendency in `ape-config.yaml`
UniswapV2Pair = project.dependencies["uniswap-v2"]["1.0.1"].UniswapV2Pair

@app.on_(UniswapV2Pair.Swap)
async def all_univ2_clone_swaps(log):
    ...

Edit: this might be lower lift:

from ethpm_types import EventABI

Swap: EventABI  # ... = EventABI.parse_file("./uni-v2-swap.json")

@app.on_(Swap)
async def all_univ2_clone_swaps(log):
    ...
elier commented 3 months ago

Yes, that's the idea. I find both proposals valid.

fubuloubu commented 3 months ago

Option 1 would need all event definitions exposed in ContractContainer objects (signifying an event with no contract address), which would require some changes in ape (cc @antazoey for your thoughts)

Option 2 is something we can try and ship sooner in silverback, also note you can get an EventABI object from UniswapV2Pair.contract_type.events from the first example (so just a little extra code to pull out the one you want, doesn't require loading the json from scratch)

antazoey commented 3 months ago

Option 1 would need all event definitions exposed in ContractContainer objects (signifying an event with no contract address), which would require some changes in ape (cc @antazoey for your thoughts)

I believe these are already available:

In [1]: type(project.VyperContract)
Out[1]: ape.contracts.base.ContractContainer

In [3]: project.VyperContract.NumberChange
Out[3]: NumberChange(bytes32 b, uint256 prevNum, string dynData, uint256 indexed newNum, string indexed 
dynIndexed)

In [4]: type(project.VyperContract.NumberChange)
Out[4]: ape.contracts.base.ContractEvent

You can do project.VyperContract.events to see them all as well.

fubuloubu commented 3 months ago

Option 1 would need all event definitions exposed in ContractContainer objects (signifying an event with no contract address), which would require some changes in ape (cc @antazoey for your thoughts)

I believe these are already available:

In [1]: type(project.VyperContract)
Out[1]: ape.contracts.base.ContractContainer

In [3]: project.VyperContract.NumberChange
Out[3]: NumberChange(bytes32 b, uint256 prevNum, string dynData, uint256 indexed newNum, string indexed 
dynIndexed)

In [4]: type(project.VyperContract.NumberChange)
Out[4]: ape.contracts.base.ContractEvent

You can do project.VyperContract.events to see them all as well.

Okay perfect, that means the non-silverback code is ready for a feature addition here