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 }