github.com/dim4egster/coreth@v0.10.2/cmd/abigen/main.go (about)

     1  // (c) 2019-2020, Ava Labs, Inc.
     2  //
     3  // This file is a derived work, based on the go-ethereum library whose original
     4  // notices appear below.
     5  //
     6  // It is distributed under a license compatible with the licensing terms of the
     7  // original code from which it is derived.
     8  //
     9  // Much love to the original authors for their work.
    10  // **********
    11  // Copyright 2016 The go-ethereum Authors
    12  // This file is part of go-ethereum.
    13  //
    14  // go-ethereum is free software: you can redistribute it and/or modify
    15  // it under the terms of the GNU General Public License as published by
    16  // the Free Software Foundation, either version 3 of the License, or
    17  // (at your option) any later version.
    18  //
    19  // go-ethereum is distributed in the hope that it will be useful,
    20  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    21  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    22  // GNU General Public License for more details.
    23  //
    24  // You should have received a copy of the GNU General Public License
    25  // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
    26  
    27  package main
    28  
    29  import (
    30  	"encoding/json"
    31  	"fmt"
    32  	"io"
    33  	"os"
    34  	"regexp"
    35  	"strings"
    36  
    37  	"github.com/dim4egster/coreth/accounts/abi/bind"
    38  	"github.com/dim4egster/coreth/internal/flags"
    39  	"github.com/ethereum/go-ethereum/cmd/utils"
    40  	"github.com/ethereum/go-ethereum/common/compiler"
    41  	"github.com/ethereum/go-ethereum/crypto"
    42  	"github.com/ethereum/go-ethereum/log"
    43  	"github.com/urfave/cli/v2"
    44  )
    45  
    46  var (
    47  	// Git SHA1 commit hash of the release (set via linker flags)
    48  	gitCommit = ""
    49  	gitDate   = ""
    50  
    51  	app *cli.App
    52  )
    53  
    54  var (
    55  	// Flags needed by abigen
    56  	abiFlag = &cli.StringFlag{
    57  		Name:  "abi",
    58  		Usage: "Path to the Ethereum contract ABI json to bind, - for STDIN",
    59  	}
    60  	binFlag = &cli.StringFlag{
    61  		Name:  "bin",
    62  		Usage: "Path to the Ethereum contract bytecode (generate deploy method)",
    63  	}
    64  	typeFlag = &cli.StringFlag{
    65  		Name:  "type",
    66  		Usage: "Struct name for the binding (default = package name)",
    67  	}
    68  	jsonFlag = &cli.StringFlag{
    69  		Name:  "combined-json",
    70  		Usage: "Path to the combined-json file generated by compiler, - for STDIN",
    71  	}
    72  	excFlag = &cli.StringFlag{
    73  		Name:  "exc",
    74  		Usage: "Comma separated types to exclude from binding",
    75  	}
    76  	pkgFlag = &cli.StringFlag{
    77  		Name:  "pkg",
    78  		Usage: "Package name to generate the binding into",
    79  	}
    80  	outFlag = &cli.StringFlag{
    81  		Name:  "out",
    82  		Usage: "Output file for the generated binding (default = stdout)",
    83  	}
    84  	langFlag = &cli.StringFlag{
    85  		Name:  "lang",
    86  		Usage: "Destination language for the bindings (go, java, objc)",
    87  		Value: "go",
    88  	}
    89  	aliasFlag = &cli.StringFlag{
    90  		Name:  "alias",
    91  		Usage: "Comma separated aliases for function and event renaming, e.g. original1=alias1, original2=alias2",
    92  	}
    93  )
    94  
    95  func init() {
    96  	app = flags.NewApp(gitCommit, gitDate, "ethereum checkpoint helper tool")
    97  	app.Name = "abigen"
    98  	app.Flags = []cli.Flag{
    99  		abiFlag,
   100  		binFlag,
   101  		typeFlag,
   102  		jsonFlag,
   103  		excFlag,
   104  		pkgFlag,
   105  		outFlag,
   106  		langFlag,
   107  		aliasFlag,
   108  	}
   109  	app.Action = abigen
   110  }
   111  
   112  func abigen(c *cli.Context) error {
   113  	utils.CheckExclusive(c, abiFlag, jsonFlag) // Only one source can be selected.
   114  
   115  	if c.String(pkgFlag.Name) == "" {
   116  		utils.Fatalf("No destination package specified (--pkg)")
   117  	}
   118  	var lang bind.Lang
   119  	switch c.String(langFlag.Name) {
   120  	case "go":
   121  		lang = bind.LangGo
   122  	case "java":
   123  		lang = bind.LangJava
   124  	case "objc":
   125  		lang = bind.LangObjC
   126  		utils.Fatalf("Objc binding generation is uncompleted")
   127  	default:
   128  		utils.Fatalf("Unsupported destination language \"%s\" (--lang)", c.String(langFlag.Name))
   129  	}
   130  	// If the entire solidity code was specified, build and bind based on that
   131  	var (
   132  		abis    []string
   133  		bins    []string
   134  		types   []string
   135  		sigs    []map[string]string
   136  		libs    = make(map[string]string)
   137  		aliases = make(map[string]string)
   138  	)
   139  	if c.String(abiFlag.Name) != "" {
   140  		// Load up the ABI, optional bytecode and type name from the parameters
   141  		var (
   142  			abi []byte
   143  			err error
   144  		)
   145  		input := c.String(abiFlag.Name)
   146  		if input == "-" {
   147  			abi, err = io.ReadAll(os.Stdin)
   148  		} else {
   149  			abi, err = os.ReadFile(input)
   150  		}
   151  		if err != nil {
   152  			utils.Fatalf("Failed to read input ABI: %v", err)
   153  		}
   154  		abis = append(abis, string(abi))
   155  
   156  		var bin []byte
   157  		if binFile := c.String(binFlag.Name); binFile != "" {
   158  			if bin, err = os.ReadFile(binFile); err != nil {
   159  				utils.Fatalf("Failed to read input bytecode: %v", err)
   160  			}
   161  			if strings.Contains(string(bin), "//") {
   162  				utils.Fatalf("Contract has additional library references, please use other mode(e.g. --combined-json) to catch library infos")
   163  			}
   164  		}
   165  		bins = append(bins, string(bin))
   166  
   167  		kind := c.String(typeFlag.Name)
   168  		if kind == "" {
   169  			kind = c.String(pkgFlag.Name)
   170  		}
   171  		types = append(types, kind)
   172  	} else {
   173  		// Generate the list of types to exclude from binding
   174  		exclude := make(map[string]bool)
   175  		for _, kind := range strings.Split(c.String(excFlag.Name), ",") {
   176  			exclude[strings.ToLower(kind)] = true
   177  		}
   178  		var contracts map[string]*compiler.Contract
   179  
   180  		if c.IsSet(jsonFlag.Name) {
   181  			var (
   182  				input      = c.String(jsonFlag.Name)
   183  				jsonOutput []byte
   184  				err        error
   185  			)
   186  			if input == "-" {
   187  				jsonOutput, err = io.ReadAll(os.Stdin)
   188  			} else {
   189  				jsonOutput, err = os.ReadFile(input)
   190  			}
   191  			if err != nil {
   192  				utils.Fatalf("Failed to read combined-json: %v", err)
   193  			}
   194  			contracts, err = compiler.ParseCombinedJSON(jsonOutput, "", "", "", "")
   195  			if err != nil {
   196  				utils.Fatalf("Failed to read contract information from json output: %v", err)
   197  			}
   198  		}
   199  		// Gather all non-excluded contract for binding
   200  		for name, contract := range contracts {
   201  			if exclude[strings.ToLower(name)] {
   202  				continue
   203  			}
   204  			abi, err := json.Marshal(contract.Info.AbiDefinition) // Flatten the compiler parse
   205  			if err != nil {
   206  				utils.Fatalf("Failed to parse ABIs from compiler output: %v", err)
   207  			}
   208  			abis = append(abis, string(abi))
   209  			bins = append(bins, contract.Code)
   210  			sigs = append(sigs, contract.Hashes)
   211  			nameParts := strings.Split(name, ":")
   212  			types = append(types, nameParts[len(nameParts)-1])
   213  
   214  			// Derive the library placeholder which is a 34 character prefix of the
   215  			// hex encoding of the keccak256 hash of the fully qualified library name.
   216  			// Note that the fully qualified library name is the path of its source
   217  			// file and the library name separated by ":".
   218  			libPattern := crypto.Keccak256Hash([]byte(name)).String()[2:36] // the first 2 chars are 0x
   219  			libs[libPattern] = nameParts[len(nameParts)-1]
   220  		}
   221  	}
   222  	// Extract all aliases from the flags
   223  	if c.IsSet(aliasFlag.Name) {
   224  		// We support multi-versions for aliasing
   225  		// e.g.
   226  		//      foo=bar,foo2=bar2
   227  		//      foo:bar,foo2:bar2
   228  		re := regexp.MustCompile(`(?:(\w+)[:=](\w+))`)
   229  		submatches := re.FindAllStringSubmatch(c.String(aliasFlag.Name), -1)
   230  		for _, match := range submatches {
   231  			aliases[match[1]] = match[2]
   232  		}
   233  	}
   234  	// Generate the contract binding
   235  	code, err := bind.Bind(types, abis, bins, sigs, c.String(pkgFlag.Name), lang, libs, aliases)
   236  	if err != nil {
   237  		utils.Fatalf("Failed to generate ABI binding: %v", err)
   238  	}
   239  	// Either flush it out to a file or display on the standard output
   240  	if !c.IsSet(outFlag.Name) {
   241  		fmt.Printf("%s\n", code)
   242  		return nil
   243  	}
   244  	if err := os.WriteFile(c.String(outFlag.Name), []byte(code), 0600); err != nil {
   245  		utils.Fatalf("Failed to write ABI binding: %v", err)
   246  	}
   247  	return nil
   248  }
   249  
   250  func main() {
   251  	log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
   252  
   253  	if err := app.Run(os.Args); err != nil {
   254  		fmt.Fprintln(os.Stderr, err)
   255  		os.Exit(1)
   256  	}
   257  }