github.com/cgcardona/r-subnet-evm@v0.1.5/accounts/abi/bind/precompilebind/precompile_bind.go (about)

     1  // (c) 2019-2020, Ava Labs, Inc.
     2  //
     3  // This file is a derived work, based on the go-ethereum library whose original
     4  // notices appear below.
     5  //
     6  // It is distributed under a license compatible with the licensing terms of the
     7  // original code from which it is derived.
     8  //
     9  // Much love to the original authors for their work.
    10  // **********
    11  // Copyright 2016 The go-ethereum Authors
    12  // This file is part of the go-ethereum library.
    13  //
    14  // The go-ethereum library is free software: you can redistribute it and/or modify
    15  // it under the terms of the GNU Lesser General Public License as published by
    16  // the Free Software Foundation, either version 3 of the License, or
    17  // (at your option) any later version.
    18  //
    19  // The go-ethereum library is distributed in the hope that it will be useful,
    20  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    21  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    22  // GNU Lesser General Public License for more details.
    23  //
    24  // You should have received a copy of the GNU Lesser General Public License
    25  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    26  
    27  // Package bind generates Ethereum contract Go bindings.
    28  //
    29  // Detailed usage document and tutorial available on the go-ethereum Wiki page:
    30  // https://github.com/ethereum/go-ethereum/wiki/Native-DApps:-Go-bindings-to-Ethereum-contracts
    31  package precompilebind
    32  
    33  import (
    34  	"errors"
    35  	"fmt"
    36  
    37  	"github.com/cgcardona/r-subnet-evm/accounts/abi/bind"
    38  )
    39  
    40  const (
    41  	setAdminFuncKey      = "setAdmin"
    42  	setEnabledFuncKey    = "setEnabled"
    43  	setNoneFuncKey       = "setNone"
    44  	readAllowListFuncKey = "readAllowList"
    45  )
    46  
    47  // BindedFiles contains the generated binding file contents.
    48  // This is used to return the contents in a expandable way.
    49  type BindedFiles struct {
    50  	Contract     string
    51  	Config       string
    52  	Module       string
    53  	ConfigTest   string
    54  	ContractTest string
    55  }
    56  
    57  // PrecompileBind generates a Go binding for a precompiled contract. It returns config binding and contract binding.
    58  func PrecompileBind(types []string, abis []string, bytecodes []string, fsigs []map[string]string, pkg string, lang bind.Lang, libs map[string]string, aliases map[string]string, abifilename string, generateTests bool) (BindedFiles, error) {
    59  	// create hooks
    60  	configHook := createPrecompileHook(abifilename, tmplSourcePrecompileConfigGo)
    61  	contractHook := createPrecompileHook(abifilename, tmplSourcePrecompileContractGo)
    62  	moduleHook := createPrecompileHook(abifilename, tmplSourcePrecompileModuleGo)
    63  	configTestHook := createPrecompileHook(abifilename, tmplSourcePrecompileConfigTestGo)
    64  	contractTestHook := createPrecompileHook(abifilename, tmplSourcePrecompileContractTestGo)
    65  
    66  	configBind, err := bind.BindHelper(types, abis, bytecodes, fsigs, pkg, lang, libs, aliases, configHook)
    67  	if err != nil {
    68  		return BindedFiles{}, fmt.Errorf("failed to generate config binding: %w", err)
    69  	}
    70  	contractBind, err := bind.BindHelper(types, abis, bytecodes, fsigs, pkg, lang, libs, aliases, contractHook)
    71  	if err != nil {
    72  		return BindedFiles{}, fmt.Errorf("failed to generate contract binding: %w", err)
    73  	}
    74  	moduleBind, err := bind.BindHelper(types, abis, bytecodes, fsigs, pkg, lang, libs, aliases, moduleHook)
    75  	if err != nil {
    76  		return BindedFiles{}, fmt.Errorf("failed to generate module binding: %w", err)
    77  	}
    78  	bindedFiles := BindedFiles{
    79  		Contract: contractBind,
    80  		Config:   configBind,
    81  		Module:   moduleBind,
    82  	}
    83  
    84  	if generateTests {
    85  		configTestBind, err := bind.BindHelper(types, abis, bytecodes, fsigs, pkg, lang, libs, aliases, configTestHook)
    86  		if err != nil {
    87  			return BindedFiles{}, fmt.Errorf("failed to generate config test binding: %w", err)
    88  		}
    89  		bindedFiles.ConfigTest = configTestBind
    90  
    91  		contractTestBind, err := bind.BindHelper(types, abis, bytecodes, fsigs, pkg, lang, libs, aliases, contractTestHook)
    92  		if err != nil {
    93  			return BindedFiles{}, fmt.Errorf("failed to generate contract test binding: %w", err)
    94  		}
    95  		bindedFiles.ContractTest = contractTestBind
    96  	}
    97  
    98  	return bindedFiles, nil
    99  }
   100  
   101  // createPrecompileHook creates a bind hook for precompiled contracts.
   102  func createPrecompileHook(abifilename string, template string) bind.BindHook {
   103  	return func(lang bind.Lang, pkg string, types []string, contracts map[string]*bind.TmplContract, structs map[string]*bind.TmplStruct) (interface{}, string, error) {
   104  		// verify first
   105  		if lang != bind.LangGo {
   106  			return nil, "", errors.New("only GoLang binding for precompiled contracts is supported yet")
   107  		}
   108  
   109  		if len(types) != 1 {
   110  			return nil, "", errors.New("cannot generate more than 1 contract")
   111  		}
   112  		funcs := make(map[string]*bind.TmplMethod)
   113  
   114  		contract := contracts[types[0]]
   115  
   116  		for k, v := range contract.Transacts {
   117  			if err := checkOutputName(*v); err != nil {
   118  				return nil, "", err
   119  			}
   120  			funcs[k] = v
   121  		}
   122  
   123  		for k, v := range contract.Calls {
   124  			if err := checkOutputName(*v); err != nil {
   125  				return nil, "", err
   126  			}
   127  			funcs[k] = v
   128  		}
   129  		isAllowList := allowListEnabled(funcs)
   130  		if isAllowList {
   131  			// these functions are not needed for binded contract.
   132  			// AllowList struct can provide the same functionality,
   133  			// so we don't need to generate them.
   134  			delete(funcs, readAllowListFuncKey)
   135  			delete(funcs, setAdminFuncKey)
   136  			delete(funcs, setEnabledFuncKey)
   137  			delete(funcs, setNoneFuncKey)
   138  		}
   139  
   140  		precompileContract := &tmplPrecompileContract{
   141  			TmplContract: contract,
   142  			AllowList:    isAllowList,
   143  			Funcs:        funcs,
   144  			ABIFilename:  abifilename,
   145  		}
   146  
   147  		data := &tmplPrecompileData{
   148  			Contract: precompileContract,
   149  			Structs:  structs,
   150  			Package:  pkg,
   151  		}
   152  		return data, template, nil
   153  	}
   154  }
   155  
   156  func allowListEnabled(funcs map[string]*bind.TmplMethod) bool {
   157  	keys := []string{readAllowListFuncKey, setAdminFuncKey, setEnabledFuncKey, setNoneFuncKey}
   158  	for _, key := range keys {
   159  		if _, ok := funcs[key]; !ok {
   160  			return false
   161  		}
   162  	}
   163  	return true
   164  }
   165  
   166  func checkOutputName(method bind.TmplMethod) error {
   167  	for _, output := range method.Original.Outputs {
   168  		if output.Name == "" {
   169  			return fmt.Errorf("ABI outputs for %s require a name to generate the precompile binding, re-generate the ABI from a Solidity source file with all named outputs", method.Original.Name)
   170  		}
   171  	}
   172  	return nil
   173  }