description: Tutorial on how to subscribe to smart contract events with Go.

Subscribing to Event Logs

First thing we need to do in order to subscribe to event logs is dial to a websocket enabled Ethereum client. Fortunately for us, Infura supports websockets.

  1. client, err := ethclient.Dial("wss://rinkeby.infura.io/ws")
  2. if err != nil {
  3. log.Fatal(err)
  4. }

The next step is to create a filter query. In this example we’ll be reading all events coming from the example contract that we’ve created in the previous lessons.

  1. contractAddress := common.HexToAddress("0x147B8eb97fD247D06C4006D269c90C1908Fb5D54")
  2. query := ethereum.FilterQuery{
  3. Addresses: []common.Address{contractAddress},
  4. }

The way we’ll be receiving events is through a Go channel. Let’s create one with type of Log from the go-ethereum core/types package.

  1. logs := make(chan types.Log)

Now all we have to do is subscribe by calling SubscribeFilterLogs from the client, which takes in the query options and the output channel. This will return a subscription struct containing unsubscribe and error methods.

  1. sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
  2. if err != nil {
  3. log.Fatal(err)
  4. }

Finally all we have to do is setup an continous loop with a select statement to read in either new log events or the subscription error.

  1. for {
  2. select {
  3. case err := <-sub.Err():
  4. log.Fatal(err)
  5. case vLog := <-logs:
  6. fmt.Println(vLog) // pointer to event log
  7. }
  8. }

You’ll have to parse the log entries, which we’ll learn how to do in the next section.

Full code

Commands

  1. solc --abi Store.sol
  2. solc --bin Store.sol
  3. abigen --bin=Store_sol_Store.bin --abi=Store_sol_Store.abi --pkg=store --out=Store.go

Store.sol

  1. pragma solidity ^0.4.24;
  2. contract Store {
  3. event ItemSet(bytes32 key, bytes32 value);
  4. string public version;
  5. mapping (bytes32 => bytes32) public items;
  6. constructor(string _version) public {
  7. version = _version;
  8. }
  9. function setItem(bytes32 key, bytes32 value) external {
  10. items[key] = value;
  11. emit ItemSet(key, value);
  12. }
  13. }

event_subscribe.go

  1. package main
  2. import (
  3. "context"
  4. "fmt"
  5. "log"
  6. "github.com/ethereum/go-ethereum"
  7. "github.com/ethereum/go-ethereum/common"
  8. "github.com/ethereum/go-ethereum/core/types"
  9. "github.com/ethereum/go-ethereum/ethclient"
  10. )
  11. func main() {
  12. client, err := ethclient.Dial("wss://rinkeby.infura.io/ws")
  13. if err != nil {
  14. log.Fatal(err)
  15. }
  16. contractAddress := common.HexToAddress("0x147B8eb97fD247D06C4006D269c90C1908Fb5D54")
  17. query := ethereum.FilterQuery{
  18. Addresses: []common.Address{contractAddress},
  19. }
  20. logs := make(chan types.Log)
  21. sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
  22. if err != nil {
  23. log.Fatal(err)
  24. }
  25. for {
  26. select {
  27. case err := <-sub.Err():
  28. log.Fatal(err)
  29. case vLog := <-logs:
  30. fmt.Println(vLog) // pointer to event log
  31. }
  32. }
  33. }
  1. $ solc --version
  2. 0.4.24+commit.e67f0147.Emscripten.clang