github.com/dim4egster/coreth@v0.10.2/cmd/abigen/main.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 go-ethereum. 13 // 14 // go-ethereum is free software: you can redistribute it and/or modify 15 // it under the terms of the GNU 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 // go-ethereum 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 General Public License for more details. 23 // 24 // You should have received a copy of the GNU General Public License 25 // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. 26 27 package main 28 29 import ( 30 "encoding/json" 31 "fmt" 32 "io" 33 "os" 34 "regexp" 35 "strings" 36 37 "github.com/dim4egster/coreth/accounts/abi/bind" 38 "github.com/dim4egster/coreth/internal/flags" 39 "github.com/ethereum/go-ethereum/cmd/utils" 40 "github.com/ethereum/go-ethereum/common/compiler" 41 "github.com/ethereum/go-ethereum/crypto" 42 "github.com/ethereum/go-ethereum/log" 43 "github.com/urfave/cli/v2" 44 ) 45 46 var ( 47 // Git SHA1 commit hash of the release (set via linker flags) 48 gitCommit = "" 49 gitDate = "" 50 51 app *cli.App 52 ) 53 54 var ( 55 // Flags needed by abigen 56 abiFlag = &cli.StringFlag{ 57 Name: "abi", 58 Usage: "Path to the Ethereum contract ABI json to bind, - for STDIN", 59 } 60 binFlag = &cli.StringFlag{ 61 Name: "bin", 62 Usage: "Path to the Ethereum contract bytecode (generate deploy method)", 63 } 64 typeFlag = &cli.StringFlag{ 65 Name: "type", 66 Usage: "Struct name for the binding (default = package name)", 67 } 68 jsonFlag = &cli.StringFlag{ 69 Name: "combined-json", 70 Usage: "Path to the combined-json file generated by compiler, - for STDIN", 71 } 72 excFlag = &cli.StringFlag{ 73 Name: "exc", 74 Usage: "Comma separated types to exclude from binding", 75 } 76 pkgFlag = &cli.StringFlag{ 77 Name: "pkg", 78 Usage: "Package name to generate the binding into", 79 } 80 outFlag = &cli.StringFlag{ 81 Name: "out", 82 Usage: "Output file for the generated binding (default = stdout)", 83 } 84 langFlag = &cli.StringFlag{ 85 Name: "lang", 86 Usage: "Destination language for the bindings (go, java, objc)", 87 Value: "go", 88 } 89 aliasFlag = &cli.StringFlag{ 90 Name: "alias", 91 Usage: "Comma separated aliases for function and event renaming, e.g. original1=alias1, original2=alias2", 92 } 93 ) 94 95 func init() { 96 app = flags.NewApp(gitCommit, gitDate, "ethereum checkpoint helper tool") 97 app.Name = "abigen" 98 app.Flags = []cli.Flag{ 99 abiFlag, 100 binFlag, 101 typeFlag, 102 jsonFlag, 103 excFlag, 104 pkgFlag, 105 outFlag, 106 langFlag, 107 aliasFlag, 108 } 109 app.Action = abigen 110 } 111 112 func abigen(c *cli.Context) error { 113 utils.CheckExclusive(c, abiFlag, jsonFlag) // Only one source can be selected. 114 115 if c.String(pkgFlag.Name) == "" { 116 utils.Fatalf("No destination package specified (--pkg)") 117 } 118 var lang bind.Lang 119 switch c.String(langFlag.Name) { 120 case "go": 121 lang = bind.LangGo 122 case "java": 123 lang = bind.LangJava 124 case "objc": 125 lang = bind.LangObjC 126 utils.Fatalf("Objc binding generation is uncompleted") 127 default: 128 utils.Fatalf("Unsupported destination language \"%s\" (--lang)", c.String(langFlag.Name)) 129 } 130 // If the entire solidity code was specified, build and bind based on that 131 var ( 132 abis []string 133 bins []string 134 types []string 135 sigs []map[string]string 136 libs = make(map[string]string) 137 aliases = make(map[string]string) 138 ) 139 if c.String(abiFlag.Name) != "" { 140 // Load up the ABI, optional bytecode and type name from the parameters 141 var ( 142 abi []byte 143 err error 144 ) 145 input := c.String(abiFlag.Name) 146 if input == "-" { 147 abi, err = io.ReadAll(os.Stdin) 148 } else { 149 abi, err = os.ReadFile(input) 150 } 151 if err != nil { 152 utils.Fatalf("Failed to read input ABI: %v", err) 153 } 154 abis = append(abis, string(abi)) 155 156 var bin []byte 157 if binFile := c.String(binFlag.Name); binFile != "" { 158 if bin, err = os.ReadFile(binFile); err != nil { 159 utils.Fatalf("Failed to read input bytecode: %v", err) 160 } 161 if strings.Contains(string(bin), "//") { 162 utils.Fatalf("Contract has additional library references, please use other mode(e.g. --combined-json) to catch library infos") 163 } 164 } 165 bins = append(bins, string(bin)) 166 167 kind := c.String(typeFlag.Name) 168 if kind == "" { 169 kind = c.String(pkgFlag.Name) 170 } 171 types = append(types, kind) 172 } else { 173 // Generate the list of types to exclude from binding 174 exclude := make(map[string]bool) 175 for _, kind := range strings.Split(c.String(excFlag.Name), ",") { 176 exclude[strings.ToLower(kind)] = true 177 } 178 var contracts map[string]*compiler.Contract 179 180 if c.IsSet(jsonFlag.Name) { 181 var ( 182 input = c.String(jsonFlag.Name) 183 jsonOutput []byte 184 err error 185 ) 186 if input == "-" { 187 jsonOutput, err = io.ReadAll(os.Stdin) 188 } else { 189 jsonOutput, err = os.ReadFile(input) 190 } 191 if err != nil { 192 utils.Fatalf("Failed to read combined-json: %v", err) 193 } 194 contracts, err = compiler.ParseCombinedJSON(jsonOutput, "", "", "", "") 195 if err != nil { 196 utils.Fatalf("Failed to read contract information from json output: %v", err) 197 } 198 } 199 // Gather all non-excluded contract for binding 200 for name, contract := range contracts { 201 if exclude[strings.ToLower(name)] { 202 continue 203 } 204 abi, err := json.Marshal(contract.Info.AbiDefinition) // Flatten the compiler parse 205 if err != nil { 206 utils.Fatalf("Failed to parse ABIs from compiler output: %v", err) 207 } 208 abis = append(abis, string(abi)) 209 bins = append(bins, contract.Code) 210 sigs = append(sigs, contract.Hashes) 211 nameParts := strings.Split(name, ":") 212 types = append(types, nameParts[len(nameParts)-1]) 213 214 // Derive the library placeholder which is a 34 character prefix of the 215 // hex encoding of the keccak256 hash of the fully qualified library name. 216 // Note that the fully qualified library name is the path of its source 217 // file and the library name separated by ":". 218 libPattern := crypto.Keccak256Hash([]byte(name)).String()[2:36] // the first 2 chars are 0x 219 libs[libPattern] = nameParts[len(nameParts)-1] 220 } 221 } 222 // Extract all aliases from the flags 223 if c.IsSet(aliasFlag.Name) { 224 // We support multi-versions for aliasing 225 // e.g. 226 // foo=bar,foo2=bar2 227 // foo:bar,foo2:bar2 228 re := regexp.MustCompile(`(?:(\w+)[:=](\w+))`) 229 submatches := re.FindAllStringSubmatch(c.String(aliasFlag.Name), -1) 230 for _, match := range submatches { 231 aliases[match[1]] = match[2] 232 } 233 } 234 // Generate the contract binding 235 code, err := bind.Bind(types, abis, bins, sigs, c.String(pkgFlag.Name), lang, libs, aliases) 236 if err != nil { 237 utils.Fatalf("Failed to generate ABI binding: %v", err) 238 } 239 // Either flush it out to a file or display on the standard output 240 if !c.IsSet(outFlag.Name) { 241 fmt.Printf("%s\n", code) 242 return nil 243 } 244 if err := os.WriteFile(c.String(outFlag.Name), []byte(code), 0600); err != nil { 245 utils.Fatalf("Failed to write ABI binding: %v", err) 246 } 247 return nil 248 } 249 250 func main() { 251 log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) 252 253 if err := app.Run(os.Args); err != nil { 254 fmt.Fprintln(os.Stderr, err) 255 os.Exit(1) 256 } 257 }