diff --git a/cmd/abigen/main.go b/cmd/abigen/main.go index 3a1ae6f4c3..3ac37ba7ad 100644 --- a/cmd/abigen/main.go +++ b/cmd/abigen/main.go @@ -29,7 +29,7 @@ import ( ) var ( - abiFlag = flag.String("abi", "", "Path to the Ethereum contract ABI json to bind") + 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)") @@ -75,16 +75,27 @@ func main() { bins []string types []string ) - if *solFlag != "" { + if *solFlag != "" || *abiFlag == "-" { // Generate the list of types to exclude from binding exclude := make(map[string]bool) for _, kind := range strings.Split(*excFlag, ",") { exclude[strings.ToLower(kind)] = true } - contracts, err := compiler.CompileSolidity(*solcFlag, *solFlag) - if err != nil { - fmt.Printf("Failed to build Solidity contract: %v\n", err) - os.Exit(-1) + + var contracts map[string]*compiler.Contract + var err error + if *solFlag != "" { + contracts, err = compiler.CompileSolidity(*solcFlag, *solFlag) + if err != nil { + fmt.Printf("Failed to build Solidity contract: %v\n", err) + os.Exit(-1) + } + } else { + contracts, err = contractsFromStdin() + if err != nil { + fmt.Printf("Failed to read input ABIs from STDIN: %v\n", err) + os.Exit(-1) + } } // Gather all non-excluded contract for binding for name, contract := range contracts { @@ -138,3 +149,12 @@ func main() { os.Exit(-1) } } + +func contractsFromStdin() (map[string]*compiler.Contract, error) { + bytes, err := ioutil.ReadAll(os.Stdin) + if err != nil { + return nil, err + } + + return compiler.ParseCombinedJSON(bytes, "", "", "", "") +} diff --git a/common/compiler/solidity.go b/common/compiler/solidity.go index 234714a2b9..f6e8d2e42a 100644 --- a/common/compiler/solidity.go +++ b/common/compiler/solidity.go @@ -31,11 +31,17 @@ import ( var versionRegexp = regexp.MustCompile(`([0-9]+)\.([0-9]+)\.([0-9]+)`) +// Contract contains information about a compiled contract, alongside its code. type Contract struct { Code string `json:"code"` Info ContractInfo `json:"info"` } +// ContractInfo contains information about a compiled contract, including access +// to the ABI definition, user and developer docs, and metadata. +// +// Depending on the source, language version, compiler version, and compiler +// options will provide information about how the contract was compiled. type ContractInfo struct { Source string `json:"source"` Language string `json:"language"` @@ -142,8 +148,22 @@ func (s *Solidity) run(cmd *exec.Cmd, source string) (map[string]*Contract, erro if err := cmd.Run(); err != nil { return nil, fmt.Errorf("solc: %v\n%s", err, stderr.Bytes()) } + + return ParseCombinedJSON(stdout.Bytes(), source, s.Version, s.Version, strings.Join(s.makeArgs(), " ")) +} + +// ParseCombinedJSON takes the direct output of a solc --combined-output run and +// parses it into a map of string contract name to Contract structs. The +// provided source, language and compiler version, and compiler options are all +// passed through into the Contract structs. +// +// The solc output is expected to contain ABI, user docs, and dev docs. +// +// Returns an error if the JSON is malformed or missing data, or if the JSON +// embedded within the JSON is malformed. +func ParseCombinedJSON(combinedJSON []byte, source string, languageVersion string, compilerVersion string, compilerOptions string) (map[string]*Contract, error) { var output solcOutput - if err := json.Unmarshal(stdout.Bytes(), &output); err != nil { + if err := json.Unmarshal(combinedJSON, &output); err != nil { return nil, err } @@ -168,9 +188,9 @@ func (s *Solidity) run(cmd *exec.Cmd, source string) (map[string]*Contract, erro Info: ContractInfo{ Source: source, Language: "Solidity", - LanguageVersion: s.Version, - CompilerVersion: s.Version, - CompilerOptions: strings.Join(s.makeArgs(), " "), + LanguageVersion: languageVersion, + CompilerVersion: compilerVersion, + CompilerOptions: compilerOptions, AbiDefinition: abi, UserDoc: userdoc, DeveloperDoc: devdoc,