github.com/0xPolygon/supernets2-node@v0.0.0-20230711153321-2fe574524eaa/test/scripts/txsender/main.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"math/big"
     6  	"os"
     7  	"strconv"
     8  
     9  	"github.com/0xPolygon/supernets2-node/log"
    10  	"github.com/0xPolygon/supernets2-node/test/operations"
    11  	"github.com/ethereum/go-ethereum"
    12  	"github.com/ethereum/go-ethereum/common"
    13  	"github.com/ethereum/go-ethereum/core/types"
    14  	"github.com/ethereum/go-ethereum/ethclient"
    15  	"github.com/urfave/cli/v2"
    16  )
    17  
    18  const (
    19  	flagNetworkName       = "network"
    20  	flagWaitName          = "wait"
    21  	flagVerboseName       = "verbose"
    22  	flagNetworkLocalL1Key = "l1"
    23  	flagNetworkLocalL2Key = "l2"
    24  	defaultNetwork        = flagNetworkLocalL2Key
    25  
    26  	receiverAddr = "0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D"
    27  )
    28  
    29  type networkLayer int
    30  
    31  const (
    32  	networkLayer1 networkLayer = iota
    33  	networkLayer2
    34  )
    35  
    36  var networks = map[string]struct {
    37  	Name       string
    38  	URL        string
    39  	ChainID    uint64
    40  	PrivateKey string
    41  	networkLayer
    42  }{
    43  	flagNetworkLocalL1Key: {Name: "Local L1", URL: operations.DefaultL1NetworkURL, ChainID: operations.DefaultL1ChainID, PrivateKey: operations.DefaultSequencerPrivateKey, networkLayer: networkLayer1},
    44  	flagNetworkLocalL2Key: {Name: "Local L2", URL: operations.DefaultL2NetworkURL, ChainID: operations.DefaultL2ChainID, PrivateKey: operations.DefaultSequencerPrivateKey, networkLayer: networkLayer2},
    45  }
    46  
    47  var (
    48  	flagNetwork = cli.StringSliceFlag{
    49  		Name:     flagNetworkName,
    50  		Aliases:  []string{"n"},
    51  		Usage:    "list of networks on which to send transactions",
    52  		Required: false,
    53  	}
    54  	flagWait = cli.BoolFlag{
    55  		Name:     flagWaitName,
    56  		Aliases:  []string{"w"},
    57  		Usage:    "wait transactions to be confirmed",
    58  		Required: false,
    59  	}
    60  	flagVerbose = cli.BoolFlag{
    61  		Name:     flagVerboseName,
    62  		Aliases:  []string{"v"},
    63  		Usage:    "output verbose logs",
    64  		Required: false,
    65  	}
    66  )
    67  
    68  func main() {
    69  	txsender := cli.NewApp()
    70  	txsender.Name = "txsender"
    71  	txsender.Flags = []cli.Flag{&flagNetwork, &flagWait, &flagVerbose}
    72  	txsender.Usage = "send transactions"
    73  	txsender.Description = `This tool allows to send a specified number of transactions.
    74  Optionally it can wait for the transactions to be validated.`
    75  	txsender.DefaultCommand = "send"
    76  	txsender.Commands = []*cli.Command{
    77  		{
    78  			Name:    "send",
    79  			Before:  setLogLevel,
    80  			Aliases: []string{},
    81  			Usage:   "Sends the specified number of transactions",
    82  			Description: `This command sends the specified number of transactions.
    83  If --wait flag is used, it waits for the corresponding validation transaction.`,
    84  			ArgsUsage: "number of transactions to be sent (default: 1)",
    85  			Action:    sendTxs,
    86  		},
    87  	}
    88  
    89  	err := txsender.Run(os.Args)
    90  	if err != nil {
    91  		log.Fatal(err)
    92  		os.Exit(1)
    93  	}
    94  }
    95  
    96  func setLogLevel(ctx *cli.Context) error {
    97  	logLevel := "info"
    98  	if ctx.Bool(flagVerboseName) {
    99  		logLevel = "debug"
   100  	}
   101  
   102  	log.Init(log.Config{
   103  		Level:   logLevel,
   104  		Outputs: []string{"stderr"},
   105  	})
   106  	return nil
   107  }
   108  
   109  func sendTxs(cliCtx *cli.Context) error {
   110  	ctx := cliCtx.Context
   111  
   112  	nTxs := 1 // send 1 tx by default
   113  	if cliCtx.NArg() > 0 {
   114  		nTxsArgStr := cliCtx.Args().Get(0)
   115  		nTxsArg, err := strconv.Atoi(nTxsArgStr)
   116  		if err == nil {
   117  			nTxs = nTxsArg
   118  		}
   119  	}
   120  
   121  	selNetworks := cliCtx.StringSlice(flagNetworkName)
   122  
   123  	// if no network selected, pick the default one
   124  	if selNetworks == nil {
   125  		selNetworks = []string{defaultNetwork}
   126  	}
   127  
   128  	for _, selNetwork := range selNetworks {
   129  		network, ok := networks[selNetwork]
   130  		if !ok {
   131  			netKeys := make([]string, 0, len(networks))
   132  			for net := range networks {
   133  				netKeys = append(netKeys, net)
   134  			}
   135  			return fmt.Errorf("please specify one or more of these networks: %v", netKeys)
   136  		}
   137  		log.Infof("connecting to %v: %v", network.Name, network.URL)
   138  		client, err := ethclient.Dial(network.URL)
   139  		if err != nil {
   140  			return err
   141  		}
   142  		log.Infof("connected")
   143  
   144  		auth, err := operations.GetAuth(network.PrivateKey, network.ChainID)
   145  		if err != nil {
   146  			return err
   147  		}
   148  
   149  		log.Infof("Sender Addr: %v", auth.From.String())
   150  
   151  		senderBalance, err := client.BalanceAt(ctx, auth.From, nil)
   152  		if err != nil {
   153  			return err
   154  		}
   155  		log.Debugf("ETH Balance for %v: %v", auth.From, senderBalance)
   156  
   157  		amount := big.NewInt(10) //nolint:gomnd
   158  		log.Debugf("Transfer Amount: %v", amount)
   159  
   160  		senderNonce, err := client.PendingNonceAt(ctx, auth.From)
   161  		if err != nil {
   162  			return err
   163  		}
   164  		log.Debugf("Sender Nonce: %v", senderNonce)
   165  
   166  		to := common.HexToAddress(receiverAddr)
   167  		log.Infof("Receiver Addr: %v", to.String())
   168  
   169  		gasLimit, err := client.EstimateGas(ctx, ethereum.CallMsg{From: auth.From, To: &to, Value: amount})
   170  		if err != nil {
   171  			return err
   172  		}
   173  
   174  		gasPrice, err := client.SuggestGasPrice(ctx)
   175  		if err != nil {
   176  			return err
   177  		}
   178  
   179  		txs := make([]*types.Transaction, 0, nTxs)
   180  		for i := 0; i < nTxs; i++ {
   181  			tx := types.NewTransaction(senderNonce+uint64(i), to, amount, gasLimit, gasPrice, nil)
   182  			txs = append(txs, tx)
   183  		}
   184  
   185  		if cliCtx.Bool(flagWaitName) {
   186  			var err error
   187  			if network.networkLayer == networkLayer1 {
   188  				err = operations.ApplyL1Txs(ctx, txs, auth, client)
   189  			} else if network.networkLayer == networkLayer2 {
   190  				_, err = operations.ApplyL2Txs(ctx, txs, auth, client, operations.VerifiedConfirmationLevel)
   191  			}
   192  			if err != nil {
   193  				return err
   194  			}
   195  		} else {
   196  			for i := 0; i < nTxs; i++ {
   197  				signedTx, err := auth.Signer(auth.From, txs[i])
   198  				if err != nil {
   199  					return err
   200  				}
   201  				log.Infof("Sending Tx %v Nonce %v", signedTx.Hash(), signedTx.Nonce())
   202  				err = client.SendTransaction(ctx, signedTx)
   203  				if err != nil {
   204  					return err
   205  				}
   206  			}
   207  		}
   208  
   209  		if nTxs > 1 {
   210  			log.Infof("%d transactions successfully sent", nTxs)
   211  		} else {
   212  			log.Info("transaction successfully sent")
   213  		}
   214  	}
   215  
   216  	return nil
   217  }