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 }