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 }