# Events

Up until this point of the textbook, all on-chain data has revolved around the smart contract; that is, any information that we associated as living on the blockchain was always tied to an associated contract (i.e. via a state variable). In this section, we will go over *events*, a different form of on-chain data that allows us to permanently store data without having it be stored within a smart contract.

### Motivation: Dummy ERC-20 Token

To understand events, we will introduce the example of a "dummy" ERC-20 token called... `Dummy`.

{% code title="Dummy.sol" %}

```solidity
contract Dummy {

    function transfer() public {}

}
```

{% endcode %}

Like all ERC-20 tokens, `Dummy` has the logic necessary to transfer tokens from one address to another, via the `transfer` function. However, rather than being able to just transfer tokens between addresses, we would also like to *keep track of every transfer*. Whether you are the IRS or your average on-chain data scrapper, there is good reason to track *transfer events*.&#x20;

To start, one might track transfer events via the following principle:

> Create a state variable which stores all transfer events (as a list). Furthermore, for each transfer event, append the event to the transfer event list

An updated implementation of the `Dummy` token with this new principle in mind might look like as follows:

```solidity
contract Dummy {

    struct TransferEvent {
        address from;
        address to;
        uint amount;
    }

    TransferEvent[] allTransfers;

    function transfer() public {
        address from = msg.sender; // Arbitrary values
        address to = address(0x0);
        uint amount = 1;
        // Transfer logic goes here
        allTransfers.push(TransferEvent(from, to, amount));
    }

}
```

Examining each segment of this new `Dummy` contract in depth:

* `TransferEvent`: struct which represents a transfer event. This struct holds the from address, to address, and value transfered.
* `allTransfers`: a dynamic array which holds all transfer events
* `transfer`:  function which executes a transfer. At the end of this function, the transfer event is appended to `allTransfers`.

Our new implementation of the `Dummy` token is now able to keep track of every transfer event! However, the biggest issue with this is that this new implementation is ***egregiously inefficient***. Storing all transfer events into a state variable is extremely costly when considering the `transfer` function might be called thousands of times per day. Are we doomed?

### Events

As the last section made it evident, we want a way to store transfer events without having to use any contract data. For this, we can leverage *events*. The syntax for events is as follows:

```solidity
event eventName();
```

Inside the parentheses is where we can list the arguments of our event (i.e. the data that we want logged). In the case of our transfer event, we can define the following:

```solidity
event Transfer(address from, address to, uint value);
```

Finally, now that we have our event defined, we can *emit* our event as follows:

```solidity
emit Transfer(from, to, value);
```

Tying all these ideas, the following code is an updated version of our `Dummy` token which utilizes events to record transfers:

```solidity
contract Dummy {

    event Transfer(address from, address to, uint value);
    
    function transfer() public {
        address from = msg.sender;
        address to = address(0x0);
        uint value = 1;
        emit Transfer(from, to, value);
    }

}
```

Many might be wondering where events are actually stored? As mentioned previously, events are not stored as state variables; rather, events are stored as part of the transaction receipt. By storing data in this format, users are able to store on-chain data without having to utilize state variables.

{% hint style="info" %}

#### Who Can Access Event Data?

Because events are stored as part of the transaction receipt, all nodes (and users with access to a node) can access events. However, this also means that contracts cannot access event data.
{% endhint %}

### Indexing

Although we showed how to store data in events, we have not shown how to prioritize certain types of data within an event. To understand why we might want to prioritize certain data fields in our events, consider again the `Transfer` event:

```solidity
event Transfer(address from, address to, uint value);
```

Although we will get more into how events are represented when we discuss the EVM, the general structure of events is as follows:

* Event ID
* Event Data

With our current implementation of the `Transfer` event, our event data field is as follows (utilizing arbitrary values for the from, to, and value fields):

<pre><code><strong>0x000000000000000000000000Fb2b43852f444DE82643ec58BDc125Ee4EBeDad6000000000000000000000000549889FA3522717E7F1665647BA89f58DE8D277d0000000000000000000000000000000000000000000000000000000000000001
</strong></code></pre>

Although it is possible to extract the arguments from event data field, most can agree that the data field, as it stands, is a mess. Ideally, we want a way to structure our event data so that we can access the arguments of an event directly without having to do any sort of decoding; that is, we want to *prioritize* certain arguments. For this, we can mark the arguments we want to prioritize with the `indexed` label; the following code is an updated of our `Transfer` event that utilizes indexed arguments:

```solidity
event Transfer(address indexed from, address indexed to, uint value);
```

Using indexed arguments, the new structure of our event is as follows:

* Event ID
* `from` Argument: `0x000000000000000000000000Fb2b43852f444DE82643ec58BDc125Ee4EBeDad6`
* `to` Argument: `0x000000000000000000000000549889FA3522717E7F1665647BA89f58DE8D277d`
* Event Data: `0x0000000000000000000000000000000000000000000000000000000000000001`

Using indexed arguments, we can now clearly access the arguments of our event. *Note that the structure of an event is dependent on the ordering of the event arguments.*

{% hint style="info" %}

#### Index Everything?

Although it seems that indexing all arguments is ideal, consider the following:

* We can only index at most 3 arguments in an event
* The amount of gas used in emitting an event is dependent on the number of arguments indexed. Therefore, in the case of our `transfer` event, although we could have indexed all three arguments, it is better from a gas perspective to index only two arguments since *we know* that the data field contains *just* the value transferred.
  {% endhint %}

### Resources

Events in Go Ethereum: <https://goethereumbook.org/events/>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://cs4998.cornellblockchain.org/introduction/hello-world-pt.-2/events.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
