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  }