github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/cli/smartcontract/generate.go (about)

     1  package smartcontract
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"strings"
     7  
     8  	"github.com/nspcc-dev/neo-go/cli/cmdargs"
     9  	"github.com/nspcc-dev/neo-go/pkg/smartcontract/binding"
    10  	"github.com/nspcc-dev/neo-go/pkg/smartcontract/rpcbinding"
    11  	"github.com/nspcc-dev/neo-go/pkg/util"
    12  	"github.com/urfave/cli"
    13  	"gopkg.in/yaml.v3"
    14  )
    15  
    16  var generatorFlags = []cli.Flag{
    17  	cli.StringFlag{
    18  		Name:  "config, c",
    19  		Usage: "Configuration file to use",
    20  	},
    21  	cli.StringFlag{
    22  		Name:     "manifest, m",
    23  		Required: true,
    24  		Usage:    "Read contract manifest (*.manifest.json) file",
    25  	},
    26  	cli.StringFlag{
    27  		Name:     "out, o",
    28  		Required: true,
    29  		Usage:    "Output of the compiled wrapper",
    30  	},
    31  	cli.StringFlag{
    32  		Name:  "hash",
    33  		Usage: "Smart-contract hash. If not passed, the wrapper will be designed for dynamic hash usage",
    34  	},
    35  }
    36  
    37  var generateWrapperCmd = cli.Command{
    38  	Name:      "generate-wrapper",
    39  	Usage:     "generate wrapper to use in other contracts",
    40  	UsageText: "neo-go contract generate-wrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]",
    41  	Description: `Generates a Go wrapper to use it in other smart contracts. If the
    42     --hash flag is provided, CALLT instruction is used for the target contract
    43     invocation as an optimization of the wrapper contract code. If omitted, the
    44     generated wrapper will be designed for dynamic hash usage, allowing
    45     the hash to be specified at runtime.
    46  `,
    47  	Action: contractGenerateWrapper,
    48  	Flags:  generatorFlags,
    49  }
    50  
    51  var generateRPCWrapperCmd = cli.Command{
    52  	Name:      "generate-rpcwrapper",
    53  	Usage:     "generate RPC wrapper to use for data reads",
    54  	UsageText: "neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]",
    55  	Action:    contractGenerateRPCWrapper,
    56  	Flags:     generatorFlags,
    57  }
    58  
    59  func contractGenerateWrapper(ctx *cli.Context) error {
    60  	return contractGenerateSomething(ctx, binding.Generate)
    61  }
    62  
    63  func contractGenerateRPCWrapper(ctx *cli.Context) error {
    64  	return contractGenerateSomething(ctx, rpcbinding.Generate)
    65  }
    66  
    67  // contractGenerateSomething reads generator parameters and calls the given callback.
    68  func contractGenerateSomething(ctx *cli.Context, cb func(binding.Config) error) error {
    69  	if err := cmdargs.EnsureNone(ctx); err != nil {
    70  		return err
    71  	}
    72  	var (
    73  		h   util.Uint160
    74  		err error
    75  	)
    76  	if hStr := ctx.String("hash"); len(hStr) != 0 {
    77  		h, err = util.Uint160DecodeStringLE(strings.TrimPrefix(hStr, "0x"))
    78  		if err != nil {
    79  			return cli.NewExitError(fmt.Errorf("invalid contract hash: %w", err), 1)
    80  		}
    81  	}
    82  	m, _, err := readManifest(ctx.String("manifest"), h)
    83  	if err != nil {
    84  		return cli.NewExitError(fmt.Errorf("can't read contract manifest: %w", err), 1)
    85  	}
    86  
    87  	cfg := binding.NewConfig()
    88  	if cfgPath := ctx.String("config"); cfgPath != "" {
    89  		bs, err := os.ReadFile(cfgPath)
    90  		if err != nil {
    91  			return cli.NewExitError(fmt.Errorf("can't read config file: %w", err), 1)
    92  		}
    93  		err = yaml.Unmarshal(bs, &cfg)
    94  		if err != nil {
    95  			return cli.NewExitError(fmt.Errorf("can't parse config file: %w", err), 1)
    96  		}
    97  	}
    98  	cfg.Manifest = m
    99  	cfg.Hash = h
   100  
   101  	f, err := os.Create(ctx.String("out"))
   102  	if err != nil {
   103  		return cli.NewExitError(fmt.Errorf("can't create output file: %w", err), 1)
   104  	}
   105  	defer f.Close()
   106  
   107  	cfg.Output = f
   108  
   109  	err = cb(cfg)
   110  	if err != nil {
   111  		return cli.NewExitError(fmt.Errorf("error during generation: %w", err), 1)
   112  	}
   113  	return nil
   114  }