|
|
|
@ -5,6 +5,7 @@ import ( |
|
|
|
|
"errors" |
|
|
|
|
"fmt" |
|
|
|
|
"io/ioutil" |
|
|
|
|
"os" |
|
|
|
|
"strconv" |
|
|
|
|
"strings" |
|
|
|
|
"time" |
|
|
|
@ -33,6 +34,7 @@ var ( |
|
|
|
|
targetChain string |
|
|
|
|
chainName chainIDWrapper |
|
|
|
|
dryRun bool |
|
|
|
|
offlineSign bool |
|
|
|
|
trueNonce bool |
|
|
|
|
inputNonce string |
|
|
|
|
gasPrice string |
|
|
|
@ -99,6 +101,9 @@ func handlerForError(txLog *transactionLog, err error) error { |
|
|
|
|
// Note that the vars need to be set before calling this handler.
|
|
|
|
|
func handlerForTransaction(txLog *transactionLog) error { |
|
|
|
|
from := fromAddress.String() |
|
|
|
|
|
|
|
|
|
var networkHandler *rpc.HTTPMessenger |
|
|
|
|
if !offlineSign { |
|
|
|
|
s, err := sharding.Structure(node) |
|
|
|
|
if handlerForError(txLog, err) != nil { |
|
|
|
|
return err |
|
|
|
@ -107,10 +112,12 @@ func handlerForTransaction(txLog *transactionLog) error { |
|
|
|
|
if handlerForError(txLog, err) != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
networkHandler, err := handlerForShard(fromShardID, node) |
|
|
|
|
|
|
|
|
|
networkHandler, err = handlerForShard(fromShardID, node) |
|
|
|
|
if handlerForError(txLog, err) != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var ctrlr *transaction.Controller |
|
|
|
|
if useLedgerWallet { |
|
|
|
@ -125,7 +132,7 @@ func handlerForTransaction(txLog *transactionLog) error { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
nonce, err := getNonce(fromAddress.String(), networkHandler) |
|
|
|
|
if err != nil { |
|
|
|
|
if handlerForError(txLog, err) != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -264,6 +271,9 @@ func opts(ctlr *transaction.Controller) { |
|
|
|
|
if dryRun { |
|
|
|
|
ctlr.Behavior.DryRun = true |
|
|
|
|
} |
|
|
|
|
if offlineSign { |
|
|
|
|
ctlr.Behavior.OfflineSign = true |
|
|
|
|
} |
|
|
|
|
if useLedgerWallet { |
|
|
|
|
ctlr.Behavior.SigningImpl = transaction.Ledger |
|
|
|
|
} |
|
|
|
@ -291,6 +301,8 @@ func getNonceFromInput(addr, inputNonce string, messenger rpc.T) (uint64, error) |
|
|
|
|
} else { |
|
|
|
|
return nonce, nil |
|
|
|
|
} |
|
|
|
|
} else if offlineSign { |
|
|
|
|
return 0, errors.New("nonce value must be specified when offline sign") |
|
|
|
|
} else { |
|
|
|
|
return transaction.GetNextPendingNonce(addr, messenger), nil |
|
|
|
|
} |
|
|
|
@ -327,6 +339,10 @@ func init() { |
|
|
|
|
Create a transaction, sign it, and send off to the Harmony blockchain |
|
|
|
|
`, |
|
|
|
|
PreRunE: func(cmd *cobra.Command, args []string) error { |
|
|
|
|
if offlineSign { |
|
|
|
|
dryRun = true |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if givenFilePath == "" { |
|
|
|
|
for _, flagName := range [...]string{"from", "to", "amount", "from-shard", "to-shard"} { |
|
|
|
|
_ = cmd.MarkFlagRequired(flagName) |
|
|
|
@ -360,7 +376,7 @@ Create a transaction, sign it, and send off to the Harmony blockchain |
|
|
|
|
passphrase = pp // needed for passphrase assignment used in handler
|
|
|
|
|
txLog := transactionLog{} |
|
|
|
|
err = handlerForTransaction(&txLog) |
|
|
|
|
fmt.Println(common.ToJSONUnsafe(txLog, !noPrettyOutput)) |
|
|
|
|
fmt.Println(common.ToJSONUnsafe([]transactionLog{txLog}, !noPrettyOutput)) |
|
|
|
|
return err |
|
|
|
|
} else { |
|
|
|
|
hasError := false |
|
|
|
@ -376,7 +392,7 @@ Create a transaction, sign it, and send off to the Harmony blockchain |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
fmt.Println(common.ToJSONUnsafe(txLogs, true)) |
|
|
|
|
fmt.Println(common.ToJSONUnsafe(txLogs, !noPrettyOutput)) |
|
|
|
|
if hasError { |
|
|
|
|
return fmt.Errorf("one or more of your transactions returned an error " + |
|
|
|
|
"-- check the log for more information") |
|
|
|
@ -390,6 +406,7 @@ Create a transaction, sign it, and send off to the Harmony blockchain |
|
|
|
|
cmdTransfer.Flags().Var(&fromAddress, "from", "sender's one address, keystore must exist locally") |
|
|
|
|
cmdTransfer.Flags().Var(&toAddress, "to", "the destination one address") |
|
|
|
|
cmdTransfer.Flags().BoolVar(&dryRun, "dry-run", false, "do not send signed transaction") |
|
|
|
|
cmdTransfer.Flags().BoolVar(&offlineSign, "offline-sign", false, "output offline signing") |
|
|
|
|
cmdTransfer.Flags().BoolVar(&trueNonce, "true-nonce", false, "send transaction with on-chain nonce") |
|
|
|
|
cmdTransfer.Flags().StringVar(&amount, "amount", "0", "amount to send (ONE)") |
|
|
|
|
cmdTransfer.Flags().StringVar(&gasPrice, "gas-price", "1", "gas price to pay (NANO)") |
|
|
|
@ -403,4 +420,86 @@ Create a transaction, sign it, and send off to the Harmony blockchain |
|
|
|
|
cmdTransfer.Flags().StringVar(&passphraseFilePath, "passphrase-file", "", "path to a file containing the passphrase") |
|
|
|
|
|
|
|
|
|
RootCmd.AddCommand(cmdTransfer) |
|
|
|
|
|
|
|
|
|
cmdGetNonce := &cobra.Command{ |
|
|
|
|
Use: "get-nonce", |
|
|
|
|
Short: "Get Nonce From a Account", |
|
|
|
|
Args: cobra.ExactArgs(0), |
|
|
|
|
Long: ` |
|
|
|
|
Get Nonce From a Account |
|
|
|
|
`, |
|
|
|
|
RunE: func(cmd *cobra.Command, args []string) error { |
|
|
|
|
networkHandler, err := handlerForShard(fromShardID, node) |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
nonce := transaction.GetNextPendingNonce(fromAddress.address, networkHandler) |
|
|
|
|
fmt.Printf("nonce is \"%d\"", nonce) |
|
|
|
|
return err |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
cmdGetNonce.Flags().Var(&fromAddress, "from", "sender's one address, keystore must exist locally") |
|
|
|
|
cmdGetNonce.Flags().Uint32Var(&fromShardID, "from-shard", 0, "source shard id") |
|
|
|
|
RootCmd.AddCommand(cmdGetNonce) |
|
|
|
|
|
|
|
|
|
cmdOfflineSignTransfer := &cobra.Command{ |
|
|
|
|
Use: "offline-sign-transfer", |
|
|
|
|
Short: "Send a Offline Signed transaction", |
|
|
|
|
Args: cobra.ExactArgs(0), |
|
|
|
|
Long: ` |
|
|
|
|
Send a offline signed to the Harmony blockchain |
|
|
|
|
`, |
|
|
|
|
PreRunE: func(cmd *cobra.Command, args []string) error { |
|
|
|
|
if givenFilePath == "" { |
|
|
|
|
return fmt.Errorf("must give a offline-signed file") |
|
|
|
|
} |
|
|
|
|
return nil |
|
|
|
|
}, |
|
|
|
|
RunE: func(cmd *cobra.Command, args []string) error { |
|
|
|
|
var txLogs []*transactionLog |
|
|
|
|
|
|
|
|
|
networkHandler, err := handlerForShard(fromShardID, node) |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
openFile, err := os.Open(givenFilePath) |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
defer openFile.Close() |
|
|
|
|
|
|
|
|
|
err = json.NewDecoder(openFile).Decode(&txLogs) |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for _, txLog := range txLogs { |
|
|
|
|
if len(txLog.Errors) > 0 { |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ctrlr := transaction.NewController(networkHandler, nil, nil, *chainName.chainID, opts) |
|
|
|
|
err := ctrlr.ExecuteRawTransaction(txLog.RawTxn) |
|
|
|
|
if handlerForError(txLog, err) != nil { |
|
|
|
|
txLog.Errors = append(txLog.Errors, err.Error()) |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if txHash := ctrlr.TransactionHash(); txHash != nil { |
|
|
|
|
txLog.TxHash = *txHash |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
txLog.Receipt = ctrlr.Receipt()["result"] |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fmt.Println(common.ToJSONUnsafe(txLogs, true)) |
|
|
|
|
return nil |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
cmdOfflineSignTransfer.Flags().Uint32Var(&fromShardID, "from-shard", 0, "source shard id") |
|
|
|
|
RootCmd.AddCommand(cmdOfflineSignTransfer) |
|
|
|
|
} |
|
|
|
|