github.com/neatio-net/neatio@v1.7.3-0.20231114194659-f4d7a2226baa/chain/accounts/abi/abi.go (about)

     1  package abi
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io"
     8  	"reflect"
     9  
    10  	"github.com/neatio-net/neatio/utilities/common"
    11  	"github.com/neatio-net/neatio/utilities/crypto"
    12  )
    13  
    14  type ABI struct {
    15  	Constructor Method
    16  	Methods     map[string]Method
    17  	Events      map[string]Event
    18  }
    19  
    20  func JSON(reader io.Reader) (ABI, error) {
    21  	dec := json.NewDecoder(reader)
    22  
    23  	var abi ABI
    24  	if err := dec.Decode(&abi); err != nil {
    25  		return ABI{}, err
    26  	}
    27  
    28  	return abi, nil
    29  }
    30  
    31  func (abi ABI) Pack(name string, args ...interface{}) ([]byte, error) {
    32  	if name == "" {
    33  		arguments, err := abi.Constructor.Inputs.Pack(args...)
    34  		if err != nil {
    35  			return nil, err
    36  		}
    37  		return arguments, nil
    38  
    39  	}
    40  	method, exist := abi.Methods[name]
    41  	if !exist {
    42  		return nil, fmt.Errorf("method '%s' not found", name)
    43  	}
    44  
    45  	arguments, err := method.Inputs.Pack(args...)
    46  	if err != nil {
    47  		return nil, err
    48  	}
    49  	return append(method.ID(), arguments...), nil
    50  }
    51  
    52  func (abi ABI) Unpack(v interface{}, name string, data []byte) (err error) {
    53  	if method, ok := abi.Methods[name]; ok {
    54  		if len(data)%32 != 0 {
    55  			return fmt.Errorf("abi: improperly formatted output: %s - Bytes: [%+v]", string(data), data)
    56  		}
    57  		return method.Outputs.Unpack(v, data)
    58  	}
    59  	if event, ok := abi.Events[name]; ok {
    60  		return event.Inputs.Unpack(v, data)
    61  	}
    62  	return fmt.Errorf("abi: could not locate named method or event")
    63  }
    64  
    65  func (abi ABI) UnpackIntoMap(v map[string]interface{}, name string, data []byte) (err error) {
    66  	if method, ok := abi.Methods[name]; ok {
    67  		if len(data)%32 != 0 {
    68  			return fmt.Errorf("abi: improperly formatted output")
    69  		}
    70  		return method.Outputs.UnpackIntoMap(v, data)
    71  	}
    72  	if event, ok := abi.Events[name]; ok {
    73  		return event.Inputs.UnpackIntoMap(v, data)
    74  	}
    75  	return fmt.Errorf("abi: could not locate named method or event")
    76  }
    77  
    78  func (abi ABI) UnpackMethodInputs(v interface{}, name string, input []byte) (err error) {
    79  	if len(input) == 0 {
    80  		return fmt.Errorf("abi: unmarshalling empty output")
    81  	}
    82  	if method, ok := abi.Methods[name]; ok {
    83  		return method.Inputs.Unpack(v, input)
    84  	}
    85  	return fmt.Errorf("abi: could not locate named method or event")
    86  }
    87  
    88  func (abi *ABI) UnmarshalJSON(data []byte) error {
    89  	var fields []struct {
    90  		Type            string
    91  		Name            string
    92  		Constant        bool
    93  		StateMutability string
    94  		Anonymous       bool
    95  		Inputs          []Argument
    96  		Outputs         []Argument
    97  	}
    98  
    99  	if err := json.Unmarshal(data, &fields); err != nil {
   100  		return err
   101  	}
   102  
   103  	abi.Methods = make(map[string]Method)
   104  	abi.Events = make(map[string]Event)
   105  	for _, field := range fields {
   106  		switch field.Type {
   107  		case "constructor":
   108  			abi.Constructor = Method{
   109  				Inputs: field.Inputs,
   110  			}
   111  		case "function", "":
   112  			name := field.Name
   113  			_, ok := abi.Methods[name]
   114  			for idx := 0; ok; idx++ {
   115  				name = fmt.Sprintf("%s%d", field.Name, idx)
   116  				_, ok = abi.Methods[name]
   117  			}
   118  			isConst := field.Constant || field.StateMutability == "pure" || field.StateMutability == "view"
   119  			abi.Methods[name] = Method{
   120  				Name:    name,
   121  				RawName: field.Name,
   122  				Const:   isConst,
   123  				Inputs:  field.Inputs,
   124  				Outputs: field.Outputs,
   125  			}
   126  		case "event":
   127  			name := field.Name
   128  			_, ok := abi.Events[name]
   129  			for idx := 0; ok; idx++ {
   130  				name = fmt.Sprintf("%s%d", field.Name, idx)
   131  				_, ok = abi.Events[name]
   132  			}
   133  			abi.Events[name] = Event{
   134  				Name:      name,
   135  				RawName:   field.Name,
   136  				Anonymous: field.Anonymous,
   137  				Inputs:    field.Inputs,
   138  			}
   139  		}
   140  	}
   141  
   142  	return nil
   143  }
   144  
   145  func (abi *ABI) MethodById(sigdata []byte) (*Method, error) {
   146  	if len(sigdata) < 4 {
   147  		return nil, fmt.Errorf("data too short (%d bytes) for abi method lookup", len(sigdata))
   148  	}
   149  	for _, method := range abi.Methods {
   150  		if bytes.Equal(method.ID(), sigdata[:4]) {
   151  			return &method, nil
   152  		}
   153  	}
   154  	return nil, fmt.Errorf("no method with id: %#x", sigdata[:4])
   155  }
   156  
   157  func (abi *ABI) EventByID(topic common.Hash) (*Event, error) {
   158  	for _, event := range abi.Events {
   159  		if bytes.Equal(event.ID().Bytes(), topic.Bytes()) {
   160  			return &event, nil
   161  		}
   162  	}
   163  	return nil, fmt.Errorf("no event with id: %#x", topic.Hex())
   164  }
   165  
   166  var revertSelector = crypto.Keccak256([]byte("Error(string)"))[:4]
   167  
   168  func UnpackRevert(data []byte) (string, error) {
   169  	if len(data) < 4 {
   170  		return "", fmt.Errorf("invalid data for unpacking")
   171  	}
   172  	if !bytes.Equal(data[:4], revertSelector) {
   173  		return "", fmt.Errorf("invalid data for unpacking")
   174  	}
   175  	typ, _ := NewType("string", "", nil)
   176  	unpacked, err := (Arguments{{Type: typ}}).UnpackForRevert(reflect.New(reflect.TypeOf(typ)).Interface(), data[4:])
   177  	if err != nil {
   178  		return "", err
   179  	}
   180  	return unpacked[0].(string), nil
   181  }