github.com/aeternity/aepp-sdk-go/v4@v4.0.1/cmd/tx.go (about) 1 package cmd 2 3 import ( 4 "errors" 5 "fmt" 6 "math/big" 7 8 "github.com/aeternity/aepp-sdk-go/utils" 9 10 "github.com/aeternity/aepp-sdk-go/aeternity" 11 12 "github.com/spf13/cobra" 13 ) 14 15 // txCmd implments the tx command 16 var txCmd = &cobra.Command{ 17 Use: "tx SUBCOMMAND [ARGS]...", 18 Short: "Handle transactions creation", 19 Long: ``, 20 } 21 22 // txSpendCmd implements the tx spend subcommand. 23 // It returns an unsigned spend transaction (to be signed with account sign) 24 var txSpendCmd = &cobra.Command{ 25 Use: "spend SENDER_ADDRESS RECIPIENT_ADDRESS AMOUNT", 26 Short: "Create a transaction to another account (unsigned)", 27 Long: ``, 28 Args: cobra.ExactArgs(3), 29 RunE: txSpendFunc, 30 } 31 32 func txSpendFunc(cmd *cobra.Command, args []string) (err error) { 33 var ( 34 sender string 35 recipient string 36 amount *big.Int 37 feeBigInt *big.Int 38 ) 39 40 // Load variables from arguments 41 sender = args[0] 42 recipient = args[1] 43 amount, err = utils.NewIntFromString(args[2]) 44 feeBigInt, _ = utils.NewIntFromString(fee) 45 46 // Validate arguments 47 if !IsAddress(sender) { 48 return errors.New("Error, missing or invalid sender address") 49 } 50 if !IsAddress(recipient) { 51 return errors.New("Error, missing or invalid recipient address") 52 } 53 if amount.Cmp(big.NewInt(0)) == -1 { 54 return errors.New("Error, missing or invalid amount") 55 } 56 if feeBigInt.Cmp(big.NewInt(0)) == -1 { 57 return errors.New("Error, missing or invalid fee") 58 } 59 60 // Connect to the node to find out sender nonce only 61 if nonce == 0 { 62 client := aeternity.NewNode(aeternity.Config.Node.URL, false) 63 nonce, err = aeternity.GetNextNonce(client, sender) 64 if err != nil { 65 return err 66 } 67 } 68 69 tx := aeternity.NewSpendTx(sender, recipient, *amount, *feeBigInt, spendTxPayload, ttl, nonce) 70 if err != nil { 71 return err 72 } 73 base64Tx, err := aeternity.BaseEncodeTx(&tx) 74 if err != nil { 75 return err 76 } 77 78 // Sender, Recipient, Amount, Ttl, Fee, Nonce, Payload, Encoded 79 aeternity.Pp( 80 "Sender acount", sender, 81 "Recipient account", recipient, 82 "Amount", amount, 83 "TTL", ttl, 84 "Fee", fee, 85 "Nonce", nonce, 86 "Payload", spendTxPayload, 87 "Encoded", base64Tx, 88 ) 89 return nil 90 } 91 92 var txContractCreateCmd = &cobra.Command{ 93 Use: "deploy OWNER_ID CONTRACT_BYTECODE INIT_CALLDATA", 94 Short: "Create a smart contract on the blockchain", 95 Long: ``, 96 Args: cobra.ExactArgs(3), 97 RunE: txContractCreateFunc, 98 } 99 100 func txContractCreateFunc(cmd *cobra.Command, args []string) (err error) { 101 var ( 102 owner string 103 contract string 104 calldata string 105 ) 106 107 // Load variables from arguments 108 owner = args[0] 109 if !IsAddress(owner) { 110 return errors.New("Error, missing or invalid owner address") 111 } 112 contract = args[1] 113 if !IsBytecode(contract) { 114 return errors.New("Error, missing or invalid contract bytecode") 115 } 116 calldata = args[2] 117 if !IsBytecode(calldata) { 118 return errors.New("Error, missing or invalid init calldata bytecode") 119 } 120 121 c := aeternity.Context{ 122 Client: aeternity.NewNode(aeternity.Config.Node.URL, debug), 123 Address: owner, 124 } 125 126 tx, err := c.ContractCreateTx(contract, calldata, aeternity.Config.Client.Contracts.VMVersion, aeternity.Config.Client.Contracts.ABIVersion, aeternity.Config.Client.Contracts.Deposit, aeternity.Config.Client.Contracts.Amount, aeternity.Config.Client.Contracts.Gas, aeternity.Config.Client.Contracts.GasPrice, aeternity.Config.Client.Fee) 127 128 if err != nil { 129 return err 130 } 131 txStr, err := aeternity.BaseEncodeTx(&tx) 132 if err != nil { 133 return err 134 } 135 136 aeternity.Pp( 137 "OwnerID", tx.OwnerID, 138 "AccountNonce", tx.AccountNonce, 139 "Code", tx.Code, 140 "VMVersion", tx.VMVersion, 141 "ABIVersion", tx.AbiVersion, 142 "Deposit", tx.Deposit, 143 "Amount", tx.Amount, 144 "Gas", tx.Gas, 145 "GasPrice", tx.GasPrice, 146 "TTL", tx.TTL, 147 "Fee", tx.Fee, 148 "CallData", tx.CallData, 149 "Encoded", txStr, 150 ) 151 152 return 153 } 154 155 // txVerifyCmd implements the tx verify subcommand. 156 // It verfies the signature of a signed transaction 157 var txVerifyCmd = &cobra.Command{ 158 Use: "verify SENDER_ADDRESS SIGNED_TRANSACTION", 159 Short: "Verify the signature of a signed base64 transaction", 160 Long: ``, 161 Args: cobra.ExactArgs(2), 162 RunE: txVerifyFunc, 163 SilenceUsage: true, 164 } 165 166 func txVerifyFunc(cmd *cobra.Command, args []string) (err error) { 167 // Load variables from arguments 168 sender := args[0] 169 txSignedBase64 := args[1] 170 171 if !IsAddress(sender) { 172 return errors.New("Error, missing or invalid sender address") 173 } 174 if !IsTransaction(txSignedBase64) { 175 return errors.New("Error, missing or invalid base64 encoded transaction") 176 } 177 valid, err := aeternity.VerifySignedTx(sender, txSignedBase64, aeternity.Config.Node.NetworkID) 178 if err != nil { 179 err := fmt.Errorf("error while verifying signature: %s", err) 180 return err 181 } 182 if valid { 183 fmt.Printf("The signature is valid (network-id: %s)\n", aeternity.Config.Node.NetworkID) 184 } else { 185 message := fmt.Sprintf("The signature is invalid (expecting network-id: %s)", aeternity.Config.Node.NetworkID) 186 // fmt.Println(message) 187 err = errors.New(message) 188 } 189 return err 190 } 191 192 // txDumpRawCmd implements the tx dumpraw subcommand. 193 // It decodes a base58/64 input down into its RLP byte level representation. 194 var txDumpRawCmd = &cobra.Command{ 195 Use: "dumpraw TRANSACTION", 196 Short: "Show the RLP byte level representation of a base58/64 encoded object", 197 Long: ``, 198 Args: cobra.ExactArgs(1), 199 RunE: txDumpRawFunc, 200 } 201 202 func txDumpRawFunc(cmd *cobra.Command, args []string) (err error) { 203 tx := args[0] 204 if !IsTransaction(tx) { 205 return errors.New("Error, missing or invalid base64 encoded transaction") 206 } 207 txRaw, err := aeternity.Decode(tx) 208 if err != nil { 209 return err 210 } 211 res := aeternity.DecodeRLPMessage(txRaw) 212 fmt.Println(res) 213 return nil 214 } 215 216 func init() { 217 RootCmd.AddCommand(txCmd) 218 txCmd.AddCommand(txSpendCmd) 219 txCmd.AddCommand(txContractCreateCmd) 220 txCmd.AddCommand(txVerifyCmd) 221 txCmd.AddCommand(txDumpRawCmd) 222 223 // tx spend command 224 txSpendCmd.Flags().StringVar(&fee, "fee", aeternity.Config.Client.Fee.String(), fmt.Sprintf("Set the transaction fee (default=%s)", aeternity.Config.Client.Fee.String())) 225 txSpendCmd.Flags().Uint64Var(&ttl, "ttl", aeternity.Config.Client.TTL, fmt.Sprintf("Set the TTL in keyblocks (default=%d)", aeternity.Config.Client.TTL)) 226 txSpendCmd.Flags().Uint64Var(&nonce, "nonce", 0, fmt.Sprint("Set the sender account nonce, if not the chain will be queried for its value")) 227 txSpendCmd.Flags().StringVar(&spendTxPayload, "payload", "", fmt.Sprint("Optional text payload for Spend Transactions")) 228 }