main.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. // Copyright 2019 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. package main
  17. import (
  18. "encoding/json"
  19. "flag"
  20. "fmt"
  21. "io/ioutil"
  22. "os"
  23. "strings"
  24. "github.com/ethereum/go-ethereum/accounts/abi/bind"
  25. "github.com/ethereum/go-ethereum/common/compiler"
  26. )
  27. var (
  28. abiFlag = flag.String("abi", "", "Path to the Ethereum contract ABI json to bind, - for STDIN")
  29. binFlag = flag.String("bin", "", "Path to the Ethereum contract bytecode (generate deploy method)")
  30. typFlag = flag.String("type", "", "Struct name for the binding (default = package name)")
  31. solFlag = flag.String("sol", "", "Path to the Ethereum contract Solidity source to build and bind")
  32. solcFlag = flag.String("solc", "solc", "Solidity compiler to use if source builds are requested")
  33. excFlag = flag.String("exc", "", "Comma separated types to exclude from binding")
  34. vyFlag = flag.String("vy", "", "Path to the Ethereum contract Vyper source to build and bind")
  35. vyperFlag = flag.String("vyper", "vyper", "Vyper compiler to use if source builds are requested")
  36. pkgFlag = flag.String("pkg", "", "Package name to generate the binding into")
  37. outFlag = flag.String("out", "", "Output file for the generated binding (default = stdout)")
  38. langFlag = flag.String("lang", "go", "Destination language for the bindings (go, java, objc)")
  39. )
  40. func main() {
  41. // Parse and ensure all needed inputs are specified
  42. flag.Parse()
  43. if *abiFlag == "" && *solFlag == "" && *vyFlag == "" {
  44. fmt.Printf("No contract ABI (--abi), Solidity source (--sol), or Vyper source (--vy) specified\n")
  45. os.Exit(-1)
  46. } else if (*abiFlag != "" || *binFlag != "" || *typFlag != "") && (*solFlag != "" || *vyFlag != "") {
  47. fmt.Printf("Contract ABI (--abi), bytecode (--bin) and type (--type) flags are mutually exclusive with the Solidity (--sol) and Vyper (--vy) flags\n")
  48. os.Exit(-1)
  49. } else if *solFlag != "" && *vyFlag != "" {
  50. fmt.Printf("Solidity (--sol) and Vyper (--vy) flags are mutually exclusive\n")
  51. os.Exit(-1)
  52. }
  53. if *pkgFlag == "" {
  54. fmt.Printf("No destination package specified (--pkg)\n")
  55. os.Exit(-1)
  56. }
  57. var lang bind.Lang
  58. switch *langFlag {
  59. case "go":
  60. lang = bind.LangGo
  61. case "java":
  62. lang = bind.LangJava
  63. default:
  64. fmt.Printf("Unsupported destination language \"%s\" (--lang)\n", *langFlag)
  65. os.Exit(-1)
  66. }
  67. // If the entire solidity code was specified, build and bind based on that
  68. var (
  69. abis []string
  70. bins []string
  71. types []string
  72. )
  73. if *solFlag != "" || *vyFlag != "" || *abiFlag == "-" {
  74. // Generate the list of types to exclude from binding
  75. exclude := make(map[string]bool)
  76. for _, kind := range strings.Split(*excFlag, ",") {
  77. exclude[strings.ToLower(kind)] = true
  78. }
  79. var contracts map[string]*compiler.Contract
  80. var err error
  81. switch {
  82. case *solFlag != "":
  83. contracts, err = compiler.CompileSolidity(*solcFlag, *solFlag)
  84. if err != nil {
  85. fmt.Printf("Failed to build Solidity contract: %v\n", err)
  86. os.Exit(-1)
  87. }
  88. case *vyFlag != "":
  89. contracts, err = compiler.CompileVyper(*vyperFlag, *vyFlag)
  90. if err != nil {
  91. fmt.Printf("Failed to build Vyper contract: %v\n", err)
  92. os.Exit(-1)
  93. }
  94. default:
  95. contracts, err = contractsFromStdin()
  96. if err != nil {
  97. fmt.Printf("Failed to read input ABIs from STDIN: %v\n", err)
  98. os.Exit(-1)
  99. }
  100. }
  101. // Gather all non-excluded contract for binding
  102. for name, contract := range contracts {
  103. if exclude[strings.ToLower(name)] {
  104. continue
  105. }
  106. abi, err := json.Marshal(contract.Info.AbiDefinition) // Flatten the compiler parse
  107. if err != nil {
  108. fmt.Printf("Failed to parse ABIs from compiler output: %v\n", err)
  109. os.Exit(-1)
  110. }
  111. abis = append(abis, string(abi))
  112. bins = append(bins, contract.Code)
  113. nameParts := strings.Split(name, ":")
  114. types = append(types, nameParts[len(nameParts)-1])
  115. }
  116. } else {
  117. // Otherwise load up the ABI, optional bytecode and type name from the parameters
  118. abi, err := ioutil.ReadFile(*abiFlag)
  119. if err != nil {
  120. fmt.Printf("Failed to read input ABI: %v\n", err)
  121. os.Exit(-1)
  122. }
  123. abis = append(abis, string(abi))
  124. var bin []byte
  125. if *binFlag != "" {
  126. if bin, err = ioutil.ReadFile(*binFlag); err != nil {
  127. fmt.Printf("Failed to read input bytecode: %v\n", err)
  128. os.Exit(-1)
  129. }
  130. }
  131. bins = append(bins, string(bin))
  132. kind := *typFlag
  133. if kind == "" {
  134. kind = *pkgFlag
  135. }
  136. types = append(types, kind)
  137. }
  138. // Generate the contract binding
  139. code, err := bind.Bind(types, abis, bins, *pkgFlag, lang)
  140. if err != nil {
  141. fmt.Printf("Failed to generate ABI binding: %v\n", err)
  142. os.Exit(-1)
  143. }
  144. // Either flush it out to a file or display on the standard output
  145. if *outFlag == "" {
  146. fmt.Printf("%s\n", code)
  147. return
  148. }
  149. if err := ioutil.WriteFile(*outFlag, []byte(code), 0600); err != nil {
  150. fmt.Printf("Failed to write ABI binding: %v\n", err)
  151. os.Exit(-1)
  152. }
  153. }
  154. func contractsFromStdin() (map[string]*compiler.Contract, error) {
  155. bytes, err := ioutil.ReadAll(os.Stdin)
  156. if err != nil {
  157. return nil, err
  158. }
  159. return compiler.ParseCombinedJSON(bytes, "", "", "", "")
  160. }