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