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. Nov 29, 2017 at 19:04

4 Answers 4


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 than 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.


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

package main

import (




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 {

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

    if err != nil {

    for {
        select {
        case err := <-sub.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")

            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, 2018 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 Jun 23, 2018 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 Jun 23, 2018 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 Jun 23, 2018 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, 2018 at 20:58

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())
data := common.TrimLeftZeroes(log.Data)
hex := common.Bytes2Hex(data)
hex = TrimLeftZeroes(hex)
if hex != "" {
    erc20Amount, err := hexutil.DecodeBig("0x" + hex)

func TrimLeftZeroes(hex string) string {
    idx := 0
    for ; idx < len(hex); idx++ {
        if hex[idx] != '0' {
    return hex[idx:]
  • 2
    Explain your code. Jan 19, 2020 at 19:48
  • This is the answer to the question, dont be kidding me.
    – VAN.CY
    Jan 22, 2020 at 7:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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