Reading ethereum contract events using Angular and ethers
Tags: ethereum, smartcontract, angular, ethers
Published: 2023-11-02 08:09:17

In this last post of this serie, we are going to see how to query contract events using ethers. To do it, we are going to use the contract deployed in the previous post. There, we deployed a contract to Goerli test network and called *initialize* function. Now, we are going to call *addOffer* function and then use ethers to query the *NewOffer* event emitted by the *addOffer* function.

### The code
You can find a minimal code [here](https://github.com/icolomina/house-swap-dapp). It includes an angular application with:

- The services to connect the wallet, deploy the contract and interact with it.
- The HomeComponent with the methods to connect, deploy and interact with the contract
- A minimal HTML with a button which connects the wallet.

The aim of this code is not to serve as a ready project but as a template so developers can use it as a base for building  any dapp using angular.

I've done some changes in the wallet connect process since the button is located in the app component and it has to communicate to the home component when the wallet is connected.

If you want to run the project, you will have to follow the next steps before:

- Compile the contract as we did in the [second post](https://dev.to/icolomina/testing-a-solidity-house-swap-contract-using-hardhat-and-typescript-4617) using hardhat. Then copy the file located in *artifacts/contracts/HouseSwap.sol/HouseSwap.json* to the angular project assets folder with the name *house_swap.json*.
- Generate the mapping type using typechain. Refer to the [previous post](https://dev.to/icolomina/deploying-and-accesing-an-ethereum-contract-using-ethers-and-angular-2hnd) to check how to do it. Ensure to execute the command in the *src/app* folder so the mappings being generated under *src/app/types* folder.

Then, you can run the *ng serve* command.

### Adding the new function to ContractInteractorService

In the last post, we created a service called *ContractInteractorService* which was in charge of interacting with the contract. Let's add a method to call *addOffer* function

```typescript
addOffer(house: HouseSwap.HouseStruct, amountPayOriginToTarget: number, amountPayTargetToOrigin: number): Promise<ContractTransactionResponse> {
    return this.contract.addOffer(house, amountPayOriginToTarget, amountPayTargetToOrigin);
}
```
As we can see, the function is simple, it uses the contract instance to call *addOffer* passing the required params. 

> Remember that, as we used typechain to map contract types to typescript, we can call the contract function as it was a class method.

### Adding the function to the HomeComponent

Let's go now to the *HomeComponent* to add the method which will call the *ContractInteractorService* *addOffer* function.

```typescript
async addOffer(contractAddress: string) {
    const address = await this.signer.getAddress();
    const house: HouseSwap.HouseStruct = {
      houseType: 'apartment',
      link: 'https://www.infolink2.com',
      value: 44158,
      propietary: address
    }

    this
      .contractInteractorSrv
      .addOfer(house, 0, 199865245)
      .then(
        async (callResult: ContractTransactionResponse) => {
          console.log(callResult.toJSON())
    })
}
```
This function is similar to the *initializeContract* function. The only difference is that, in this case, we are calling to *addOffer* function. 


![addOffer function result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/loqvz5k8lbmfkjdt9zc9.png)

The image above shows some data of the call result. As we did in the previous post, we can copy the transaction hash, go to the [goerli ethersan](https://goerli.etherscan.io/) and query the transaction information.


![addOffer transaction information](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4v01d31kmfg7hosoz5we.png)

As we can see in the image, the transaction has been successfully executed.

### Quering the contract *NewOffer* events

As the *addOffer* function emits a *NewOffer* event, we need to query contract *NewOffer* events so the owner contract could  read them.
Let's use *queryFilter* ethers function to achieve this.
First of all, we will add a new method in the *ContractInteractorService*:

```typescript
queryFilters(): Promise<Array<TypedEventLog<any>>> {
    return this.contract.queryFilter(this.contract.filters.NewOffer);
}
```

This method is pretty simple, it uses contract *queryFilter* method to retrieve *NewOffer* emitted events.

> Both contract *queryFilter* and *filters* object are result of the typechain mapping.

Now, let's go back to the *HomeComponent* and add a new method called *getContractOffers*.

```typescript
getContractOffers(contractAddress: string) {
    this.contractInteractorSrv.queryFilters().then(
      (result: TypedEventLog<any>[]) => {
        if(result.length > 0) {
          result.forEach((e: TypedEventLog<any>) => {
            const eventData = e.args[0][0];
            console.log('HouseType:' + eventData[0]);
            console.log('value:' + eventData[1]);
            console.log('Link:' + eventData[2]);
            console.log('Propietary:' + eventData[3]);
          })
        }
      }
    );
}
```

The *getContractOffers* uses the recently added *ContractInteractorService* *queryFilters* function to retrieve the events. If there are events, it loops each of them and logs their args.



![addOffer NewOffer data](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qz6ahpivvbwu56dimdxf.png)

The above image shows the result of the *getContractOffers* method logs. This would be the way as the contract owners should read the offers.

### Resume
In this last post we have seen, specifically, how to read contract events using ethers. That is the last aspect regarding the interaction with smart contracts.
Quering contract events is important since it allows users to respond to such events. In this case, the contract owner can respond to a *NewOffer* event if he would want to accept it.