github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/pkg/call/find.go (about)

     1  package call
     2  
     3  import (
     4  	"strings"
     5  
     6  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/abi"
     7  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/parser"
     8  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types"
     9  )
    10  
    11  type findMode int
    12  
    13  const (
    14  	FindByName findMode = iota
    15  	FindBySelector
    16  )
    17  
    18  // FindAbiFunction returns either the function to call or a list of suggestions (function
    19  // signatures with the same name, but different argument count)
    20  func FindAbiFunction(mode findMode, identifier string, arguments []*parser.ContractArgument, abiMap *abi.SelectorSyncMap) (fn *types.Function, suggestions []string, err error) {
    21  	functions := abiMap.Values()
    22  	for _, function := range functions {
    23  		if (mode == FindByName && function.Name != identifier) ||
    24  			(mode == FindBySelector && function.Encoding != strings.ToLower(identifier)) {
    25  			continue
    26  		}
    27  
    28  		// now we will compare arguments
    29  		if arguments != nil {
    30  			// we start with argument count
    31  			if len(function.Inputs) != len(arguments) {
    32  				suggestions = append(suggestions, function.Signature)
    33  				continue
    34  			}
    35  			// now we check if the argument types are compatible
    36  			compatible := false
    37  			for index, input := range function.Inputs {
    38  				argument := arguments[index]
    39  				if input.InternalType == "string" && argument.String == nil {
    40  					break
    41  				}
    42  				if input.InternalType == "bool" && argument.Boolean == nil {
    43  					break
    44  				}
    45  				// address in parsed into argument.Hex.Address
    46  				if input.InternalType == "address" {
    47  					// if both ways of finding an address are empty, break
    48  					if argument.EnsAddr == nil && (argument.Hex == nil || argument.Hex.Address == nil) {
    49  						break
    50  					}
    51  				}
    52  				// bytes32, array and tuples of any kind are only support via
    53  				// hashes. Hashes are parsed into argument.Hex.String
    54  				if input.InternalType == "bytes32" ||
    55  					strings.Contains(input.InternalType, "[") ||
    56  					strings.Contains(input.InternalType, "(") {
    57  					if argument.Hex == nil {
    58  						break
    59  					}
    60  					if argument.Hex.String == nil {
    61  						break
    62  					}
    63  				}
    64  
    65  				// we use strings.Contains here, because all integers are parsed into argument.Number
    66  				if strings.Contains(input.InternalType, "int") && argument.Number == nil {
    67  					break
    68  				}
    69  
    70  				compatible = true
    71  			}
    72  
    73  			if !compatible {
    74  				suggestions = append(suggestions, function.Signature)
    75  				continue
    76  			}
    77  		}
    78  
    79  		return &function, nil, nil
    80  	}
    81  
    82  	return nil, suggestions, nil
    83  }