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

     1  package call
     2  
     3  import (
     4  	"strings"
     5  	"testing"
     6  
     7  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/abi"
     8  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base"
     9  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/parser"
    10  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types"
    11  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/utils"
    12  	ethAbi "github.com/ethereum/go-ethereum/accounts/abi"
    13  )
    14  
    15  var abiSource = `
    16  [
    17    {
    18      "encoding": "0xa175b638",
    19      "inputs": [
    20        {
    21          "name": "_value",
    22          "type": "bool"
    23        }
    24      ],
    25      "name": "setShouldReject",
    26      "outputs": [],
    27      "signature": "setShouldReject(bool)",
    28      "type": "function"
    29    },
    30    {
    31      "constant": true,
    32      "encoding": "0x01ffc9a7",
    33      "inputs": [
    34        {
    35          "name": "interfaceID",
    36          "type": "bytes4"
    37        }
    38      ],
    39      "name": "supportsInterface",
    40      "outputs": [
    41        {
    42          "name": "ret_0",
    43          "type": "bool"
    44        }
    45      ],
    46      "signature": "supportsInterface(bytes4)",
    47      "type": "function"
    48    },
    49    {
    50      "constant": true,
    51      "encoding": "0x0e89341c",
    52      "inputs": [
    53        {
    54          "name": "_id",
    55          "type": "uint256"
    56        }
    57      ],
    58      "name": "uri",
    59      "outputs": [
    60        {
    61          "name": "memory",
    62          "type": "string"
    63        }
    64      ],
    65      "signature": "uri(uint256)",
    66      "type": "function"
    67    }
    68  ]
    69  `
    70  
    71  // This comes from go-ethereum's abi_test.go, we will use it to
    72  // test packing
    73  const packTestAbiSource = `
    74  [
    75  	{ "type" : "function", "name" : ""},
    76  	{ "type" : "function", "name" : "string", "inputs" : [ { "name" : "inputs", "type" : "string" } ] },
    77  	{ "type" : "function", "name" : "bool", "inputs" : [ { "name" : "inputs", "type" : "bool" } ] },
    78  	{ "type" : "function", "name" : "address", "inputs" : [ { "name" : "inputs", "type" : "address" } ] },
    79  	{ "type" : "function", "name" : "uint64", "inputs" : [ { "name" : "inputs", "type" : "uint64" } ] },
    80  	{ "type" : "function", "name" : "uint256", "inputs" : [ { "name" : "inputs", "type" : "uint256" } ] },
    81  	{ "type" : "function", "name" : "int8", "inputs" : [ { "name" : "inputs", "type" : "int8" } ] },
    82  	{ "type" : "function", "name" : "int64", "inputs" : [ { "name" : "inputs", "type" : "int64" } ] },
    83  	{ "type" : "function", "name" : "int256", "inputs" : [ { "name" : "inputs", "type" : "int256" } ] },
    84  	{ "type" : "function", "name" : "bytes4", "inputs" : [ { "name" : "inputs", "type" : "bytes4" } ] },
    85  	{ "type" : "function", "name" : "bytes32", "inputs" : [ { "name" : "inputs", "type" : "bytes32" } ] }
    86  ]`
    87  
    88  var testAbi ethAbi.ABI
    89  var abiMap abi.SelectorSyncMap
    90  var packTestAbi ethAbi.ABI
    91  
    92  func init() {
    93  	var err error
    94  	testAbi, err = ethAbi.JSON(strings.NewReader(abiSource))
    95  	if err != nil {
    96  		panic(err)
    97  	}
    98  
    99  	testHelperAbisFromJson(&testAbi, &abiMap)
   100  
   101  	packTestAbi, err = ethAbi.JSON(strings.NewReader(packTestAbiSource))
   102  	if err != nil {
   103  		panic(err)
   104  	}
   105  }
   106  
   107  func testHelperAbisFromJson(parsedAbi *ethAbi.ABI, abiMap *abi.SelectorSyncMap) {
   108  	for _, method := range parsedAbi.Methods {
   109  		encoding := "0x" + strings.ToLower(base.Bytes2Hex(method.ID))
   110  		abiMap.SetValue(encoding, types.FunctionFromAbiMethod(&method))
   111  	}
   112  }
   113  
   114  func Test_findAbiFunction(t *testing.T) {
   115  	call := &parser.FunctionContractCall{
   116  		Name: "setShouldReject",
   117  		Arguments: []*parser.ContractArgument{
   118  			{
   119  				Boolean: utils.PointerOf(parser.ArgBool(true)),
   120  			},
   121  		},
   122  	}
   123  
   124  	result, hints, err := FindAbiFunction(FindByName, call.Name, call.Arguments, &abiMap)
   125  	if err != nil {
   126  		t.Fatal(err)
   127  	}
   128  	wanted := testAbi.Methods["setShouldReject"]
   129  
   130  	if result.Signature != wanted.Sig {
   131  		t.Fatal("wanted", wanted.Sig, "got", result.Signature)
   132  	}
   133  
   134  	if len(hints) > 0 {
   135  		t.Fatal("expected no hints")
   136  	}
   137  
   138  	// Expect hints
   139  	call = &parser.FunctionContractCall{
   140  		Name:      "setShouldReject",
   141  		Arguments: []*parser.ContractArgument{},
   142  	}
   143  
   144  	result, hints, err = FindAbiFunction(FindByName, call.Name, call.Arguments, &abiMap)
   145  	if err != nil {
   146  		t.Fatal(err)
   147  	}
   148  
   149  	if result != nil {
   150  		t.Fatal("expected no result")
   151  	}
   152  
   153  	if len(hints) != 1 {
   154  		t.Fatal("expected single hint", hints)
   155  	}
   156  
   157  	hint := hints[0]
   158  	if hint != "setShouldReject(bool)" {
   159  		t.Fatal("wrong hint:", hint)
   160  	}
   161  
   162  	// Expect no match
   163  	call = &parser.FunctionContractCall{
   164  		Name:      "somethingElse",
   165  		Arguments: []*parser.ContractArgument{},
   166  	}
   167  
   168  	result, hints, err = FindAbiFunction(FindByName, call.Name, call.Arguments, &abiMap)
   169  	if err != nil {
   170  		t.Fatal(err)
   171  	}
   172  
   173  	if result != nil {
   174  		t.Fatal("expected no result")
   175  	}
   176  
   177  	if len(hints) != 0 {
   178  		t.Fatal("expected no hints")
   179  	}
   180  }
   181  
   182  func Test_findAbiFunctionBySelector(t *testing.T) {
   183  	call := &parser.SelectorContractCall{
   184  		Selector: parser.Selector{
   185  			Value: "0xa175b638",
   186  		},
   187  		Arguments: []*parser.ContractArgument{
   188  			{
   189  				Boolean: utils.PointerOf(parser.ArgBool(true)),
   190  			},
   191  		},
   192  	}
   193  
   194  	result, hints, err := FindAbiFunction(FindBySelector, call.Selector.Value, call.Arguments, &abiMap)
   195  	if err != nil {
   196  		t.Fatal(err)
   197  	}
   198  	wanted := testAbi.Methods["setShouldReject"]
   199  
   200  	if result.Signature != wanted.Sig {
   201  		t.Fatal("wanted", wanted.Sig, "got", result.Signature)
   202  	}
   203  
   204  	if len(hints) > 0 {
   205  		t.Fatal("expected no hints")
   206  	}
   207  
   208  	// Expect hints
   209  	call = &parser.SelectorContractCall{
   210  		Selector: parser.Selector{
   211  			Value: "0xa175b638",
   212  		},
   213  		Arguments: []*parser.ContractArgument{},
   214  	}
   215  
   216  	result, hints, err = FindAbiFunction(FindBySelector, call.Selector.Value, call.Arguments, &abiMap)
   217  	if err != nil {
   218  		t.Fatal(err)
   219  	}
   220  
   221  	if result != nil {
   222  		t.Fatal("expected no result")
   223  	}
   224  
   225  	if len(hints) != 1 {
   226  		t.Fatal("expected single hint", hints)
   227  	}
   228  
   229  	hint := hints[0]
   230  	if hint != "setShouldReject(bool)" {
   231  		t.Fatal("wrong hint:", hint)
   232  	}
   233  
   234  	// Expect no match
   235  	call = &parser.SelectorContractCall{
   236  		Selector: parser.Selector{
   237  			Value: "0xf175b639",
   238  		},
   239  		Arguments: []*parser.ContractArgument{},
   240  	}
   241  
   242  	result, hints, err = FindAbiFunction(FindBySelector, call.Selector.Value, call.Arguments, &abiMap)
   243  	if err != nil {
   244  		t.Fatal(err)
   245  	}
   246  
   247  	if result != nil {
   248  		t.Fatal("expected no result")
   249  	}
   250  
   251  	if len(hints) != 0 {
   252  		t.Fatal("expected no hints")
   253  	}
   254  }
   255  
   256  func Test_findAbiFunctionMisleading(t *testing.T) {
   257  	// This test makes sure we choose the right function
   258  	// when given two very similar ones. In this case, it's
   259  	// transfer(bytes32, address) and transfer(address, address).
   260  	parsedAbi, err := ethAbi.JSON(strings.NewReader(`
   261  		[
   262  			{ "type" : "function", "name" : "transfer", "inputs" : [ { "name" : "from", "type" : "bytes32" }, { "name" : "to", "type" : "address" } ] },
   263  			{ "type" : "function", "name" : "transfer", "inputs" : [ { "name" : "from", "type" : "address" }, { "name" : "to", "type" : "address" } ] }
   264  		]
   265  	`))
   266  	if err != nil {
   267  		t.Fatal(err)
   268  	}
   269  
   270  	testHelperAbisFromJson(&parsedAbi, &abiMap)
   271  
   272  	call := &parser.FunctionContractCall{
   273  		Name: "transfer",
   274  		Arguments: []*parser.ContractArgument{
   275  			{
   276  				Hex: &parser.ArgHex{
   277  					Address: utils.PointerOf(base.HexToAddress("0x6B175474E89094C44Da98b954EedeAC495271d0F")),
   278  				},
   279  			},
   280  			{
   281  				Hex: &parser.ArgHex{
   282  					Address: utils.PointerOf(base.HexToAddress("0x6B175474E89094C44Da98b954EedeAC495271d0F")),
   283  				},
   284  			},
   285  		},
   286  	}
   287  
   288  	result, hints, err := FindAbiFunction(FindByName, call.Name, call.Arguments, &abiMap)
   289  	if err != nil {
   290  		t.Fatal(err)
   291  	}
   292  	wanted := parsedAbi.Methods["transfer0"]
   293  	if result == nil {
   294  		t.Fatal("did not find anything")
   295  	}
   296  	if result.Signature != wanted.Sig {
   297  		t.Fatal("found wrong function:", result.Signature)
   298  	}
   299  	if len(hints) > 0 {
   300  		t.Fatal("expected no hints:", hints)
   301  	}
   302  }