github.com/iotexproject/iotex-core@v1.14.1-rc1/blockindex/contractstaking/util.go (about)

     1  // Copyright (c) 2023 IoTeX Foundation
     2  // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability
     3  // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed.
     4  // This source code is governed by Apache License 2.0 that can be found in the LICENSE file.
     5  
     6  package contractstaking
     7  
     8  import (
     9  	"math/big"
    10  
    11  	"github.com/ethereum/go-ethereum/accounts/abi"
    12  	"github.com/ethereum/go-ethereum/common"
    13  	"github.com/pkg/errors"
    14  
    15  	"github.com/iotexproject/iotex-address/address"
    16  
    17  	"github.com/iotexproject/iotex-core/action"
    18  )
    19  
    20  type (
    21  	// eventParam is a struct to hold smart contract event parameters, which can easily convert a param to go type
    22  	eventParam map[string]any
    23  )
    24  
    25  var (
    26  	errInvlidEventParam = errors.New("invalid event param")
    27  )
    28  
    29  func eventField[T any](e eventParam, name string) (T, error) {
    30  	field, ok := e[name].(T)
    31  	if !ok {
    32  		return field, errors.Wrapf(errInvlidEventParam, "field %s got %#v, expect %T", name, e[name], field)
    33  	}
    34  	return field, nil
    35  }
    36  
    37  func (e eventParam) FieldUint256(name string) (*big.Int, error) {
    38  	return eventField[*big.Int](e, name)
    39  }
    40  
    41  func (e eventParam) FieldBytes12(name string) (string, error) {
    42  	data, err := eventField[[12]byte](e, name)
    43  	if err != nil {
    44  		return "", err
    45  	}
    46  	// remove trailing zeros
    47  	tail := len(data) - 1
    48  	for ; tail >= 0 && data[tail] == 0; tail-- {
    49  	}
    50  	return string(data[:tail+1]), nil
    51  }
    52  
    53  func (e eventParam) FieldUint256Slice(name string) ([]*big.Int, error) {
    54  	return eventField[[]*big.Int](e, name)
    55  }
    56  
    57  func (e eventParam) FieldAddress(name string) (address.Address, error) {
    58  	commAddr, err := eventField[common.Address](e, name)
    59  	if err != nil {
    60  		return nil, err
    61  	}
    62  	return address.FromBytes(commAddr.Bytes())
    63  }
    64  
    65  func (e eventParam) IndexedFieldAddress(name string) (address.Address, error) {
    66  	return e.FieldAddress(name)
    67  }
    68  
    69  func (e eventParam) IndexedFieldUint256(name string) (*big.Int, error) {
    70  	return eventField[*big.Int](e, name)
    71  }
    72  
    73  func unpackEventParam(abiEvent *abi.Event, log *action.Log) (eventParam, error) {
    74  	event := make(eventParam)
    75  	// unpack non-indexed fields
    76  	if len(log.Data) > 0 {
    77  		if err := abiEvent.Inputs.UnpackIntoMap(event, log.Data); err != nil {
    78  			return nil, errors.Wrap(err, "unpack event data failed")
    79  		}
    80  	}
    81  	// unpack indexed fields
    82  	args := make(abi.Arguments, 0)
    83  	for _, arg := range abiEvent.Inputs {
    84  		if arg.Indexed {
    85  			args = append(args, arg)
    86  		}
    87  	}
    88  	topics := make([]common.Hash, 0)
    89  	for i, topic := range log.Topics {
    90  		if i > 0 {
    91  			topics = append(topics, common.Hash(topic))
    92  		}
    93  	}
    94  	err := abi.ParseTopicsIntoMap(event, args, topics)
    95  	if err != nil {
    96  		return nil, errors.Wrap(err, "unpack event indexed fields failed")
    97  	}
    98  	return event, nil
    99  }