Monitor events from multiple contracts web3.py

dappspythonweb3.py

When a user signs up on my system, a custom 'deposit' contract gets created. N users signing up means N deposit contracts.

I am able to monitor the events from 1 contract using the following code:

contract_address = '' contract here
contract_abi = json.loads('ABI HERE')

contract = web3.eth.contract(address=contract_address, abi=contract_abi)

def handle_event(event):
    print(web3.eth.get_block('latest')['number'])

    temp = json.loads(Web3.toJSON(event))
    print(temp)

async def log_loop(event_filter, poll_interval):
    while True:
        for PairCreated in event_filter.get_new_entries():
            print("I'm here")
            handle_event(PairCreated)
        await asyncio.sleep(poll_interval)


def main():
    event_filter = contract.events.EVENT.createFilter(fromBlock='latest')
    loop = asyncio.get_event_loop()
    try:
        loop.run_until_complete(
            asyncio.gather(
                log_loop(event_filter, 2)))
    finally:
        loop.close()


if __name__ == "__main__":
    main()

However, this just monitors ONE contract, I want it to be able to monitor multiple contracts (the same event but emitted from multiple contracts)

Is there anything I can do to achieve this (apart from spawning another listener process for each new contract, that I'm sure will consume memory very quickly on any box we run this on) and simply wont scale.

Best Answer

So instead of monitoring all events from all contracts, what I did instead is created a new contract:

event Event:
    sender: indexed(address)
    value: uint256

admin: public(HashMap[address,address])
minter: address

@external
def __init__():
    self.minter = msg.sender


@external
def setadmin(_address: address)->bool:
    assert msg.sender != self.minter, "Not admin"
    self.admin[_address] = _address
    return True


@external
def reporter(_address: address, withdraw: uint256)->bool:
    assert msg.sender != self.admin[msg.sender], "Not admin"
    log Event(msg.sender,withdraw)
    return True

I then interface this contract in each individual contract and effectively all the contracts invoke this contract which sends out one event. I then just need to monitor one contract's events not all contracts.

While typing this, I've noticed that there was a glaring security problem whereby anyone could invoke reporter() and issue an Event (which I subsequently relied upon to mint a coin offchain).

I then upgraded the contract to create an array of admin addresses (each contract that will be subsequently monitored) which only they have the power to invoke reporter() and issue the Event.