6

I'm fetching the logs using client.SubscribeFilterLogs. The event parameters are encoded in types.Log.Data. How can I decode it in go?

  • Yes, the go-ethereum (the geth libraries) package received the contribution to add Event unpacking. I will write more about it in the answer below. – Robert Zaremba Nov 29 '17 at 19:04
7

go-ethereum abi package in Oct 2017 got the update to unpack event output. Initially it was only able to unpack method output.

All functionality is delivered through the abi.ABI object. To use it you need to have Event ABI (JSON string). Then use func (abi *ABI) UnmarshalJSON to construct the ABI object. From there you can use the Unpack method using Data from your log object.

Bear in mind that indexed attributes go into log Topic rather then Data.

For more usage details you can follow this examples:

NOTE: In the current implementation (2017-11-29) there is a bug with indexed attributes. I've submitted a PR for that and still waiting for the final approval.

4

Here's a full code example for anyone who's still confused (thanks to @Robert Zaremba's answer)

package main

import (
    "context"

    "log"
    "math/big"
    "strings"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/accounts/abi"
    "github.com/ethereum/go-ethereum/common"

    "github.com/myorg/myrepo/go-contracts/token"
    "github.com/ethereum/go-ethereum/core/types"
)


func main() {
    contractAddress := common.HexToAddress("0x0d8775f648430679a709e98d2b0cb6250d2887ef")

    query := ethereum.FilterQuery{
        Addresses: []common.Address{contractAddress},
    }

    var ch = make(chan types.Log)
    ctx := context.Background()

    sub, err := Client.SubscribeFilterLogs(ctx, query, ch)

    if err != nil {
        log.Fatal(err)
    }

    tokenAbi, err := abi.JSON(strings.NewReader(string(token.TokenABI)))

    if err != nil {
        log.Fatal(err)
    }

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case eventLog := <-ch:
            var transferEvent struct {
                From  common.Address
                To    common.Address
                Value *big.Int
            }

            err = tokenAbi.Unpack(&transferEvent, "Transfer", eventLog.Data)

            if err != nil {
                log.Println("Failed to unpack")
                continue
            }

            transferEvent.From = common.BytesToAddress(eventLog.Topics[1].Bytes())
            transferEvent.To = common.BytesToAddress(eventLog.Topics[2].Bytes())

            log.Println("From", transferEvent.From.Hex())
            log.Println("To", transferEvent.To.Hex())
            log.Println("Value", transferEvent.Value)
        }
    }
}
  • One question: how do you know if the data contains a Transfer event, or a Approval event??? Because, you can receive both, or you can even receive other events, like burn or mint , so how do you know in advance which type of event do you have to unpack? – Nulik Jun 23 '18 at 20:25
  • @Nulik great question; so topic[0] will be the event signature which is keccak256(eventName(arg1,arg2)) so if it's a transfer event then topic[0] will be keccak256(Transfer(address,address,uint256)) => ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. So in short: you know the event type by filtering by topic[0] which is the hash of the event signature. Check out this Ethereum Development with Go guide for examples goethereumbook.org – Miguel Mota Jun 23 '18 at 20:32
  • @Nulik here's an example event log of a transfer event etherscan.io/tx/… . As you can see topic[0] is keccak256(Transfer(address,address,uint256)) => ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef – Miguel Mota Jun 23 '18 at 20:34
  • @Nulik here's an example event log of an approval event etherscan.io/tx/… . As you can see topic[0] is keccak256(Approval(address,address,uint256)) => 8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925 – Miguel Mota Jun 23 '18 at 20:36
  • Thanks, I have got it now. BTW, do you know of any other standard events? Transfer() and Approval() are the usual, but many tokens add minting or burning events. Do you know of any other events that are becoming standard too for erc20 tokens? – Nulik Jun 23 '18 at 20:58
2

Here's how I did it using the ABI:

path, _ := filepath.Abs("./resources/etherdelta.abi")
file, err := ioutil.ReadFile(path)
if err != nil {
    fmt.Println("Failed to read file:", err)
}
edabi, err := abi.JSON(strings.NewReader(string(file)))
if err != nil {
    fmt.Println("Invalid abi:", err)
}
var orderStruct struct {
    TokenGet   common.Address
    AmountGet  *big.Int
    TokenGive  common.Address
    AmountGive *big.Int
    Expires    *big.Int
    Nonce      *big.Int
    User       common.Address
}
err = edabi.Unpack(&orderStruct, "Order", log.Data)
if err != nil {
    fmt.Println("Failed to unpack:", err)
}
fmt.Println("TokenGet:", orderStruct.TokenGet.Hex())
fmt.Println("AmountGet:", orderStruct.AmountGet.Hex())

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.