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