Go-Ethereum – How to Decode Raw Transaction Inputs in Golang

go-ethereumgolangraw-transaction

When making a contract transaction using go-ethereum (golang) how can I decode the transaction inputs.

Specifically
Given a tx.Data []byte , the contract's contractABI abi.ABI and the method that is being called its methodID string how can I decode tx.Data from hexadecimal to go types ?

I've tried doing abi.Methods[methodID].Inputs.Arguments.UnpackValues(tx.Data) but this always results in an empty slice of values.

Code:

func decodeTxParams(abi abi.ABI, method string, data []byte) ([]interface{}, error) {
    txParams, err := abi.Methods[method].Inputs.UnpackValues(data)
    if err != nil {
        return []interface{}{}, err
    }
    return txParams, nil
}

caller:

func (b *backend) SendTransaction(ctx context.Context, tx *types.Transaction) error {
    err := b.Client.SendTransaction(ctx, tx)
    if err != nil {
        return err
    }

    // update local nonce
    msg, err := tx.AsMessage(types.HomesteadSigner{})
    if err != nil {
        return err
    }
    sender := msg.From()
    b.nonceManager.Lock(sender)
    b.nonceManager.Update(sender, tx.Nonce())
    b.nonceManager.Unlock(sender)

    data := msg.Data()
    method, ok := b.methods[string(data[:4])]
    if !ok {
        method = "unknown"
    }

        txParams, err := decodeTxParams(b.abiMap[string(data[:4])], string(data[:4]), data[4:])

    if err != nil {
        return err
    }

    if err != nil {
        glog.Infof("\n%vEth Transaction%v\n\nInvoking transaction: \"%v\".  \nTransaction Failed: %v\n\n%v\n", strings.Repeat("*", 30), strings.Repeat("*", 30), method, err, strings.Repeat("*", 75))
        return err
    }

    glog.Infof("\n%vEth Transaction%v\n\nInvoking transaction: \"%v\".  Hash: \"%v\". \n\n%v\n", strings.Repeat("*", 30), strings.Repeat("*", 30), method, tx.Hash().String(), strings.Repeat("*", 75))

    return nil
}

Best Answer

func decodeTxParams(abi abi.ABI, v map[string]interface{}, data []byte) (map[string]interface{}, error) {
    m, err := abi.MethodById(data[:4])
    if err != nil {
        return map[string]interface{}{}, err
    }
    if err := m.Inputs.UnpackIntoMap(v, data[4:]); err != nil {
        return map[string]interface{}{}, err
    }
    return v, nil
}
Related Topic