github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/sdk/bank/msgs.go (about)

     1  package bank
     2  
     3  import (
     4  	"github.com/gnolang/gno/tm2/pkg/amino"
     5  	"github.com/gnolang/gno/tm2/pkg/crypto"
     6  	"github.com/gnolang/gno/tm2/pkg/errors"
     7  	"github.com/gnolang/gno/tm2/pkg/std"
     8  )
     9  
    10  // RouterKey is they name of the bank module
    11  const RouterKey = ModuleName
    12  
    13  // MsgSend - high level transaction of the coin module
    14  type MsgSend struct {
    15  	FromAddress crypto.Address `json:"from_address" yaml:"from_address"`
    16  	ToAddress   crypto.Address `json:"to_address" yaml:"to_address"`
    17  	Amount      std.Coins      `json:"amount" yaml:"amount"`
    18  }
    19  
    20  var _ std.Msg = MsgSend{}
    21  
    22  // NewMsgSend - construct arbitrary multi-in, multi-out send msg.
    23  func NewMsgSend(fromAddr, toAddr crypto.Address, amount std.Coins) MsgSend {
    24  	return MsgSend{FromAddress: fromAddr, ToAddress: toAddr, Amount: amount}
    25  }
    26  
    27  // Route Implements Msg.
    28  func (msg MsgSend) Route() string { return RouterKey }
    29  
    30  // Type Implements Msg.
    31  func (msg MsgSend) Type() string { return "send" }
    32  
    33  // ValidateBasic Implements Msg.
    34  func (msg MsgSend) ValidateBasic() error {
    35  	if msg.FromAddress.IsZero() {
    36  		return std.ErrInvalidAddress("missing sender address")
    37  	}
    38  	if msg.ToAddress.IsZero() {
    39  		return std.ErrInvalidAddress("missing recipient address")
    40  	}
    41  	if !msg.Amount.IsValid() {
    42  		return std.ErrInvalidCoins("send amount is invalid: " + msg.Amount.String())
    43  	}
    44  	if !msg.Amount.IsAllPositive() {
    45  		return std.ErrInsufficientCoins("send amount must be positive")
    46  	}
    47  	return nil
    48  }
    49  
    50  // GetSignBytes Implements Msg.
    51  func (msg MsgSend) GetSignBytes() []byte {
    52  	return std.MustSortJSON(amino.MustMarshalJSON(msg))
    53  }
    54  
    55  // GetSigners Implements Msg.
    56  func (msg MsgSend) GetSigners() []crypto.Address {
    57  	return []crypto.Address{msg.FromAddress}
    58  }
    59  
    60  // MsgMultiSend - high level transaction of the coin module
    61  type MsgMultiSend struct {
    62  	Inputs  []Input  `json:"inputs" yaml:"inputs"`
    63  	Outputs []Output `json:"outputs" yaml:"outputs"`
    64  }
    65  
    66  var _ std.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 "multisend" }
    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  	if len(msg.Outputs) == 0 {
    87  		return ErrNoOutputs()
    88  	}
    89  
    90  	return ValidateInputsOutputs(msg.Inputs, msg.Outputs)
    91  }
    92  
    93  // GetSignBytes Implements Msg.
    94  func (msg MsgMultiSend) GetSignBytes() []byte {
    95  	return std.MustSortJSON(amino.MustMarshalJSON(msg))
    96  }
    97  
    98  // GetSigners Implements Msg.
    99  func (msg MsgMultiSend) GetSigners() []crypto.Address {
   100  	addrs := make([]crypto.Address, len(msg.Inputs))
   101  	for i, in := range msg.Inputs {
   102  		addrs[i] = in.Address
   103  	}
   104  	return addrs
   105  }
   106  
   107  // Input models transaction input
   108  type Input struct {
   109  	Address crypto.Address `json:"address" yaml:"address"`
   110  	Coins   std.Coins      `json:"coins" yaml:"coins"`
   111  }
   112  
   113  // ValidateBasic - validate transaction input
   114  func (in Input) ValidateBasic() error {
   115  	if len(in.Address) == 0 {
   116  		return std.ErrInvalidAddress(in.Address.String())
   117  	}
   118  	if !in.Coins.IsValid() {
   119  		return std.ErrInvalidCoins(in.Coins.String())
   120  	}
   121  	if !in.Coins.IsAllPositive() {
   122  		return std.ErrInvalidCoins(in.Coins.String())
   123  	}
   124  	return nil
   125  }
   126  
   127  // NewInput - create a transaction input, used with MsgMultiSend
   128  func NewInput(addr crypto.Address, coins std.Coins) Input {
   129  	return Input{
   130  		Address: addr,
   131  		Coins:   coins,
   132  	}
   133  }
   134  
   135  // Output models transaction outputs
   136  type Output struct {
   137  	Address crypto.Address `json:"address" yaml:"address"`
   138  	Coins   std.Coins      `json:"coins" yaml:"coins"`
   139  }
   140  
   141  // ValidateBasic - validate transaction output
   142  func (out Output) ValidateBasic() error {
   143  	if len(out.Address) == 0 {
   144  		return std.ErrInvalidAddress(out.Address.String())
   145  	}
   146  	if !out.Coins.IsValid() {
   147  		return std.ErrInvalidCoins(out.Coins.String())
   148  	}
   149  	if !out.Coins.IsAllPositive() {
   150  		return std.ErrInvalidCoins(out.Coins.String())
   151  	}
   152  	return nil
   153  }
   154  
   155  // NewOutput - create a transaction output, used with MsgMultiSend
   156  func NewOutput(addr crypto.Address, coins std.Coins) Output {
   157  	return Output{
   158  		Address: addr,
   159  		Coins:   coins,
   160  	}
   161  }
   162  
   163  // ValidateInputsOutputs validates that each respective input and output is
   164  // valid and that the sum of inputs is equal to the sum of outputs.
   165  func ValidateInputsOutputs(inputs []Input, outputs []Output) error {
   166  	var totalIn, totalOut std.Coins
   167  
   168  	for _, in := range inputs {
   169  		if err := in.ValidateBasic(); err != nil {
   170  			return errors.Wrap(err, "")
   171  		}
   172  		totalIn = totalIn.Add(in.Coins)
   173  	}
   174  
   175  	for _, out := range outputs {
   176  		if err := out.ValidateBasic(); err != nil {
   177  			return errors.Wrap(err, "")
   178  		}
   179  		totalOut = totalOut.Add(out.Coins)
   180  	}
   181  
   182  	// make sure inputs and outputs match
   183  	if !totalIn.IsEqual(totalOut) {
   184  		return ErrInputOutputMismatch()
   185  	}
   186  
   187  	return nil
   188  }