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