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 }