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  }