github.com/cryptotooltop/go-ethereum@v0.0.0-20231103184714-151d1922f3e5/cmd/abigen/main.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of go-ethereum. 3 // 4 // go-ethereum is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // go-ethereum is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. 16 17 package main 18 19 import ( 20 "encoding/json" 21 "fmt" 22 "io/ioutil" 23 "os" 24 "path/filepath" 25 "regexp" 26 "strings" 27 28 "gopkg.in/urfave/cli.v1" 29 30 "github.com/scroll-tech/go-ethereum/accounts/abi" 31 "github.com/scroll-tech/go-ethereum/accounts/abi/bind" 32 "github.com/scroll-tech/go-ethereum/cmd/utils" 33 "github.com/scroll-tech/go-ethereum/common/compiler" 34 "github.com/scroll-tech/go-ethereum/crypto" 35 "github.com/scroll-tech/go-ethereum/internal/flags" 36 "github.com/scroll-tech/go-ethereum/log" 37 ) 38 39 var ( 40 // Git SHA1 commit hash of the release (set via linker flags) 41 gitCommit = "" 42 gitDate = "" 43 44 app *cli.App 45 46 // Flags needed by abigen 47 abiFlag = cli.StringFlag{ 48 Name: "abi", 49 Usage: "Path to the Ethereum contract ABI json to bind, - for STDIN", 50 } 51 binFlag = cli.StringFlag{ 52 Name: "bin", 53 Usage: "Path to the Ethereum contract bytecode (generate deploy method)", 54 } 55 typeFlag = cli.StringFlag{ 56 Name: "type", 57 Usage: "Struct name for the binding (default = package name)", 58 } 59 jsonFlag = cli.StringFlag{ 60 Name: "combined-json", 61 Usage: "Path to the combined-json file generated by compiler", 62 } 63 solFlag = cli.StringFlag{ 64 Name: "sol", 65 Usage: "Path to the Ethereum contract Solidity source to build and bind", 66 } 67 solcFlag = cli.StringFlag{ 68 Name: "solc", 69 Usage: "Solidity compiler to use if source builds are requested", 70 Value: "solc", 71 } 72 vyFlag = cli.StringFlag{ 73 Name: "vy", 74 Usage: "Path to the Ethereum contract Vyper source to build and bind", 75 } 76 vyperFlag = cli.StringFlag{ 77 Name: "vyper", 78 Usage: "Vyper compiler to use if source builds are requested", 79 Value: "vyper", 80 } 81 excFlag = cli.StringFlag{ 82 Name: "exc", 83 Usage: "Comma separated types to exclude from binding", 84 } 85 pkgFlag = cli.StringFlag{ 86 Name: "pkg", 87 Usage: "Package name to generate the binding into", 88 } 89 outFlag = cli.StringFlag{ 90 Name: "out", 91 Usage: "Output file for the generated binding (default = stdout)", 92 } 93 langFlag = cli.StringFlag{ 94 Name: "lang", 95 Usage: "Destination language for the bindings (go, java, objc)", 96 Value: "go", 97 } 98 aliasFlag = cli.StringFlag{ 99 Name: "alias", 100 Usage: "Comma separated aliases for function and event renaming, e.g. original1=alias1, original2=alias2", 101 } 102 contractFlag = cli.StringFlag{ 103 Name: "contract", 104 Usage: "Name of the contract to generate the bindings for", 105 } 106 tmplFlag = cli.StringFlag{ 107 Name: "tmpl", 108 Usage: "Template file if a user wants to customize", 109 } 110 ) 111 112 func init() { 113 app = flags.NewApp(gitCommit, gitDate, "ethereum checkpoint helper tool") 114 app.Flags = []cli.Flag{ 115 abiFlag, 116 binFlag, 117 typeFlag, 118 jsonFlag, 119 solFlag, 120 solcFlag, 121 vyFlag, 122 vyperFlag, 123 excFlag, 124 pkgFlag, 125 outFlag, 126 langFlag, 127 aliasFlag, 128 contractFlag, 129 tmplFlag, 130 } 131 app.Action = utils.MigrateFlags(abigen) 132 cli.CommandHelpTemplate = flags.OriginCommandHelpTemplate 133 } 134 135 func abigen(c *cli.Context) error { 136 utils.CheckExclusive(c, abiFlag, jsonFlag, solFlag, vyFlag) // Only one source can be selected. 137 if c.GlobalString(pkgFlag.Name) == "" { 138 utils.Fatalf("No destination package specified (--pkg)") 139 } 140 var lang bind.Lang 141 switch c.GlobalString(langFlag.Name) { 142 case "go": 143 lang = bind.LangGo 144 case "java": 145 lang = bind.LangJava 146 case "objc": 147 lang = bind.LangObjC 148 utils.Fatalf("Objc binding generation is uncompleted") 149 default: 150 utils.Fatalf("Unsupported destination language \"%s\" (--lang)", c.GlobalString(langFlag.Name)) 151 } 152 // If the entire solidity code was specified, build and bind based on that 153 var ( 154 abis []string 155 bins []string 156 types []string 157 sigs []map[string]string 158 libs = make(map[string]string) 159 aliases = make(map[string]string) 160 ) 161 if c.GlobalString(abiFlag.Name) != "" { 162 // Load up the ABI, optional bytecode and type name from the parameters 163 var ( 164 abi []byte 165 err error 166 ) 167 input := c.GlobalString(abiFlag.Name) 168 if input == "-" { 169 abi, err = ioutil.ReadAll(os.Stdin) 170 } else { 171 abi, err = ioutil.ReadFile(input) 172 } 173 if err != nil { 174 utils.Fatalf("Failed to read input ABI: %v", err) 175 } 176 abis = append(abis, string(abi)) 177 178 var bin []byte 179 if binFile := c.GlobalString(binFlag.Name); binFile != "" { 180 if bin, err = ioutil.ReadFile(binFile); err != nil { 181 utils.Fatalf("Failed to read input bytecode: %v", err) 182 } 183 if strings.Contains(string(bin), "//") { 184 utils.Fatalf("Contract has additional library references, please use other mode(e.g. --combined-json) to catch library infos") 185 } 186 } 187 bins = append(bins, string(bin)) 188 189 kind := c.GlobalString(typeFlag.Name) 190 if kind == "" { 191 kind = c.GlobalString(pkgFlag.Name) 192 } 193 types = append(types, kind) 194 } else { 195 // Generate the list of types to exclude from binding 196 exclude := make(map[string]bool) 197 for _, kind := range strings.Split(c.GlobalString(excFlag.Name), ",") { 198 exclude[strings.ToLower(kind)] = true 199 } 200 var err error 201 var contracts map[string]*compiler.Contract 202 203 switch { 204 case c.GlobalIsSet(solFlag.Name): 205 contracts, err = compiler.CompileSolidity(c.GlobalString(solcFlag.Name), c.GlobalString(solFlag.Name)) 206 if err != nil { 207 utils.Fatalf("Failed to build Solidity contract: %v", err) 208 } 209 case c.GlobalIsSet(vyFlag.Name): 210 output, err := compiler.CompileVyper(c.GlobalString(vyperFlag.Name), c.GlobalString(vyFlag.Name)) 211 if err != nil { 212 utils.Fatalf("Failed to build Vyper contract: %v", err) 213 } 214 contracts = make(map[string]*compiler.Contract) 215 for n, contract := range output { 216 name := n 217 // Sanitize the combined json names to match the 218 // format expected by solidity. 219 if !strings.Contains(n, ":") { 220 // Remove extra path components 221 name = abi.ToCamelCase(strings.TrimSuffix(filepath.Base(name), ".vy")) 222 } 223 contracts[name] = contract 224 } 225 226 case c.GlobalIsSet(jsonFlag.Name): 227 jsonOutput, err := ioutil.ReadFile(c.GlobalString(jsonFlag.Name)) 228 if err != nil { 229 utils.Fatalf("Failed to read combined-json from compiler: %v", err) 230 } 231 contracts, err = compiler.ParseCombinedJSON(jsonOutput, "", "", "", "") 232 if err != nil { 233 utils.Fatalf("Failed to read contract information from json output: %v", err) 234 } 235 } 236 // Gather all non-excluded contract for binding 237 for name, contract := range contracts { 238 // The fully qualified name is of the form <solFilePath>:<type> 239 nameParts := strings.Split(name, ":") 240 typeName := nameParts[len(nameParts)-1] 241 // If a contract name is provided then ignore all other contracts 242 if c.GlobalIsSet(contractFlag.Name) && c.GlobalString(contractFlag.Name) != typeName { 243 continue 244 } 245 if exclude[strings.ToLower(name)] { 246 continue 247 } 248 abi, err := json.Marshal(contract.Info.AbiDefinition) // Flatten the compiler parse 249 if err != nil { 250 utils.Fatalf("Failed to parse ABIs from compiler output: %v", err) 251 } 252 abis = append(abis, string(abi)) 253 bins = append(bins, contract.Code) 254 sigs = append(sigs, contract.Hashes) 255 types = append(types, typeName) 256 257 libPattern := crypto.Keccak256Hash([]byte(name)).String()[2:36] 258 libs[libPattern] = typeName 259 } 260 } 261 // Extract all aliases from the flags 262 if c.GlobalIsSet(aliasFlag.Name) { 263 // We support multi-versions for aliasing 264 // e.g. 265 // foo=bar,foo2=bar2 266 // foo:bar,foo2:bar2 267 re := regexp.MustCompile(`(?:(\w+)[:=](\w+))`) 268 submatches := re.FindAllStringSubmatch(c.GlobalString(aliasFlag.Name), -1) 269 for _, match := range submatches { 270 aliases[match[1]] = match[2] 271 } 272 } 273 // Set customize template file. 274 if c.GlobalIsSet(tmplFlag.Name) { 275 tmplFile := c.GlobalString(tmplFlag.Name) 276 data, err := os.ReadFile(tmplFile) 277 if err != nil { 278 utils.Fatalf("Failed to read template file: %v", err) 279 } 280 bind.SetTmplSource(lang, string(data)) 281 } 282 // Generate the contract binding 283 code, err := bind.Bind(types, abis, bins, sigs, c.GlobalString(pkgFlag.Name), lang, libs, aliases) 284 if err != nil { 285 utils.Fatalf("Failed to generate ABI binding: %v", err) 286 } 287 // Either flush it out to a file or display on the standard output 288 if !c.GlobalIsSet(outFlag.Name) { 289 fmt.Printf("%s\n", code) 290 return nil 291 } 292 if err := ioutil.WriteFile(c.GlobalString(outFlag.Name), []byte(code), 0600); err != nil { 293 utils.Fatalf("Failed to write ABI binding: %v", err) 294 } 295 return nil 296 } 297 298 func main() { 299 log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) 300 301 if err := app.Run(os.Args); err != nil { 302 fmt.Fprintln(os.Stderr, err) 303 os.Exit(1) 304 } 305 }