package gov import ( "encoding/json" "fmt" "time" "github.com/pkg/errors" sdk "github.com/cosmos/cosmos-sdk/types" ) //----------------------------------------------------------- // Proposal interface type Proposal interface { GetProposalID() uint64 SetProposalID(uint64) GetTitle() string SetTitle(string) GetDescription() string SetDescription(string) GetProposalType() ProposalKind SetProposalType(ProposalKind) GetStatus() ProposalStatus SetStatus(ProposalStatus) GetTallyResult() TallyResult SetTallyResult(TallyResult) GetSubmitTime() time.Time SetSubmitTime(time.Time) GetDepositEndTime() time.Time SetDepositEndTime(time.Time) GetTotalDeposit() sdk.Coins SetTotalDeposit(sdk.Coins) GetVotingStartTime() time.Time SetVotingStartTime(time.Time) GetVotingEndTime() time.Time SetVotingEndTime(time.Time) } // checks if two proposals are equal func ProposalEqual(proposalA Proposal, proposalB Proposal) bool { if proposalA.GetProposalID() == proposalB.GetProposalID() && proposalA.GetTitle() == proposalB.GetTitle() && proposalA.GetDescription() == proposalB.GetDescription() && proposalA.GetProposalType() == proposalB.GetProposalType() && proposalA.GetStatus() == proposalB.GetStatus() && proposalA.GetTallyResult().Equals(proposalB.GetTallyResult()) && proposalA.GetSubmitTime().Equal(proposalB.GetSubmitTime()) && proposalA.GetDepositEndTime().Equal(proposalB.GetDepositEndTime()) && proposalA.GetTotalDeposit().IsEqual(proposalB.GetTotalDeposit()) && proposalA.GetVotingStartTime().Equal(proposalB.GetVotingStartTime()) && proposalA.GetVotingEndTime().Equal(proposalB.GetVotingEndTime()) { return true } return false } //----------------------------------------------------------- // Text Proposals type TextProposal struct { ProposalID uint64 `json:"proposal_id"` // ID of the proposal Title string `json:"title"` // Title of the proposal Description string `json:"description"` // Description of the proposal ProposalType ProposalKind `json:"proposal_type"` // Type of proposal. Initial set {PlainTextProposal, SoftwareUpgradeProposal} Status ProposalStatus `json:"proposal_status"` // Status of the Proposal {Pending, Active, Passed, Rejected} TallyResult TallyResult `json:"tally_result"` // Result of Tallys SubmitTime time.Time `json:"submit_time"` // Time of the block where TxGovSubmitProposal was included DepositEndTime time.Time `json:"deposit_end_time"` // Time that the Proposal would expire if deposit amount isn't met TotalDeposit sdk.Coins `json:"total_deposit"` // Current deposit on this proposal. Initial value is set at InitialDeposit VotingStartTime time.Time `json:"voting_start_time"` // Time of the block where MinDeposit was reached. -1 if MinDeposit is not reached VotingEndTime time.Time `json:"voting_end_time"` // Time that the VotingPeriod for this proposal will end and votes will be tallied } // Implements Proposal Interface var _ Proposal = (*TextProposal)(nil) // nolint func (tp TextProposal) GetProposalID() uint64 { return tp.ProposalID } func (tp *TextProposal) SetProposalID(proposalID uint64) { tp.ProposalID = proposalID } func (tp TextProposal) GetTitle() string { return tp.Title } func (tp *TextProposal) SetTitle(title string) { tp.Title = title } func (tp TextProposal) GetDescription() string { return tp.Description } func (tp *TextProposal) SetDescription(description string) { tp.Description = description } func (tp TextProposal) GetProposalType() ProposalKind { return tp.ProposalType } func (tp *TextProposal) SetProposalType(proposalType ProposalKind) { tp.ProposalType = proposalType } func (tp TextProposal) GetStatus() ProposalStatus { return tp.Status } func (tp *TextProposal) SetStatus(status ProposalStatus) { tp.Status = status } func (tp TextProposal) GetTallyResult() TallyResult { return tp.TallyResult } func (tp *TextProposal) SetTallyResult(tallyResult TallyResult) { tp.TallyResult = tallyResult } func (tp TextProposal) GetSubmitTime() time.Time { return tp.SubmitTime } func (tp *TextProposal) SetSubmitTime(submitTime time.Time) { tp.SubmitTime = submitTime } func (tp TextProposal) GetDepositEndTime() time.Time { return tp.DepositEndTime } func (tp *TextProposal) SetDepositEndTime(depositEndTime time.Time) { tp.DepositEndTime = depositEndTime } func (tp TextProposal) GetTotalDeposit() sdk.Coins { return tp.TotalDeposit } func (tp *TextProposal) SetTotalDeposit(totalDeposit sdk.Coins) { tp.TotalDeposit = totalDeposit } func (tp TextProposal) GetVotingStartTime() time.Time { return tp.VotingStartTime } func (tp *TextProposal) SetVotingStartTime(votingStartTime time.Time) { tp.VotingStartTime = votingStartTime } func (tp TextProposal) GetVotingEndTime() time.Time { return tp.VotingEndTime } func (tp *TextProposal) SetVotingEndTime(votingEndTime time.Time) { tp.VotingEndTime = votingEndTime } //----------------------------------------------------------- // ProposalQueue type ProposalQueue []uint64 //----------------------------------------------------------- // ProposalKind // Type that represents Proposal Type as a byte type ProposalKind byte //nolint const ( ProposalTypeNil ProposalKind = 0x00 ProposalTypeText ProposalKind = 0x01 ProposalTypeParameterChange ProposalKind = 0x02 ProposalTypeSoftwareUpgrade ProposalKind = 0x03 ) // String to proposalType byte. Returns ff if invalid. func ProposalTypeFromString(str string) (ProposalKind, error) { switch str { case "Text": return ProposalTypeText, nil case "ParameterChange": return ProposalTypeParameterChange, nil case "SoftwareUpgrade": return ProposalTypeSoftwareUpgrade, nil default: return ProposalKind(0xff), errors.Errorf("'%s' is not a valid proposal type", str) } } // is defined ProposalType? func validProposalType(pt ProposalKind) bool { if pt == ProposalTypeText || pt == ProposalTypeParameterChange || pt == ProposalTypeSoftwareUpgrade { return true } return false } // Marshal needed for protobuf compatibility func (pt ProposalKind) Marshal() ([]byte, error) { return []byte{byte(pt)}, nil } // Unmarshal needed for protobuf compatibility func (pt *ProposalKind) Unmarshal(data []byte) error { *pt = ProposalKind(data[0]) return nil } // Marshals to JSON using string func (pt ProposalKind) MarshalJSON() ([]byte, error) { return json.Marshal(pt.String()) } // Unmarshals from JSON assuming Bech32 encoding func (pt *ProposalKind) UnmarshalJSON(data []byte) error { var s string err := json.Unmarshal(data, &s) if err != nil { return nil } bz2, err := ProposalTypeFromString(s) if err != nil { return err } *pt = bz2 return nil } // Turns VoteOption byte to String func (pt ProposalKind) String() string { switch pt { case ProposalTypeText: return "Text" case ProposalTypeParameterChange: return "ParameterChange" case ProposalTypeSoftwareUpgrade: return "SoftwareUpgrade" default: return "" } } // For Printf / Sprintf, returns bech32 when using %s // nolint: errcheck func (pt ProposalKind) Format(s fmt.State, verb rune) { switch verb { case 's': s.Write([]byte(pt.String())) default: // TODO: Do this conversion more directly s.Write([]byte(fmt.Sprintf("%v", byte(pt)))) } } //----------------------------------------------------------- // ProposalStatus // Type that represents Proposal Status as a byte type ProposalStatus byte //nolint const ( StatusNil ProposalStatus = 0x00 StatusDepositPeriod ProposalStatus = 0x01 StatusVotingPeriod ProposalStatus = 0x02 StatusPassed ProposalStatus = 0x03 StatusRejected ProposalStatus = 0x04 ) // ProposalStatusToString turns a string into a ProposalStatus func ProposalStatusFromString(str string) (ProposalStatus, error) { switch str { case "DepositPeriod": return StatusDepositPeriod, nil case "VotingPeriod": return StatusVotingPeriod, nil case "Passed": return StatusPassed, nil case "Rejected": return StatusRejected, nil case "": return StatusNil, nil default: return ProposalStatus(0xff), errors.Errorf("'%s' is not a valid proposal status", str) } } // is defined ProposalType? func validProposalStatus(status ProposalStatus) bool { if status == StatusDepositPeriod || status == StatusVotingPeriod || status == StatusPassed || status == StatusRejected { return true } return false } // Marshal needed for protobuf compatibility func (status ProposalStatus) Marshal() ([]byte, error) { return []byte{byte(status)}, nil } // Unmarshal needed for protobuf compatibility func (status *ProposalStatus) Unmarshal(data []byte) error { *status = ProposalStatus(data[0]) return nil } // Marshals to JSON using string func (status ProposalStatus) MarshalJSON() ([]byte, error) { return json.Marshal(status.String()) } // Unmarshals from JSON assuming Bech32 encoding func (status *ProposalStatus) UnmarshalJSON(data []byte) error { var s string err := json.Unmarshal(data, &s) if err != nil { return nil } bz2, err := ProposalStatusFromString(s) if err != nil { return err } *status = bz2 return nil } // Turns VoteStatus byte to String func (status ProposalStatus) String() string { switch status { case StatusDepositPeriod: return "DepositPeriod" case StatusVotingPeriod: return "VotingPeriod" case StatusPassed: return "Passed" case StatusRejected: return "Rejected" default: return "" } } // For Printf / Sprintf, returns bech32 when using %s // nolint: errcheck func (status ProposalStatus) Format(s fmt.State, verb rune) { switch verb { case 's': s.Write([]byte(status.String())) default: // TODO: Do this conversion more directly s.Write([]byte(fmt.Sprintf("%v", byte(status)))) } } //----------------------------------------------------------- // Tally Results type TallyResult struct { Yes sdk.Dec `json:"yes"` Abstain sdk.Dec `json:"abstain"` No sdk.Dec `json:"no"` NoWithVeto sdk.Dec `json:"no_with_veto"` } // checks if two proposals are equal func EmptyTallyResult() TallyResult { return TallyResult{ Yes: sdk.ZeroDec(), Abstain: sdk.ZeroDec(), No: sdk.ZeroDec(), NoWithVeto: sdk.ZeroDec(), } } // checks if two proposals are equal func (resultA TallyResult) Equals(resultB TallyResult) bool { return (resultA.Yes.Equal(resultB.Yes) && resultA.Abstain.Equal(resultB.Abstain) && resultA.No.Equal(resultB.No) && resultA.NoWithVeto.Equal(resultB.NoWithVeto)) }