.. _event-logging:

Event Logging
#############

Vyper can log events to be caught and displayed by user interfaces.

Example of Logging
==================

This example is taken from the `sample ERC20 contract <https://github.com/vyperlang/vyper/blob/master/examples/tokens/ERC20.vy>`_ and shows the basic flow of event logging:

.. code-block:: vyper

    # Events of the token.
    event Transfer:
        sender: indexed(address)
        receiver: indexed(address)
        value: uint256

    event Approval:
        owner: indexed(address)
        spender: indexed(address)
        value: uint256

    # Transfer some tokens from message sender to another address
    def transfer(_to : address, _value : uint256) -> bool:

       ... Logic here to do the real work ...

       # All done, log the event for listeners
       log Transfer(msg.sender, _to, _value)

Let's look at what this is doing.

    1. We declare two event types to log. The two events are similar in that they contain two indexed address fields. Indexed fields do not make up part of the event data itself, but can be searched by clients that want to catch the event. Also, each event contains one single data field, in each case called ``value``. Events can contain several arguments with any names desired.
    2. In the ``transfer`` function, after we do whatever work is necessary, we log the event. We pass three arguments, corresponding with the three arguments of the Transfer event declaration.

Clients listening to the events will declare and handle the events they are interested in using a `library such as web3.js <https://solidity.readthedocs.io/en/latest/contracts.html#events>`_:

.. code-block:: javascript

    var abi = /* abi as generated by the compiler */;
    var MyToken = web3.eth.contract(abi);
    var myToken = MyToken.at("0x1234...ab67" /* address */);

    // watch for changes in the callback
    var event = myToken.Transfer(function(error, result) {
        if (!error) {
            var args = result.returnValues;
            console.log('value transferred = ', args._amount);
        }
    });

In this example, the listening client declares the event to listen for. Any time the contract sends this log event, the callback will be invoked.

Declaring Events
================

Let's look at an event declaration in more detail.

.. code-block:: vyper

    event Transfer:
        sender: indexed(address)
        receiver: indexed(address)
        value: uint256

The EVM currently has five opcodes for emitting event logs: ``LOG0``, ``LOG1``, ``LOG2``, ``LOG3``, and ``LOG4``.
These opcodes can be used to create log records, where each log record consists of both **topics** and **data**.
Topics are 32-byte ''words'' that are used to describe what is happening in an event.
While topics are searchable, data is not.
Event data is however not limited, which means that you can include large or complicated data like arrays or strings.
Different opcodes (``LOG0`` through ``LOG4``) allow for different numbers of topics.
For instance, ``LOG1`` includes one topic, ``LOG2`` includes two topics, and so on.
Event declarations look similar to struct declarations, containing one or more arguments that are passed to the event. Typical events will contain two kinds of arguments:

    * **Indexed** arguments (topics), which can be searched for by listeners. Each indexed argument is identified by the ``indexed`` keyword.  Here, each indexed argument is an address. You can have up to four indexed arguments (``LOG4``), but indexed arguments are not passed directly to listeners, although some of this information (such as the sender) may be available in the listener's `results` object.
    * **Value** arguments (data), which are passed through to listeners. You can have any number of value arguments and they can have arbitrary names, but each is limited by the EVM to be no more than 32 bytes.

Note that the first topic of a log record consists of the signature of the name of the event that occurred, including the types of its parameters.
It is also possible to create an event with no arguments. In this case, use the ``pass`` statement:

.. code-block:: vyper

    event Foo: pass

Logging Events
==============

Once an event is declared, you can log (send) events. You can send events as many times as you want to. Please note that events sent do not take state storage and thus do not cost gas: this makes events a good way to save some information. However, the drawback is that events are not available to contracts, only to clients.

Logging events is done using the ``log`` statement:

.. code-block:: vyper

   log Transfer(msg.sender, _to, _amount)

The order and types of arguments given must match the order of arguments used when declaring the event.

Listening for Events
====================

In the example listener above, the ``result`` arg actually passes a `large amount of information <https://web3js.readthedocs.io/en/v1.2.6/web3-eth-contract.html#contract-events-return>`_. Here we're most interested in ``result.returnValues``. This is an object with properties that match the properties declared in the event. Note that this object does not contain the indexed properties, which can only be searched in the original ``myToken.Transfer`` that created the callback.
