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