# #37359 \[BC-Insight] Failure to Generate ABI Binding in Golang

**Submitted on Dec 2nd 2024 at 20:36:56 UTC by @CertiK for** [**Attackathon | Ethereum Protocol**](https://immunefi.com/audit-competition/ethereum-protocol-attackathon)

* **Report ID:** #37359
* **Report Type:** Blockchain/DLT
* **Report severity:** Insight
* **Target:** <https://github.com/ledgerwatch/erigon>
* **Impacts:**
  * (Specifications) A bug in specifications with no direct impact on client implementations

## Description

## Brief/Intro

Abigen fails to generate ABI binding of Solidity code in the accounts/abi package when the keyword of Golang is passed as the inputs of the binding.

## Vulnerability Details

Affected Codebase:\
<https://github.com/erigontech/erigon/tree/v2.61.0-beta1>

The Ethereum client Erigon (<https://github.com/erigontech/erigon>) provides the Abigen tool to generate the Golang wrapper around a Solidity contract ABI:

<https://github.com/erigontech/erigon/blob/v2.61.0-beta1/accounts/abi/bind/bind.go#L60>

```
func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]string, pkg string, lang Lang, libs map[string]string, aliases map[string]string) (string, error) {
	var (
		// contracts is the map of each individual contract requested binding
		contracts = make(map[string]*tmplContract)


		// structs is the map of all redeclared structs shared by passed contracts.
		structs = make(map[string]*tmplStruct)


		// isLib is the map used to flag each encountered library as such
		isLib = make(map[string]struct{})
	)
	for i := 0; i < len(types); i++ {
		// Parse the actual ABI to generate the binding for
		evmABI, err := abi.JSON(strings.NewReader(abis[i]))
		if err != nil {
			return "", err
		}
		// Strip any whitespace from the JSON ABI
		strippedABI := strings.Map(func(r rune) rune {
			if unicode.IsSpace(r) {
				return -1
			}
			return r
		}, abis[i])


		// Extract the call and transact methods; events, struct definitions; and sort them alphabetically
		var (
			calls     = make(map[string]*tmplMethod)
			transacts = make(map[string]*tmplMethod)
			events    = make(map[string]*tmplEvent)
			fallback  *tmplMethod
			receive   *tmplMethod


			// identifiers are used to detect duplicated identifiers of functions
			// and events. For all calls, transacts and events, abigen will generate
			// corresponding bindings. However we have to ensure there is no
			// identifier collisions in the bindings of these categories.
			callIdentifiers     = make(map[string]bool)
			transactIdentifiers = make(map[string]bool)
			eventIdentifiers    = make(map[string]bool)
		)
		for _, original := range evmABI.Methods {
			// Normalize the method for capital cases and non-anonymous inputs/outputs
			normalized := original
			normalizedName := methodNormalizer[lang](alias(aliases, original.Name))
			// Ensure there is no duplicated identifier
			var identifiers = callIdentifiers
			if !original.IsConstant() {
				identifiers = transactIdentifiers
			}
			if identifiers[normalizedName] {
				return "", fmt.Errorf("duplicated identifier \"%s\"(normalized \"%s\"), use --alias for renaming", original.Name, normalizedName)
			}
			identifiers[normalizedName] = true
			normalized.Name = normalizedName
			normalized.Inputs = make([]abi.Argument, len(original.Inputs))
			copy(normalized.Inputs, original.Inputs)
			for j, input := range normalized.Inputs {
				if input.Name == "" {
					normalized.Inputs[j].Name = fmt.Sprintf("arg%d", j)
				}
				if hasStruct(input.Type) {
					bindStructType[lang](input.Type, structs)
				}
			}
			normalized.Outputs = make([]abi.Argument, len(original.Outputs))
			copy(normalized.Outputs, original.Outputs)
			for j, output := range normalized.Outputs {
				if output.Name != "" {
					normalized.Outputs[j].Name = capitalise(output.Name)
				}
				if hasStruct(output.Type) {
					bindStructType[lang](output.Type, structs)
				}
			}
			// Append the methods to the call or transact lists
			if original.IsConstant() {
				calls[original.Name] = &tmplMethod{Original: original, Normalized: normalized, Structured: structured(original.Outputs)}
			} else {
				transacts[original.Name] = &tmplMethod{Original: original, Normalized: normalized, Structured: structured(original.Outputs)}
			}
		}
		for _, original := range evmABI.Events {
			// Skip anonymous events as they don't support explicit filtering
			if original.Anonymous {
				continue
			}
			// Normalize the event for capital cases and non-anonymous outputs
			normalized := original


			// Ensure there is no duplicated identifier
			normalizedName := methodNormalizer[lang](alias(aliases, original.Name))
			if eventIdentifiers[normalizedName] {
				return "", fmt.Errorf("duplicated identifier \"%s\"(normalized \"%s\"), use --alias for renaming", original.Name, normalizedName)
			}
			eventIdentifiers[normalizedName] = true
			normalized.Name = normalizedName


			normalized.Inputs = make([]abi.Argument, len(original.Inputs))
			copy(normalized.Inputs, original.Inputs)
			for j, input := range normalized.Inputs {
				if input.Name == "" {
					normalized.Inputs[j].Name = fmt.Sprintf("arg%d", j)
				}
				if hasStruct(input.Type) {
					bindStructType[lang](input.Type, structs)
				}
			}
			// Append the event to the accumulator list
			events[original.Name] = &tmplEvent{Original: original, Normalized: normalized}
		}
		// Add two special fallback functions if they exist
		if evmABI.HasFallback() {
			fallback = &tmplMethod{Original: evmABI.Fallback}
		}
		if evmABI.HasReceive() {
			receive = &tmplMethod{Original: evmABI.Receive}
		}
		// There is no easy way to pass arbitrary java objects to the Go side.
		if len(structs) > 0 && lang == LangJava {
			return "", errors.New("java binding for tuple arguments is not supported yet")
		}


		contracts[types[i]] = &tmplContract{
			Type:        capitalise(types[i]),
			InputABI:    strings.ReplaceAll(strippedABI, "\"", "\\\""),
			InputBin:    strings.TrimPrefix(strings.TrimSpace(bytecodes[i]), "0x"),
			Constructor: evmABI.Constructor,
			Calls:       calls,
			Transacts:   transacts,
			Fallback:    fallback,
			Receive:     receive,
			Events:      events,
			Libraries:   make(map[string]string),
		}
		// Function 4-byte signatures are stored in the same sequence
		// as types, if available.
		if len(fsigs) > i {
			contracts[types[i]].FuncSigs = fsigs[i]
		}
		// Parse library references.
		for pattern, name := range libs {
			matched, err := regexp.Match("__\\$"+pattern+"\\$__", []byte(contracts[types[i]].InputBin))
			if err != nil {
				log.Error("Could not search for pattern", "pattern", pattern, "contract", contracts[types[i]], "err", err)
			}
			if matched {
				contracts[types[i]].Libraries[pattern] = name
				// keep track that this type is a library
				if _, ok := isLib[name]; !ok {
					isLib[name] = struct{}{}
				}
			}
		}
	}
	// Check if that type has already been identified as a library
	for i := 0; i < len(types); i++ {
		_, ok := isLib[types[i]]
		contracts[types[i]].Library = ok
	}
	// Generate the contract template data content and render it
	data := &tmplData{
		Package:   pkg,
		Contracts: contracts,
		Libraries: libs,
		Structs:   structs,
	}
	buffer := new(bytes.Buffer)


	funcs := map[string]interface{}{
		"bindtype":      bindType[lang],
		"bindtopictype": bindTopicType[lang],
		"namedtype":     namedType[lang],
		"capitalise":    capitalise,
		"decapitalise":  decapitalise,
	}
	tmpl := template.Must(template.New("").Funcs(funcs).Parse(tmplSource[lang]))
	if err := tmpl.Execute(buffer, data); err != nil {
		return "", err
	}
	// For Go bindings pass the code through gofmt to clean it up
	if lang == LangGo {
		code, err := format.Source(buffer.Bytes())
		if err != nil {
			return "", fmt.Errorf("%w\n%s", err, buffer)
		}
		return string(code), nil
	}
	// For all others just return as is for now
	return buffer.String(), nil
}
```

However, in case that the Golang keyword is passed in as the function parameter names, the ABI wrapper generation fails.

This issue of Abigen has been reported in the Go-ethereum: <https://github.com/ethereum/go-ethereum/issues/25252>

And it has been patched in the PR:\
<https://github.com/ethereum/go-ethereum/pull/25307>

## Impact Details

The tool Abigen fails in case that the Golang keywords are passed as the function parameter names.

## References

* <https://github.com/erigontech/erigon/tree/v2.61.0-beta1>
* <https://github.com/ethereum/go-ethereum/issues/25252>
* <https://github.com/ethereum/go-ethereum/pull/25307>

## Proof of Concept

## Proof of Concept

For simplicity, we can reuse and modify the test case from go-ethereum (<https://github.com/ethereum/go-ethereum/pull/25307> ) to verify the issue:

```
 // Test Golang Keyword conflict, for example, range keword
   {
      `RangeKeyword`,
      `
      // SPDX-License-Identifier: GPL-3.0
      pragma solidity >=0.4.22 <0.9.0;
      contract keywordcontract {
         function functionWithKeywordParameter(range uint256) public pure {}
      }
      `,
      []string{"0x608060405234801561001057600080fd5b5060dc8061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063527a119f14602d575b600080fd5b60436004803603810190603f9190605b565b6045565b005b50565b6000813590506055816092565b92915050565b600060208284031215606e57606d608d565b5b6000607a848285016048565b91505092915050565b6000819050919050565b600080fd5b6099816083565b811460a357600080fd5b5056fea2646970667358221220d4f4525e2615516394055d369fb17df41c359e5e962734f27fd683ea81fd9db164736f6c63430008070033"},
      []string{`[{"inputs":[{"internalType":"uint256","name":"range","type":"uint256"}],"name":"functionWithKeywordParameter","outputs":[],"stateMutability":"pure","type":"function"}]`},
      `
         "context"
         "math/big"


         "github.com/ledgerwatch/erigon/accounts/abi/bind"
         "github.com/ledgerwatch/erigon/accounts/abi/bind/backends"
         "github.com/ledgerwatch/erigon/types"
         "github.com/ledgerwatch/erigon/crypto"
         "github.com/ledgerwatch/erigon/eth/ethconfig"
      `,
      `
var (
            key, _  = crypto.GenerateKey()
            user, _ = bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
            sim     = backends.NewSimulatedBackend(core.GenesisAlloc{user.From: {Balance: big.NewInt(1000000000000000000)}}, ethconfig.Defaults.Miner.GasCeil)
         )
         _, tx, _, err := DeployRangeKeyword(user, sim)
         if err != nil {
            t.Fatalf("error deploying contract: %v", err)
         }
         sim.Commit()
         if _, err = bind.WaitDeployed(nil, sim, tx); err != nil {
            t.Errorf("error deploying the contract: %v", err)
         }
   `,
      nil,
      nil,
      nil,
      nil,
   }
```

Run the following unit test:

```
// Tests that packages generated by the binder can be successfully compiled and
// the requested tester run against it.
func TestGolangBindings(t *testing.T) {
   // Skip the test if no Go command can be found
   //gocmd := "go"
   gocmd := runtime.GOROOT() + "/bin/go"
   if !dir.FileExist(gocmd) {
      t.Skip("go sdk not found for testing")
   }
   // Create a temporary workspace for the test suite
   ws := t.TempDir()


   pkg := filepath.Join(ws, "bindtest")
   if err := os.MkdirAll(pkg, 0700); err != nil {
      t.Fatalf("failed to create package: %v", err)
   }
   // Generate the test suite for all the contracts
   for i, tt := range bindTests {
      var types []string
      if tt.types != nil {
         types = tt.types
      } else {
         types = []string{tt.name}
      }
      // Generate the binding and create a Go source file in the workspace
      bind, err := Bind(types, tt.abi, tt.bytecode, tt.fsigs, "bindtest", LangGo, tt.libs, tt.aliases)
      if err != nil {
         t.Fatalf("test %d: failed to generate binding: %v", i, err)
      }
      if err = os.WriteFile(filepath.Join(pkg, strings.ToLower(tt.name)+".go"), []byte(bind), 0600); err != nil {
         t.Fatalf("test %d: failed to write binding: %v", i, err)
      }
      // Generate the test file with the injected test code
      code := fmt.Sprintf(`
         package bindtest


         import (
            "testing"
            %s
         )


         func Test%s(t *testing.T) {
            %s
         }
      `, tt.imports, tt.name, tt.tester)
      if err := os.WriteFile(filepath.Join(pkg, strings.ToLower(tt.name)+"_test.go"), []byte(code), 0600); err != nil {
         t.Fatalf("test %d: failed to write tests: %v", i, err)
      }
   }
   // Convert the package to go modules and use the current source for go-ethereum
   moder := exec.Command(gocmd, "mod", "init", "bindtest")
   moder.Dir = pkg
   if out, err := moder.CombinedOutput(); err != nil {
      t.Fatalf("failed to convert binding test to modules: %v\n%s", err, out)
   }
   pwd, _ := os.Getwd()
   replacer := exec.Command(gocmd, "mod", "edit", "-replace", "github.com/ledgerwatch/erigon="+filepath.Join(pwd, "..", "..", "..")) // Repo root
   replacer.Dir = pkg
   if out, err := replacer.CombinedOutput(); err != nil {
      t.Fatalf("failed to replace binding test dependency to current source tree: %v\n%s", err, out)
   }


   tidier := exec.Command(gocmd, "mod", "tidy")
   tidier.Dir = pkg
   if out, err := tidier.CombinedOutput(); err != nil {
      t.Fatalf("failed to tidy Go module file: %v\n%s", err, out)
   }
   //Test the entire package and report any failures
   cmd := exec.Command(gocmd, "test", "-v", "-count", "1")
   cmd.Dir = pkg
   if out, err := cmd.CombinedOutput(); err != nil {
      t.Fatalf("failed to run binding test: %v\n%s", err, out)
   }
}
```

The test result shows the Abigen fails due to the `range` keyword conflict:

```
=== RUN   TestGolangBindings
    bind_test.go:1859: test 28: failed to generate binding: 208:95: expected ')', found 'range' (and 9 more errors)
        
        // Code generated by abigen. DO NOT EDIT.
        // This file is a generated binding and any manual changes will be lost.
        
        package bindtest
        
        import (
        	"math/big"
        	"strings"
        	"fmt"
        	"reflect"
        
        	ethereum "github.com/ledgerwatch/erigon"
        	"github.com/ledgerwatch/erigon/accounts/abi"
        	"github.com/ledgerwatch/erigon/accounts/abi/bind"
        	libcommon "github.com/ledgerwatch/erigon-lib/common"
        	"github.com/ledgerwatch/erigon/core/types"
        	"github.com/ledgerwatch/erigon/event"
        )
        
        // Reference imports to suppress errors if they are not otherwise used.
        var (
        	_ = big.NewInt
        	_ = strings.NewReader
        	_ = ethereum.NotFound
        	_ = bind.Bind
        	_ = libcommon.Big1
        	_ = types.BloomLookup
        	_ = event.NewSubscription
        	_ = fmt.Errorf
        	_ = reflect.ValueOf
        )
        
        
        
        
        
        	// RangeKeywordABI is the input ABI used to generate the binding from.
        	const RangeKeywordABI = "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"range\",\"type\":\"uint256\"}],\"name\":\"functionWithKeywordParameter\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"}]"
        
        	
        
        	
        		// RangeKeywordBin is the compiled bytecode used for deploying new contracts.
        		var RangeKeywordBin = "0x608060405234801561001057600080fd5b5060dc8061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063527a119f14602d575b600080fd5b60436004803603810190603f9190605b565b6045565b005b50565b6000813590506055816092565b92915050565b600060208284031215606e57606d608d565b5b6000607a848285016048565b91505092915050565b6000819050919050565b600080fd5b6099816083565b811460a357600080fd5b5056fea2646970667358221220d4f4525e2615516394055d369fb17df41c359e5e962734f27fd683ea81fd9db164736f6c63430008070033"
        
        		// DeployRangeKeyword deploys a new Ethereum contract, binding an instance of RangeKeyword to it.
        		func DeployRangeKeyword(auth *bind.TransactOpts, backend bind.ContractBackend ) (libcommon.Address, types.Transaction, *RangeKeyword, error) {
        		  parsed, err := abi.JSON(strings.NewReader(RangeKeywordABI))
        		  if err != nil {
        		    return libcommon.Address{}, nil, nil, err
        		  }
        		  
        		  address, tx, contract, err := bind.DeployContract(auth, parsed, libcommon.FromHex(RangeKeywordBin), backend )
        		  if err != nil {
        		    return libcommon.Address{}, nil, nil, err
        		  }
        		  return address, tx, &RangeKeyword{ RangeKeywordCaller: RangeKeywordCaller{contract: contract}, RangeKeywordTransactor: RangeKeywordTransactor{contract: contract}, RangeKeywordFilterer: RangeKeywordFilterer{contract: contract} }, nil
        		}
        	
        
        	// RangeKeyword is an auto generated Go binding around an Ethereum contract.
        	type RangeKeyword struct {
        	  RangeKeywordCaller     // Read-only binding to the contract
        	  RangeKeywordTransactor // Write-only binding to the contract
        	  RangeKeywordFilterer   // Log filterer for contract events
        	}
        
        	// RangeKeywordCaller is an auto generated read-only Go binding around an Ethereum contract.
        	type RangeKeywordCaller struct {
        	  contract *bind.BoundContract // Generic contract wrapper for the low level calls
        	}
        
        	// RangeKeywordTransactor is an auto generated write-only Go binding around an Ethereum contract.
        	type RangeKeywordTransactor struct {
        	  contract *bind.BoundContract // Generic contract wrapper for the low level calls
        	}
        
        	// RangeKeywordFilterer is an auto generated log filtering Go binding around an Ethereum contract events.
        	type RangeKeywordFilterer struct {
        	  contract *bind.BoundContract // Generic contract wrapper for the low level calls
        	}
        
        	// RangeKeywordSession is an auto generated Go binding around an Ethereum contract,
        	// with pre-set call and transact options.
        	type RangeKeywordSession struct {
        	  Contract     *RangeKeyword        // Generic contract binding to set the session for
        	  CallOpts     bind.CallOpts     // Call options to use throughout this session
        	  TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
        	}
        
        	// RangeKeywordCallerSession is an auto generated read-only Go binding around an Ethereum contract,
        	// with pre-set call options.
        	type RangeKeywordCallerSession struct {
        	  Contract *RangeKeywordCaller // Generic contract caller binding to set the session for
        	  CallOpts bind.CallOpts    // Call options to use throughout this session
        	}
        
        	// RangeKeywordTransactorSession is an auto generated write-only Go binding around an Ethereum contract,
        	// with pre-set transact options.
        	type RangeKeywordTransactorSession struct {
        	  Contract     *RangeKeywordTransactor // Generic contract transactor binding to set the session for
        	  TransactOpts bind.TransactOpts    // Transaction auth options to use throughout this session
        	}
        
        	// RangeKeywordRaw is an auto generated low-level Go binding around an Ethereum contract.
        	type RangeKeywordRaw struct {
        	  Contract *RangeKeyword // Generic contract binding to access the raw methods on
        	}
        
        	// RangeKeywordCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
        	type RangeKeywordCallerRaw struct {
        		Contract *RangeKeywordCaller // Generic read-only contract binding to access the raw methods on
        	}
        
        	// RangeKeywordTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
        	type RangeKeywordTransactorRaw struct {
        		Contract *RangeKeywordTransactor // Generic write-only contract binding to access the raw methods on
        	}
        
        	// NewRangeKeyword creates a new instance of RangeKeyword, bound to a specific deployed contract.
        	func NewRangeKeyword(address libcommon.Address, backend bind.ContractBackend) (*RangeKeyword, error) {
        	  contract, err := bindRangeKeyword(address, backend, backend, backend)
        	  if err != nil {
        	    return nil, err
        	  }
        	  return &RangeKeyword{ RangeKeywordCaller: RangeKeywordCaller{contract: contract}, RangeKeywordTransactor: RangeKeywordTransactor{contract: contract}, RangeKeywordFilterer: RangeKeywordFilterer{contract: contract} }, nil
        	}
        
        	// NewRangeKeywordCaller creates a new read-only instance of RangeKeyword, bound to a specific deployed contract.
        	func NewRangeKeywordCaller(address libcommon.Address, caller bind.ContractCaller) (*RangeKeywordCaller, error) {
        	  contract, err := bindRangeKeyword(address, caller, nil, nil)
        	  if err != nil {
        	    return nil, err
        	  }
        	  return &RangeKeywordCaller{contract: contract}, nil
        	}
        
        	// NewRangeKeywordTransactor creates a new write-only instance of RangeKeyword, bound to a specific deployed contract.
        	func NewRangeKeywordTransactor(address libcommon.Address, transactor bind.ContractTransactor) (*RangeKeywordTransactor, error) {
        	  contract, err := bindRangeKeyword(address, nil, transactor, nil)
        	  if err != nil {
        	    return nil, err
        	  }
        	  return &RangeKeywordTransactor{contract: contract}, nil
        	}
        
        	// NewRangeKeywordFilterer creates a new log filterer instance of RangeKeyword, bound to a specific deployed contract.
         	func NewRangeKeywordFilterer(address libcommon.Address, filterer bind.ContractFilterer) (*RangeKeywordFilterer, error) {
         	  contract, err := bindRangeKeyword(address, nil, nil, filterer)
         	  if err != nil {
         	    return nil, err
         	  }
         	  return &RangeKeywordFilterer{contract: contract}, nil
         	}
        
        	// bindRangeKeyword binds a generic wrapper to an already deployed contract.
        	func bindRangeKeyword(address libcommon.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
        	  parsed, err := abi.JSON(strings.NewReader(RangeKeywordABI))
        	  if err != nil {
        	    return nil, err
        	  }
        	  return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil
        	}
        
        	// Call invokes the (constant) contract method with params as input values and
        	// sets the output to result. The result type might be a single field for simple
        	// returns, a slice of interfaces for anonymous returns and a struct for named
        	// returns.
        	func (_RangeKeyword *RangeKeywordRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
        		return _RangeKeyword.Contract.RangeKeywordCaller.contract.Call(opts, result, method, params...)
        	}
        
        	// Transfer initiates a plain transaction to move funds to the contract, calling
        	// its default method if one is available.
        	func (_RangeKeyword *RangeKeywordRaw) Transfer(opts *bind.TransactOpts) (types.Transaction, error) {
        		return _RangeKeyword.Contract.RangeKeywordTransactor.contract.Transfer(opts)
        	}
        
        	// Transact invokes the (paid) contract method with params as input values.
        	func (_RangeKeyword *RangeKeywordRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (types.Transaction, error) {
        		return _RangeKeyword.Contract.RangeKeywordTransactor.contract.Transact(opts, method, params...)
        	}
        
        	// Call invokes the (constant) contract method with params as input values and
        	// sets the output to result. The result type might be a single field for simple
        	// returns, a slice of interfaces for anonymous returns and a struct for named
        	// returns.
        	func (_RangeKeyword *RangeKeywordCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
        		return _RangeKeyword.Contract.contract.Call(opts, result, method, params...)
        	}
        
        	// Transfer initiates a plain transaction to move funds to the contract, calling
        	// its default method if one is available.
        	func (_RangeKeyword *RangeKeywordTransactorRaw) Transfer(opts *bind.TransactOpts) (types.Transaction, error) {
        		return _RangeKeyword.Contract.contract.Transfer(opts)
        	}
        
        	// Transact invokes the (paid) contract method with params as input values.
        	func (_RangeKeyword *RangeKeywordTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (types.Transaction, error) {
        		return _RangeKeyword.Contract.contract.Transact(opts, method, params...)
        	}
        
        	
        		// FunctionWithKeywordParameter is a free data retrieval call binding the contract method 0x527a119f.
        		//
        		// Solidity: function functionWithKeywordParameter(uint256 range) pure returns()
        		func (_RangeKeyword *RangeKeywordCaller) FunctionWithKeywordParameter(opts *bind.CallOpts , range *big.Int ) ( error) {
        			var out []interface{}
        			err := _RangeKeyword.contract.Call(opts, &out, "functionWithKeywordParameter" , range)
        			
        			if err != nil {
        				return  err
        			}
        			
        			
        			return  err
        			
        		}
        
        		// FunctionWithKeywordParameter is a free data retrieval call binding the contract method 0x527a119f.
        		//
        		// Solidity: function functionWithKeywordParameter(uint256 range) pure returns()
        		func (_RangeKeyword *RangeKeywordSession) FunctionWithKeywordParameter( range *big.Int ) (   error) {
        		  return _RangeKeyword.Contract.FunctionWithKeywordParameter(&_RangeKeyword.CallOpts , range)
        		}
        
        		// FunctionWithKeywordParameter is a free data retrieval call binding the contract method 0x527a119f.
        		//
        		// Solidity: function functionWithKeywordParameter(uint256 range) pure returns()
        		func (_RangeKeyword *RangeKeywordCallerSession) FunctionWithKeywordParameter( range *big.Int ) (   error) {
        		  return _RangeKeyword.Contract.FunctionWithKeywordParameter(&_RangeKeyword.CallOpts , range)
        		}




        
--- FAIL: TestGolangBindings (0.15s)


FAIL
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://reports.immunefi.com/ethereum-protocol-or-attackathon/37359-bc-insight-failure-to-generate-abi-binding-in-golang.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
