github.com/Finschia/finschia-sdk@v0.48.1/x/gov/types/msgs.go (about) 1 package types 2 3 import ( 4 "fmt" 5 6 "github.com/gogo/protobuf/proto" 7 yaml "gopkg.in/yaml.v2" 8 9 "github.com/Finschia/finschia-sdk/codec/types" 10 sdk "github.com/Finschia/finschia-sdk/types" 11 sdkerrors "github.com/Finschia/finschia-sdk/types/errors" 12 "github.com/Finschia/finschia-sdk/x/gov/codec" 13 ) 14 15 // Governance message types and routes 16 const ( 17 TypeMsgDeposit = "deposit" 18 TypeMsgVote = "vote" 19 TypeMsgVoteWeighted = "weighted_vote" 20 TypeMsgSubmitProposal = "submit_proposal" 21 ) 22 23 var ( 24 _, _, _, _ sdk.Msg = &MsgSubmitProposal{}, &MsgDeposit{}, &MsgVote{}, &MsgVoteWeighted{} 25 _ types.UnpackInterfacesMessage = &MsgSubmitProposal{} 26 ) 27 28 // NewMsgSubmitProposal creates a new MsgSubmitProposal. 29 // 30 //nolint:interfacer 31 func NewMsgSubmitProposal(content Content, initialDeposit sdk.Coins, proposer sdk.AccAddress) (*MsgSubmitProposal, error) { 32 m := &MsgSubmitProposal{ 33 InitialDeposit: initialDeposit, 34 Proposer: proposer.String(), 35 } 36 err := m.SetContent(content) 37 if err != nil { 38 return nil, err 39 } 40 return m, nil 41 } 42 43 func (m *MsgSubmitProposal) GetInitialDeposit() sdk.Coins { return m.InitialDeposit } 44 45 func (m *MsgSubmitProposal) GetProposer() sdk.AccAddress { 46 proposer, _ := sdk.AccAddressFromBech32(m.Proposer) 47 return proposer 48 } 49 50 func (m *MsgSubmitProposal) GetContent() Content { 51 content, ok := m.Content.GetCachedValue().(Content) 52 if !ok { 53 return nil 54 } 55 return content 56 } 57 58 func (m *MsgSubmitProposal) SetInitialDeposit(coins sdk.Coins) { 59 m.InitialDeposit = coins 60 } 61 62 func (m *MsgSubmitProposal) SetProposer(address fmt.Stringer) { 63 m.Proposer = address.String() 64 } 65 66 func (m *MsgSubmitProposal) SetContent(content Content) error { 67 msg, ok := content.(proto.Message) 68 if !ok { 69 return fmt.Errorf("can't proto marshal %T", msg) 70 } 71 any, err := types.NewAnyWithValue(msg) 72 if err != nil { 73 return err 74 } 75 m.Content = any 76 return nil 77 } 78 79 // Route implements Msg 80 func (m MsgSubmitProposal) Route() string { return RouterKey } 81 82 // Type implements Msg 83 func (m MsgSubmitProposal) Type() string { return TypeMsgSubmitProposal } 84 85 // ValidateBasic implements Msg 86 func (m MsgSubmitProposal) ValidateBasic() error { 87 if _, err := sdk.AccAddressFromBech32(m.Proposer); err != nil { 88 return sdkerrors.ErrInvalidAddress.Wrapf("invalid proposer address: %s", err) 89 } 90 if !m.InitialDeposit.IsValid() { 91 return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, m.InitialDeposit.String()) 92 } 93 if m.InitialDeposit.IsAnyNegative() { 94 return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, m.InitialDeposit.String()) 95 } 96 97 content := m.GetContent() 98 if content == nil { 99 return sdkerrors.Wrap(ErrInvalidProposalContent, "missing content") 100 } 101 if !IsValidProposalType(content.ProposalType()) { 102 return sdkerrors.Wrap(ErrInvalidProposalType, content.ProposalType()) 103 } 104 if err := content.ValidateBasic(); err != nil { 105 return err 106 } 107 108 return nil 109 } 110 111 // GetSignBytes implements Msg 112 func (m MsgSubmitProposal) GetSignBytes() []byte { 113 bz := codec.ModuleCdc.MustMarshalJSON(&m) 114 return sdk.MustSortJSON(bz) 115 } 116 117 // GetSigners implements Msg 118 func (m MsgSubmitProposal) GetSigners() []sdk.AccAddress { 119 proposer, _ := sdk.AccAddressFromBech32(m.Proposer) 120 return []sdk.AccAddress{proposer} 121 } 122 123 // String implements the Stringer interface 124 func (m MsgSubmitProposal) String() string { 125 out, _ := yaml.Marshal(m) 126 return string(out) 127 } 128 129 // UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces 130 func (m MsgSubmitProposal) UnpackInterfaces(unpacker types.AnyUnpacker) error { 131 var content Content 132 return unpacker.UnpackAny(m.Content, &content) 133 } 134 135 // NewMsgDeposit creates a new MsgDeposit instance 136 // 137 //nolint:interfacer 138 func NewMsgDeposit(depositor sdk.AccAddress, proposalID uint64, amount sdk.Coins) *MsgDeposit { 139 return &MsgDeposit{proposalID, depositor.String(), amount} 140 } 141 142 // Route implements Msg 143 func (msg MsgDeposit) Route() string { return RouterKey } 144 145 // Type implements Msg 146 func (msg MsgDeposit) Type() string { return TypeMsgDeposit } 147 148 // ValidateBasic implements Msg 149 func (msg MsgDeposit) ValidateBasic() error { 150 if _, err := sdk.AccAddressFromBech32(msg.Depositor); err != nil { 151 return sdkerrors.ErrInvalidAddress.Wrapf("invalid depositor address: %s", err) 152 } 153 if !msg.Amount.IsValid() { 154 return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, msg.Amount.String()) 155 } 156 if msg.Amount.IsAnyNegative() { 157 return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, msg.Amount.String()) 158 } 159 160 return nil 161 } 162 163 // String implements the Stringer interface 164 func (msg MsgDeposit) String() string { 165 out, _ := yaml.Marshal(msg) 166 return string(out) 167 } 168 169 // GetSignBytes implements Msg 170 func (msg MsgDeposit) GetSignBytes() []byte { 171 bz := codec.ModuleCdc.MustMarshalJSON(&msg) 172 return sdk.MustSortJSON(bz) 173 } 174 175 // GetSigners implements Msg 176 func (msg MsgDeposit) GetSigners() []sdk.AccAddress { 177 depositor, _ := sdk.AccAddressFromBech32(msg.Depositor) 178 return []sdk.AccAddress{depositor} 179 } 180 181 // NewMsgVote creates a message to cast a vote on an active proposal 182 // 183 //nolint:interfacer 184 func NewMsgVote(voter sdk.AccAddress, proposalID uint64, option VoteOption) *MsgVote { 185 return &MsgVote{proposalID, voter.String(), option} 186 } 187 188 // Route implements Msg 189 func (msg MsgVote) Route() string { return RouterKey } 190 191 // Type implements Msg 192 func (msg MsgVote) Type() string { return TypeMsgVote } 193 194 // ValidateBasic implements Msg 195 func (msg MsgVote) ValidateBasic() error { 196 if _, err := sdk.AccAddressFromBech32(msg.Voter); err != nil { 197 return sdkerrors.ErrInvalidAddress.Wrapf("invalid voter address: %s", err) 198 } 199 if !ValidVoteOption(msg.Option) { 200 return sdkerrors.Wrap(ErrInvalidVote, msg.Option.String()) 201 } 202 203 return nil 204 } 205 206 // String implements the Stringer interface 207 func (msg MsgVote) String() string { 208 out, _ := yaml.Marshal(msg) 209 return string(out) 210 } 211 212 // GetSignBytes implements Msg 213 func (msg MsgVote) GetSignBytes() []byte { 214 bz := codec.ModuleCdc.MustMarshalJSON(&msg) 215 return sdk.MustSortJSON(bz) 216 } 217 218 // GetSigners implements Msg 219 func (msg MsgVote) GetSigners() []sdk.AccAddress { 220 voter, _ := sdk.AccAddressFromBech32(msg.Voter) 221 return []sdk.AccAddress{voter} 222 } 223 224 // NewMsgVoteWeighted creates a message to cast a vote on an active proposal 225 // 226 //nolint:interfacer 227 func NewMsgVoteWeighted(voter sdk.AccAddress, proposalID uint64, options WeightedVoteOptions) *MsgVoteWeighted { 228 return &MsgVoteWeighted{proposalID, voter.String(), options} 229 } 230 231 // Route implements Msg 232 func (msg MsgVoteWeighted) Route() string { return RouterKey } 233 234 // Type implements Msg 235 func (msg MsgVoteWeighted) Type() string { return TypeMsgVoteWeighted } 236 237 // ValidateBasic implements Msg 238 func (msg MsgVoteWeighted) ValidateBasic() error { 239 if _, err := sdk.AccAddressFromBech32(msg.Voter); err != nil { 240 return sdkerrors.ErrInvalidAddress.Wrapf("invalid voter address: %s", err) 241 } 242 243 if len(msg.Options) == 0 { 244 return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, WeightedVoteOptions(msg.Options).String()) 245 } 246 247 totalWeight := sdk.NewDec(0) 248 usedOptions := make(map[VoteOption]bool) 249 for _, option := range msg.Options { 250 if !ValidWeightedVoteOption(option) { 251 return sdkerrors.Wrap(ErrInvalidVote, option.String()) 252 } 253 totalWeight = totalWeight.Add(option.Weight) 254 if usedOptions[option.Option] { 255 return sdkerrors.Wrap(ErrInvalidVote, "Duplicated vote option") 256 } 257 usedOptions[option.Option] = true 258 } 259 260 if totalWeight.GT(sdk.NewDec(1)) { 261 return sdkerrors.Wrap(ErrInvalidVote, "Total weight overflow 1.00") 262 } 263 264 if totalWeight.LT(sdk.NewDec(1)) { 265 return sdkerrors.Wrap(ErrInvalidVote, "Total weight lower than 1.00") 266 } 267 268 return nil 269 } 270 271 // String implements the Stringer interface 272 func (msg MsgVoteWeighted) String() string { 273 out, _ := yaml.Marshal(msg) 274 return string(out) 275 } 276 277 // GetSignBytes implements Msg 278 func (msg MsgVoteWeighted) GetSignBytes() []byte { 279 bz := codec.ModuleCdc.MustMarshalJSON(&msg) 280 return sdk.MustSortJSON(bz) 281 } 282 283 // GetSigners implements Msg 284 func (msg MsgVoteWeighted) GetSigners() []sdk.AccAddress { 285 voter, _ := sdk.AccAddressFromBech32(msg.Voter) 286 return []sdk.AccAddress{voter} 287 }