|
|
|
@ -18,63 +18,129 @@ package main |
|
|
|
|
|
|
|
|
|
import ( |
|
|
|
|
"encoding/json" |
|
|
|
|
"flag" |
|
|
|
|
"fmt" |
|
|
|
|
"io/ioutil" |
|
|
|
|
"os" |
|
|
|
|
"strings" |
|
|
|
|
|
|
|
|
|
"github.com/ethereum/go-ethereum/accounts/abi/bind" |
|
|
|
|
"github.com/ethereum/go-ethereum/cmd/utils" |
|
|
|
|
"github.com/ethereum/go-ethereum/common/compiler" |
|
|
|
|
"github.com/ethereum/go-ethereum/crypto" |
|
|
|
|
"github.com/ethereum/go-ethereum/log" |
|
|
|
|
"gopkg.in/urfave/cli.v1" |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
|
abiFlag = flag.String("abi", "", "Path to the Ethereum contract ABI json to bind, - for STDIN") |
|
|
|
|
binFlag = flag.String("bin", "", "Path to the Ethereum contract bytecode (generate deploy method)") |
|
|
|
|
typFlag = flag.String("type", "", "Struct name for the binding (default = package name)") |
|
|
|
|
const ( |
|
|
|
|
commandHelperTemplate = `{{.Name}}{{if .Subcommands}} command{{end}}{{if .Flags}} [command options]{{end}} [arguments...] |
|
|
|
|
{{if .Description}}{{.Description}} |
|
|
|
|
{{end}}{{if .Subcommands}} |
|
|
|
|
SUBCOMMANDS: |
|
|
|
|
{{range .Subcommands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}} |
|
|
|
|
{{end}}{{end}}{{if .Flags}} |
|
|
|
|
OPTIONS: |
|
|
|
|
{{range $.Flags}}{{"\t"}}{{.}} |
|
|
|
|
{{end}} |
|
|
|
|
{{end}}` |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
solFlag = flag.String("sol", "", "Path to the Ethereum contract Solidity source to build and bind") |
|
|
|
|
solcFlag = flag.String("solc", "solc", "Solidity compiler to use if source builds are requested") |
|
|
|
|
excFlag = flag.String("exc", "", "Comma separated types to exclude from binding") |
|
|
|
|
var ( |
|
|
|
|
// Git SHA1 commit hash of the release (set via linker flags)
|
|
|
|
|
gitCommit = "" |
|
|
|
|
gitDate = "" |
|
|
|
|
|
|
|
|
|
vyFlag = flag.String("vy", "", "Path to the Ethereum contract Vyper source to build and bind") |
|
|
|
|
vyperFlag = flag.String("vyper", "vyper", "Vyper compiler to use if source builds are requested") |
|
|
|
|
app *cli.App |
|
|
|
|
|
|
|
|
|
pkgFlag = flag.String("pkg", "", "Package name to generate the binding into") |
|
|
|
|
outFlag = flag.String("out", "", "Output file for the generated binding (default = stdout)") |
|
|
|
|
langFlag = flag.String("lang", "go", "Destination language for the bindings (go, java, objc)") |
|
|
|
|
// Flags needed by abigen
|
|
|
|
|
abiFlag = cli.StringFlag{ |
|
|
|
|
Name: "abi", |
|
|
|
|
Usage: "Path to the Ethereum contract ABI json to bind, - for STDIN", |
|
|
|
|
} |
|
|
|
|
binFlag = cli.StringFlag{ |
|
|
|
|
Name: "bin", |
|
|
|
|
Usage: "Path to the Ethereum contract bytecode (generate deploy method)", |
|
|
|
|
} |
|
|
|
|
typeFlag = cli.StringFlag{ |
|
|
|
|
Name: "type", |
|
|
|
|
Usage: "Struct name for the binding (default = package name)", |
|
|
|
|
} |
|
|
|
|
jsonFlag = cli.StringFlag{ |
|
|
|
|
Name: "combined-json", |
|
|
|
|
Usage: "Path to the combined-json file generated by compiler", |
|
|
|
|
} |
|
|
|
|
solFlag = cli.StringFlag{ |
|
|
|
|
Name: "sol", |
|
|
|
|
Usage: "Path to the Ethereum contract Solidity source to build and bind", |
|
|
|
|
} |
|
|
|
|
solcFlag = cli.StringFlag{ |
|
|
|
|
Name: "solc", |
|
|
|
|
Usage: "Solidity compiler to use if source builds are requested", |
|
|
|
|
Value: "solc", |
|
|
|
|
} |
|
|
|
|
vyFlag = cli.StringFlag{ |
|
|
|
|
Name: "vy", |
|
|
|
|
Usage: "Path to the Ethereum contract Vyper source to build and bind", |
|
|
|
|
} |
|
|
|
|
vyperFlag = cli.StringFlag{ |
|
|
|
|
Name: "vyper", |
|
|
|
|
Usage: "Vyper compiler to use if source builds are requested", |
|
|
|
|
Value: "vyper", |
|
|
|
|
} |
|
|
|
|
excFlag = cli.StringFlag{ |
|
|
|
|
Name: "exc", |
|
|
|
|
Usage: "Comma separated types to exclude from binding", |
|
|
|
|
} |
|
|
|
|
pkgFlag = cli.StringFlag{ |
|
|
|
|
Name: "pkg", |
|
|
|
|
Usage: "Package name to generate the binding into", |
|
|
|
|
} |
|
|
|
|
outFlag = cli.StringFlag{ |
|
|
|
|
Name: "out", |
|
|
|
|
Usage: "Output file for the generated binding (default = stdout)", |
|
|
|
|
} |
|
|
|
|
langFlag = cli.StringFlag{ |
|
|
|
|
Name: "lang", |
|
|
|
|
Usage: "Destination language for the bindings (go, java, objc)", |
|
|
|
|
Value: "go", |
|
|
|
|
} |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
func main() { |
|
|
|
|
// Parse and ensure all needed inputs are specified
|
|
|
|
|
flag.Parse() |
|
|
|
|
func init() { |
|
|
|
|
app = utils.NewApp(gitCommit, gitDate, "ethereum checkpoint helper tool") |
|
|
|
|
app.Flags = []cli.Flag{ |
|
|
|
|
abiFlag, |
|
|
|
|
binFlag, |
|
|
|
|
typeFlag, |
|
|
|
|
jsonFlag, |
|
|
|
|
solFlag, |
|
|
|
|
solcFlag, |
|
|
|
|
vyFlag, |
|
|
|
|
vyperFlag, |
|
|
|
|
excFlag, |
|
|
|
|
pkgFlag, |
|
|
|
|
outFlag, |
|
|
|
|
langFlag, |
|
|
|
|
} |
|
|
|
|
app.Action = utils.MigrateFlags(abigen) |
|
|
|
|
cli.CommandHelpTemplate = commandHelperTemplate |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if *abiFlag == "" && *solFlag == "" && *vyFlag == "" { |
|
|
|
|
fmt.Printf("No contract ABI (--abi), Solidity source (--sol), or Vyper source (--vy) specified\n") |
|
|
|
|
os.Exit(-1) |
|
|
|
|
} else if (*abiFlag != "" || *binFlag != "" || *typFlag != "") && (*solFlag != "" || *vyFlag != "") { |
|
|
|
|
fmt.Printf("Contract ABI (--abi), bytecode (--bin) and type (--type) flags are mutually exclusive with the Solidity (--sol) and Vyper (--vy) flags\n") |
|
|
|
|
os.Exit(-1) |
|
|
|
|
} else if *solFlag != "" && *vyFlag != "" { |
|
|
|
|
fmt.Printf("Solidity (--sol) and Vyper (--vy) flags are mutually exclusive\n") |
|
|
|
|
os.Exit(-1) |
|
|
|
|
} |
|
|
|
|
if *pkgFlag == "" { |
|
|
|
|
fmt.Printf("No destination package specified (--pkg)\n") |
|
|
|
|
os.Exit(-1) |
|
|
|
|
func abigen(c *cli.Context) error { |
|
|
|
|
utils.CheckExclusive(c, abiFlag, jsonFlag, solFlag, vyFlag) // Only one source can be selected.
|
|
|
|
|
if c.GlobalString(pkgFlag.Name) == "" { |
|
|
|
|
utils.Fatalf("No destination package specified (--pkg)") |
|
|
|
|
} |
|
|
|
|
var lang bind.Lang |
|
|
|
|
switch *langFlag { |
|
|
|
|
switch c.GlobalString(langFlag.Name) { |
|
|
|
|
case "go": |
|
|
|
|
lang = bind.LangGo |
|
|
|
|
case "java": |
|
|
|
|
lang = bind.LangJava |
|
|
|
|
case "objc": |
|
|
|
|
lang = bind.LangObjC |
|
|
|
|
utils.Fatalf("Objc binding generation is uncompleted") |
|
|
|
|
default: |
|
|
|
|
fmt.Printf("Unsupported destination language \"%s\" (--lang)\n", *langFlag) |
|
|
|
|
os.Exit(-1) |
|
|
|
|
utils.Fatalf("Unsupported destination language \"%s\" (--lang)", c.GlobalString(langFlag.Name)) |
|
|
|
|
} |
|
|
|
|
// If the entire solidity code was specified, build and bind based on that
|
|
|
|
|
var ( |
|
|
|
@ -84,34 +150,67 @@ func main() { |
|
|
|
|
sigs []map[string]string |
|
|
|
|
libs = make(map[string]string) |
|
|
|
|
) |
|
|
|
|
if *solFlag != "" || *vyFlag != "" || *abiFlag == "-" { |
|
|
|
|
if c.GlobalString(abiFlag.Name) != "" { |
|
|
|
|
// Load up the ABI, optional bytecode and type name from the parameters
|
|
|
|
|
var ( |
|
|
|
|
abi []byte |
|
|
|
|
err error |
|
|
|
|
) |
|
|
|
|
input := c.GlobalString(abiFlag.Name) |
|
|
|
|
if input == "-" { |
|
|
|
|
abi, err = ioutil.ReadAll(os.Stdin) |
|
|
|
|
} else { |
|
|
|
|
abi, err = ioutil.ReadFile(input) |
|
|
|
|
} |
|
|
|
|
if err != nil { |
|
|
|
|
utils.Fatalf("Failed to read input ABI: %v", err) |
|
|
|
|
} |
|
|
|
|
abis = append(abis, string(abi)) |
|
|
|
|
|
|
|
|
|
var bin []byte |
|
|
|
|
if binFile := c.GlobalString(binFlag.Name); binFile != "" { |
|
|
|
|
if bin, err = ioutil.ReadFile(binFile); err != nil { |
|
|
|
|
utils.Fatalf("Failed to read input bytecode: %v", err) |
|
|
|
|
} |
|
|
|
|
if strings.Contains(string(bin), "//") { |
|
|
|
|
utils.Fatalf("Contract has additional library references, please use other mode(e.g. --combined-json) to catch library infos") |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
bins = append(bins, string(bin)) |
|
|
|
|
|
|
|
|
|
kind := c.GlobalString(typeFlag.Name) |
|
|
|
|
if kind == "" { |
|
|
|
|
kind = c.GlobalString(pkgFlag.Name) |
|
|
|
|
} |
|
|
|
|
types = append(types, kind) |
|
|
|
|
} else { |
|
|
|
|
// Generate the list of types to exclude from binding
|
|
|
|
|
exclude := make(map[string]bool) |
|
|
|
|
for _, kind := range strings.Split(*excFlag, ",") { |
|
|
|
|
for _, kind := range strings.Split(c.GlobalString(excFlag.Name), ",") { |
|
|
|
|
exclude[strings.ToLower(kind)] = true |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var contracts map[string]*compiler.Contract |
|
|
|
|
var err error |
|
|
|
|
var contracts map[string]*compiler.Contract |
|
|
|
|
|
|
|
|
|
switch { |
|
|
|
|
case *solFlag != "": |
|
|
|
|
contracts, err = compiler.CompileSolidity(*solcFlag, *solFlag) |
|
|
|
|
case c.GlobalIsSet(solFlag.Name): |
|
|
|
|
contracts, err = compiler.CompileSolidity(c.GlobalString(solcFlag.Name), c.GlobalString(solFlag.Name)) |
|
|
|
|
if err != nil { |
|
|
|
|
utils.Fatalf("Failed to build Solidity contract: %v", err) |
|
|
|
|
} |
|
|
|
|
case c.GlobalIsSet(vyFlag.Name): |
|
|
|
|
contracts, err = compiler.CompileVyper(c.GlobalString(vyperFlag.Name), c.GlobalString(vyFlag.Name)) |
|
|
|
|
if err != nil { |
|
|
|
|
fmt.Printf("Failed to build Solidity contract: %v\n", err) |
|
|
|
|
os.Exit(-1) |
|
|
|
|
utils.Fatalf("Failed to build Vyper contract: %v", err) |
|
|
|
|
} |
|
|
|
|
case *vyFlag != "": |
|
|
|
|
contracts, err = compiler.CompileVyper(*vyperFlag, *vyFlag) |
|
|
|
|
case c.GlobalIsSet(jsonFlag.Name): |
|
|
|
|
jsonOutput, err := ioutil.ReadFile(c.GlobalString(jsonFlag.Name)) |
|
|
|
|
if err != nil { |
|
|
|
|
fmt.Printf("Failed to build Vyper contract: %v\n", err) |
|
|
|
|
os.Exit(-1) |
|
|
|
|
utils.Fatalf("Failed to read combined-json from compiler: %v", err) |
|
|
|
|
} |
|
|
|
|
default: |
|
|
|
|
contracts, err = contractsFromStdin() |
|
|
|
|
contracts, err = compiler.ParseCombinedJSON(jsonOutput, "", "", "", "") |
|
|
|
|
if err != nil { |
|
|
|
|
fmt.Printf("Failed to read input ABIs from STDIN: %v\n", err) |
|
|
|
|
os.Exit(-1) |
|
|
|
|
utils.Fatalf("Failed to read contract information from json output: %v", err) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// Gather all non-excluded contract for binding
|
|
|
|
@ -121,65 +220,39 @@ func main() { |
|
|
|
|
} |
|
|
|
|
abi, err := json.Marshal(contract.Info.AbiDefinition) // Flatten the compiler parse
|
|
|
|
|
if err != nil { |
|
|
|
|
fmt.Printf("Failed to parse ABIs from compiler output: %v\n", err) |
|
|
|
|
os.Exit(-1) |
|
|
|
|
utils.Fatalf("Failed to parse ABIs from compiler output: %v", err) |
|
|
|
|
} |
|
|
|
|
abis = append(abis, string(abi)) |
|
|
|
|
bins = append(bins, contract.Code) |
|
|
|
|
sigs = append(sigs, contract.Hashes) |
|
|
|
|
|
|
|
|
|
nameParts := strings.Split(name, ":") |
|
|
|
|
types = append(types, nameParts[len(nameParts)-1]) |
|
|
|
|
|
|
|
|
|
libPattern := crypto.Keccak256Hash([]byte(name)).String()[2:36] |
|
|
|
|
libs[libPattern] = nameParts[len(nameParts)-1] |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
// Otherwise load up the ABI, optional bytecode and type name from the parameters
|
|
|
|
|
abi, err := ioutil.ReadFile(*abiFlag) |
|
|
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
fmt.Printf("Failed to read input ABI: %v\n", err) |
|
|
|
|
os.Exit(-1) |
|
|
|
|
} |
|
|
|
|
abis = append(abis, string(abi)) |
|
|
|
|
|
|
|
|
|
var bin []byte |
|
|
|
|
if *binFlag != "" { |
|
|
|
|
if bin, err = ioutil.ReadFile(*binFlag); err != nil { |
|
|
|
|
fmt.Printf("Failed to read input bytecode: %v\n", err) |
|
|
|
|
os.Exit(-1) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
bins = append(bins, string(bin)) |
|
|
|
|
|
|
|
|
|
kind := *typFlag |
|
|
|
|
if kind == "" { |
|
|
|
|
kind = *pkgFlag |
|
|
|
|
} |
|
|
|
|
types = append(types, kind) |
|
|
|
|
} |
|
|
|
|
// Generate the contract binding
|
|
|
|
|
code, err := bind.Bind(types, abis, bins, sigs, *pkgFlag, lang, libs) |
|
|
|
|
code, err := bind.Bind(types, abis, bins, sigs, c.GlobalString(pkgFlag.Name), lang, libs) |
|
|
|
|
if err != nil { |
|
|
|
|
fmt.Printf("Failed to generate ABI binding: %v\n", err) |
|
|
|
|
os.Exit(-1) |
|
|
|
|
utils.Fatalf("Failed to generate ABI binding: %v", err) |
|
|
|
|
} |
|
|
|
|
// Either flush it out to a file or display on the standard output
|
|
|
|
|
if *outFlag == "" { |
|
|
|
|
if !c.GlobalIsSet(outFlag.Name) { |
|
|
|
|
fmt.Printf("%s\n", code) |
|
|
|
|
return |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
if err := ioutil.WriteFile(*outFlag, []byte(code), 0600); err != nil { |
|
|
|
|
fmt.Printf("Failed to write ABI binding: %v\n", err) |
|
|
|
|
os.Exit(-1) |
|
|
|
|
if err := ioutil.WriteFile(c.GlobalString(outFlag.Name), []byte(code), 0600); err != nil { |
|
|
|
|
utils.Fatalf("Failed to write ABI binding: %v", err) |
|
|
|
|
} |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func contractsFromStdin() (map[string]*compiler.Contract, error) { |
|
|
|
|
bytes, err := ioutil.ReadAll(os.Stdin) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
func main() { |
|
|
|
|
log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) |
|
|
|
|
|
|
|
|
|
if err := app.Run(os.Args); err != nil { |
|
|
|
|
fmt.Fprintln(os.Stderr, err) |
|
|
|
|
os.Exit(1) |
|
|
|
|
} |
|
|
|
|
return compiler.ParseCombinedJSON(bytes, "", "", "", "") |
|
|
|
|
} |
|
|
|
|