Svarog 639183ba0e
Add support for auto-compound in kaspawallet send (#1951)
* Add GetUTXOsByBalances command to rpc

* Fix wrong commands in GetBalanceByAddress

* Moved calculation of TransactionMass out of TransactionValidator, so t that it can be used in kaspawallet

* Allow CreateUnsignedTransaction to return multiple transactions

* Start working on split

* Implement maybeSplitTransactionInner

* estimateMassIncreaseForSignatures should multiply by the number of inputs

* Implement createSplitTransaction

* Implement mergeTransactions

* Broadcast all transaction, not only 1

* workaround missing UTXOEntry in partially signed transaction

* Bugfix in broadcast loop

* Add underscores in some constants

* Make all nets RelayNonStdTxs: false

* Change estimateMassIncreaseForSignatures to estimateMassAfterSignatures

* Allow situations where merge transaction doesn't have enough funds to pay fees

* Add comments

* A few of renames

* Handle missed errors

* Fix clone of PubKeySignaturePair  to properly clone nil signatures

* Add sanity check to make sure originalTransaction has exactly two outputs

* Re-use change address for splitAddress

* Add one more utxo if the total amount is smaller then what we need to send due to fees

* Fix off-by-1 error in splitTrasnaction

* Add a comment to maybeAutoCompoundTransaction

* Add comment on why we are increasing inputCountPerSplit

* Add comment explaining while originalTransaction has 1 or 2 outputs

* Move oneMoreUTXOForMergeTransaction to split_transaction.go

* Allow to add multiple utxos to pay fee for mergeTransactions, if needed

* calculate split input counts and sizes properly

* Allow multiple transactions inside the create-unsigned-transaction -> sign -> broadcast workflow

* Print the number of transaction which was sent, in case there were multiple

* Rename broadcastConfig.Transaction(File) to Transactions(File)

* Convert alreadySelectedUTXOs to a map

* Fix a typo

* Add comment explaining that we assume all inputs are the same

* Revert over-refactor of rename of config.Transaction -> config.Transactions

* Rename: inputPerSplitCount -> inputsPerSplitCount

* Add comment for splitAndInputPerSplitCounts

* Use createSplitTransaction to calculate the upper bound of mass for split transactions
2022-03-27 20:06:55 +03:00

83 lines
2.3 KiB
Go

package main
import (
"context"
"fmt"
"github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/client"
"github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/pb"
"github.com/kaspanet/kaspad/cmd/kaspawallet/keys"
"github.com/kaspanet/kaspad/cmd/kaspawallet/libkaspawallet"
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
"github.com/pkg/errors"
)
func send(conf *sendConfig) error {
keysFile, err := keys.ReadKeysFile(conf.NetParams(), conf.KeysFile)
if err != nil {
return err
}
if len(keysFile.ExtendedPublicKeys) > len(keysFile.EncryptedMnemonics) {
return errors.Errorf("Cannot use 'send' command for multisig wallet without all of the keys")
}
daemonClient, tearDown, err := client.Connect(conf.DaemonAddress)
if err != nil {
return err
}
defer tearDown()
ctx, cancel := context.WithTimeout(context.Background(), daemonTimeout)
defer cancel()
sendAmountSompi := uint64(conf.SendAmount * constants.SompiPerKaspa)
createUnsignedTransactionsResponse, err :=
daemonClient.CreateUnsignedTransactions(ctx, &pb.CreateUnsignedTransactionsRequest{
Address: conf.ToAddress,
Amount: sendAmountSompi,
})
if err != nil {
return err
}
mnemonics, err := keysFile.DecryptMnemonics(conf.Password)
if err != nil {
return err
}
signedTransactions := make([][]byte, len(createUnsignedTransactionsResponse.UnsignedTransactions))
for i, unsignedTransaction := range createUnsignedTransactionsResponse.UnsignedTransactions {
signedTransaction, err := libkaspawallet.Sign(conf.NetParams(), mnemonics, unsignedTransaction, keysFile.ECDSA)
if err != nil {
return err
}
signedTransactions[i] = signedTransaction
}
if len(signedTransactions) > 1 {
fmt.Printf("Broadcasting %d transactions\n", len(signedTransactions))
}
for _, signedTransaction := range signedTransactions {
err := func() error { // surround with func so that defer runs separately per transaction
ctx2, cancel2 := context.WithTimeout(context.Background(), daemonTimeout)
defer cancel2()
broadcastResponse, err := daemonClient.Broadcast(ctx2, &pb.BroadcastRequest{
Transaction: signedTransaction,
})
if err != nil {
return err
}
fmt.Println("Transaction was sent successfully")
fmt.Printf("Transaction ID: \t%s\n", broadcastResponse.TxID)
return nil
}()
if err != nil {
return err
}
}
return nil
}