github.com/Finschia/finschia-sdk@v0.48.1/x/bank/types/msgs.go (about)

     1  package types
     2  
     3  import (
     4  	sdk "github.com/Finschia/finschia-sdk/types"
     5  	sdkerrors "github.com/Finschia/finschia-sdk/types/errors"
     6  )
     7  
     8  // bank message types
     9  const (
    10  	TypeMsgSend      = "send"
    11  	TypeMsgMultiSend = "multisend"
    12  )
    13  
    14  var _ sdk.Msg = &MsgSend{}
    15  
    16  // NewMsgSend - construct a msg to send coins from one account to another.
    17  //
    18  //nolint:interfacer
    19  func NewMsgSend(fromAddr, toAddr sdk.AccAddress, amount sdk.Coins) *MsgSend {
    20  	return &MsgSend{FromAddress: fromAddr.String(), ToAddress: toAddr.String(), Amount: amount}
    21  }
    22  
    23  // Route Implements Msg.
    24  func (msg MsgSend) Route() string { return RouterKey }
    25  
    26  // Type Implements Msg.
    27  func (msg MsgSend) Type() string { return TypeMsgSend }
    28  
    29  // ValidateBasic Implements Msg.
    30  func (msg MsgSend) ValidateBasic() error {
    31  	_, err := sdk.AccAddressFromBech32(msg.FromAddress)
    32  	if err != nil {
    33  		return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "Invalid sender address (%s)", err)
    34  	}
    35  
    36  	_, err = sdk.AccAddressFromBech32(msg.ToAddress)
    37  	if err != nil {
    38  		return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "Invalid recipient address (%s)", err)
    39  	}
    40  
    41  	if !msg.Amount.IsValid() {
    42  		return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, msg.Amount.String())
    43  	}
    44  
    45  	if !msg.Amount.IsAllPositive() {
    46  		return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, msg.Amount.String())
    47  	}
    48  
    49  	return nil
    50  }
    51  
    52  // GetSignBytes Implements Msg.
    53  func (msg MsgSend) GetSignBytes() []byte {
    54  	return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&msg))
    55  }
    56  
    57  // GetSigners Implements Msg.
    58  func (msg MsgSend) GetSigners() []sdk.AccAddress {
    59  	from, err := sdk.AccAddressFromBech32(msg.FromAddress)
    60  	if err != nil {
    61  		panic(err)
    62  	}
    63  	return []sdk.AccAddress{from}
    64  }
    65  
    66  var _ sdk.Msg = &MsgMultiSend{}
    67  
    68  // NewMsgMultiSend - construct arbitrary multi-in, multi-out send msg.
    69  func NewMsgMultiSend(in []Input, out []Output) *MsgMultiSend {
    70  	return &MsgMultiSend{Inputs: in, Outputs: out}
    71  }
    72  
    73  // Route Implements Msg
    74  func (msg MsgMultiSend) Route() string { return RouterKey }
    75  
    76  // Type Implements Msg
    77  func (msg MsgMultiSend) Type() string { return TypeMsgMultiSend }
    78  
    79  // ValidateBasic Implements Msg.
    80  func (msg MsgMultiSend) ValidateBasic() error {
    81  	// this just makes sure all the inputs and outputs are properly formatted,
    82  	// not that they actually have the money inside
    83  	if len(msg.Inputs) == 0 {
    84  		return ErrNoInputs
    85  	}
    86  
    87  	if len(msg.Outputs) == 0 {
    88  		return ErrNoOutputs
    89  	}
    90  
    91  	return ValidateInputsOutputs(msg.Inputs, msg.Outputs)
    92  }
    93  
    94  // GetSignBytes Implements Msg.
    95  func (msg MsgMultiSend) GetSignBytes() []byte {
    96  	return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&msg))
    97  }
    98  
    99  // GetSigners Implements Msg.
   100  func (msg MsgMultiSend) GetSigners() []sdk.AccAddress {
   101  	addrs := make([]sdk.AccAddress, len(msg.Inputs))
   102  	for i, in := range msg.Inputs {
   103  		addr := sdk.MustAccAddressFromBech32(in.Address)
   104  		addrs[i] = addr
   105  	}
   106  
   107  	return addrs
   108  }
   109  
   110  // ValidateBasic - validate transaction input
   111  func (in Input) ValidateBasic() error {
   112  	_, err := sdk.AccAddressFromBech32(in.Address)
   113  	if err != nil {
   114  		return err
   115  	}
   116  
   117  	if !in.Coins.IsValid() {
   118  		return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, in.Coins.String())
   119  	}
   120  
   121  	if !in.Coins.IsAllPositive() {
   122  		return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, in.Coins.String())
   123  	}
   124  
   125  	return nil
   126  }
   127  
   128  // NewInput - create a transaction input, used with MsgMultiSend
   129  //
   130  //nolint:interfacer
   131  func NewInput(addr sdk.AccAddress, coins sdk.Coins) Input {
   132  	return Input{
   133  		Address: addr.String(),
   134  		Coins:   coins,
   135  	}
   136  }
   137  
   138  // ValidateBasic - validate transaction output
   139  func (out Output) ValidateBasic() error {
   140  	_, err := sdk.AccAddressFromBech32(out.Address)
   141  	if err != nil {
   142  		return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "Invalid output address (%s)", err)
   143  	}
   144  
   145  	if !out.Coins.IsValid() {
   146  		return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, out.Coins.String())
   147  	}
   148  
   149  	if !out.Coins.IsAllPositive() {
   150  		return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, out.Coins.String())
   151  	}
   152  
   153  	return nil
   154  }
   155  
   156  // NewOutput - create a transaction output, used with MsgMultiSend
   157  //
   158  //nolint:interfacer
   159  func NewOutput(addr sdk.AccAddress, coins sdk.Coins) Output {
   160  	return Output{
   161  		Address: addr.String(),
   162  		Coins:   coins,
   163  	}
   164  }
   165  
   166  // ValidateInputsOutputs validates that each respective input and output is
   167  // valid and that the sum of inputs is equal to the sum of outputs.
   168  func ValidateInputsOutputs(inputs []Input, outputs []Output) error {
   169  	var totalIn, totalOut sdk.Coins
   170  
   171  	for _, in := range inputs {
   172  		if err := in.ValidateBasic(); err != nil {
   173  			return err
   174  		}
   175  
   176  		totalIn = totalIn.Add(in.Coins...)
   177  	}
   178  
   179  	for _, out := range outputs {
   180  		if err := out.ValidateBasic(); err != nil {
   181  			return err
   182  		}
   183  
   184  		totalOut = totalOut.Add(out.Coins...)
   185  	}
   186  
   187  	// make sure inputs and outputs match
   188  	if !totalIn.IsEqual(totalOut) {
   189  		return ErrInputOutputMismatch
   190  	}
   191  
   192  	return nil
   193  }