github.com/Finschia/finschia-sdk@v0.49.1/x/auth/client/tx.go (about)

     1  package client
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"fmt"
     7  	"io"
     8  	"os"
     9  	"strings"
    10  
    11  	"github.com/gogo/protobuf/jsonpb"
    12  
    13  	"github.com/Finschia/finschia-sdk/client"
    14  	"github.com/Finschia/finschia-sdk/client/tx"
    15  	"github.com/Finschia/finschia-sdk/codec"
    16  	"github.com/Finschia/finschia-sdk/crypto/keyring"
    17  	sdk "github.com/Finschia/finschia-sdk/types"
    18  	sdkerrors "github.com/Finschia/finschia-sdk/types/errors"
    19  	"github.com/Finschia/finschia-sdk/types/tx/signing"
    20  	"github.com/Finschia/finschia-sdk/x/auth/legacy/legacytx"
    21  )
    22  
    23  // GasEstimateResponse defines a response definition for tx gas estimation.
    24  type GasEstimateResponse struct {
    25  	GasEstimate uint64 `json:"gas_estimate" yaml:"gas_estimate"`
    26  }
    27  
    28  func (gr GasEstimateResponse) String() string {
    29  	return fmt.Sprintf("gas estimate: %d", gr.GasEstimate)
    30  }
    31  
    32  // PrintUnsignedStdTx builds an unsigned StdTx and prints it to os.Stdout.
    33  func PrintUnsignedStdTx(txBldr tx.Factory, clientCtx client.Context, msgs []sdk.Msg) error {
    34  	err := tx.GenerateTx(clientCtx, txBldr, msgs...)
    35  	return err
    36  }
    37  
    38  // SignTx signs a transaction managed by the TxBuilder using a `name` key stored in Keybase.
    39  // The new signature is appended to the TxBuilder when overwrite=false or overwritten otherwise.
    40  // Don't perform online validation or lookups if offline is true.
    41  func SignTx(txFactory tx.Factory, clientCtx client.Context, name string, txBuilder client.TxBuilder, offline, overwriteSig bool) error {
    42  	info, err := txFactory.Keybase().Key(name)
    43  	if err != nil {
    44  		return err
    45  	}
    46  
    47  	// Ledger and Multisigs only support LEGACY_AMINO_JSON signing.
    48  	if txFactory.SignMode() == signing.SignMode_SIGN_MODE_UNSPECIFIED &&
    49  		(info.GetType() == keyring.TypeLedger || info.GetType() == keyring.TypeMulti) {
    50  		txFactory = txFactory.WithSignMode(signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON)
    51  	}
    52  
    53  	addr := sdk.AccAddress(info.GetPubKey().Address())
    54  	if !isTxSigner(addr, txBuilder.GetTx().GetSigners()) {
    55  		return fmt.Errorf("%w: %s", sdkerrors.ErrorInvalidSigner, name)
    56  	}
    57  	if !offline {
    58  		txFactory, err = populateAccountFromState(txFactory, clientCtx, addr)
    59  		if err != nil {
    60  			return err
    61  		}
    62  	}
    63  
    64  	return tx.Sign(txFactory, name, txBuilder, overwriteSig)
    65  }
    66  
    67  // SignTxWithSignerAddress attaches a signature to a transaction.
    68  // Don't perform online validation or lookups if offline is true, else
    69  // populate account and sequence numbers from a foreign account.
    70  // This function should only be used when signing with a multisig. For
    71  // normal keys, please use SignTx directly.
    72  func SignTxWithSignerAddress(txFactory tx.Factory, clientCtx client.Context, addr sdk.AccAddress,
    73  	name string, txBuilder client.TxBuilder, offline, overwrite bool,
    74  ) (err error) {
    75  	// Multisigs only support LEGACY_AMINO_JSON signing.
    76  	if txFactory.SignMode() == signing.SignMode_SIGN_MODE_UNSPECIFIED {
    77  		txFactory = txFactory.WithSignMode(signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON)
    78  	}
    79  
    80  	// check whether the address is a signer
    81  	if !isTxSigner(addr, txBuilder.GetTx().GetSigners()) {
    82  		return fmt.Errorf("%w: %s", sdkerrors.ErrorInvalidSigner, name)
    83  	}
    84  
    85  	if !offline {
    86  		txFactory, err = populateAccountFromState(txFactory, clientCtx, addr)
    87  		if err != nil {
    88  			return err
    89  		}
    90  	}
    91  
    92  	return tx.Sign(txFactory, name, txBuilder, overwrite)
    93  }
    94  
    95  // Read and decode a StdTx from the given filename.  Can pass "-" to read from stdin.
    96  func ReadTxFromFile(ctx client.Context, filename string) (tx sdk.Tx, err error) {
    97  	var bytes []byte
    98  
    99  	if filename == "-" {
   100  		bytes, err = io.ReadAll(os.Stdin)
   101  	} else {
   102  		bytes, err = os.ReadFile(filename)
   103  	}
   104  
   105  	if err != nil {
   106  		return
   107  	}
   108  
   109  	return ctx.TxConfig.TxJSONDecoder()(bytes)
   110  }
   111  
   112  // NewBatchScanner returns a new BatchScanner to read newline-delimited StdTx transactions from r.
   113  func NewBatchScanner(cfg client.TxConfig, r io.Reader) *BatchScanner {
   114  	return &BatchScanner{Scanner: bufio.NewScanner(r), cfg: cfg}
   115  }
   116  
   117  // BatchScanner provides a convenient interface for reading batch data such as a file
   118  // of newline-delimited JSON encoded StdTx.
   119  type BatchScanner struct {
   120  	*bufio.Scanner
   121  	theTx        sdk.Tx
   122  	cfg          client.TxConfig
   123  	unmarshalErr error
   124  }
   125  
   126  // Tx returns the most recent Tx unmarshalled by a call to Scan.
   127  func (bs BatchScanner) Tx() sdk.Tx { return bs.theTx }
   128  
   129  // UnmarshalErr returns the first unmarshalling error that was encountered by the scanner.
   130  func (bs BatchScanner) UnmarshalErr() error { return bs.unmarshalErr }
   131  
   132  // Scan advances the Scanner to the next line.
   133  func (bs *BatchScanner) Scan() bool {
   134  	if !bs.Scanner.Scan() {
   135  		return false
   136  	}
   137  
   138  	tx, err := bs.cfg.TxJSONDecoder()(bs.Bytes())
   139  	bs.theTx = tx
   140  	if err != nil && bs.unmarshalErr == nil {
   141  		bs.unmarshalErr = err
   142  		return false
   143  	}
   144  
   145  	return true
   146  }
   147  
   148  func populateAccountFromState(
   149  	txBldr tx.Factory, clientCtx client.Context, addr sdk.AccAddress,
   150  ) (tx.Factory, error) {
   151  	num, seq, err := clientCtx.AccountRetriever.GetAccountNumberSequence(clientCtx, addr)
   152  	if err != nil {
   153  		return txBldr, err
   154  	}
   155  
   156  	return txBldr.WithAccountNumber(num).WithSequence(seq), nil
   157  }
   158  
   159  // GetTxEncoder return tx encoder from global sdk configuration if ones is defined.
   160  // Otherwise returns encoder with default logic.
   161  func GetTxEncoder(cdc *codec.LegacyAmino) (encoder sdk.TxEncoder) {
   162  	encoder = sdk.GetConfig().GetTxEncoder()
   163  	if encoder == nil {
   164  		encoder = legacytx.DefaultTxEncoder(cdc)
   165  	}
   166  
   167  	return encoder
   168  }
   169  
   170  func ParseQueryResponse(bz []byte) (sdk.SimulationResponse, error) {
   171  	var simRes sdk.SimulationResponse
   172  	if err := jsonpb.Unmarshal(strings.NewReader(string(bz)), &simRes); err != nil {
   173  		return sdk.SimulationResponse{}, err
   174  	}
   175  
   176  	return simRes, nil
   177  }
   178  
   179  func isTxSigner(user sdk.AccAddress, signers []sdk.AccAddress) bool {
   180  	for _, s := range signers {
   181  		if bytes.Equal(user.Bytes(), s.Bytes()) {
   182  			return true
   183  		}
   184  	}
   185  
   186  	return false
   187  }