github.com/KiraCore/sekai@v0.3.43/x/gov/keeper/proposal.go (about) 1 package keeper 2 3 import ( 4 "time" 5 6 sdk "github.com/cosmos/cosmos-sdk/types" 7 8 "github.com/KiraCore/sekai/x/gov/types" 9 ) 10 11 func (k Keeper) GetNextProposalIDAndIncrement(ctx sdk.Context) uint64 { 12 proposalID := k.GetNextProposalID(ctx) 13 k.SetNextProposalID(ctx, proposalID+1) 14 return proposalID 15 } 16 17 func (k Keeper) GetNextProposalID(ctx sdk.Context) uint64 { 18 store := ctx.KVStore(k.storeKey) 19 20 bz := store.Get(NextProposalIDPrefix) 21 if bz == nil { 22 return 1 23 } 24 25 proposalID := BytesToProposalID(bz) 26 return proposalID 27 } 28 29 func (k Keeper) SetNextProposalID(ctx sdk.Context, proposalID uint64) { 30 store := ctx.KVStore(k.storeKey) 31 store.Set(NextProposalIDPrefix, ProposalIDToBytes(proposalID)) 32 } 33 34 func (k Keeper) CreateAndSaveProposalWithContent(ctx sdk.Context, title, description string, content types.Content) (uint64, error) { 35 blockTime := ctx.BlockTime() 36 proposalID := k.GetNextProposalIDAndIncrement(ctx) 37 38 properties := k.GetNetworkProperties(ctx) 39 40 // dynamic proposal end time based on proposal type 41 proposalEndTime := k.GetProposalDuration(ctx, content.ProposalType()) 42 if proposalEndTime < properties.MinimumProposalEndTime { 43 proposalEndTime = properties.MinimumProposalEndTime 44 } 45 46 proposalEnactmentTime := properties.ProposalEnactmentTime 47 48 if content.VotePermission() == types.PermZero { 49 router := k.GetProposalRouter() 50 proposalEndTime = router.VotePeriodDynamicProposal(ctx, content) 51 proposalEnactmentTime = router.EnactmentPeriodDynamicProposal(ctx, content) 52 } 53 54 proposal, err := types.NewProposal( 55 proposalID, 56 title, 57 description, 58 content, 59 blockTime, 60 blockTime.Add(time.Second*time.Duration(proposalEndTime)), 61 blockTime.Add(time.Second*time.Duration(proposalEndTime)+ 62 time.Second*time.Duration(proposalEnactmentTime), 63 ), 64 ctx.BlockHeight()+int64(properties.MinProposalEndBlocks), 65 ctx.BlockHeight()+int64(properties.MinProposalEndBlocks+properties.MinProposalEnactmentBlocks), 66 ) 67 68 if err != nil { 69 return proposalID, err 70 } 71 72 k.SaveProposal(ctx, proposal) 73 k.AddToActiveProposals(ctx, proposal) 74 75 return proposalID, nil 76 } 77 78 func (k Keeper) SaveProposal(ctx sdk.Context, proposal types.Proposal) { 79 store := ctx.KVStore(k.storeKey) 80 81 bz := k.cdc.MustMarshal(&proposal) 82 store.Set(GetProposalKey(proposal.ProposalId), bz) 83 } 84 85 func (k Keeper) GetProposal(ctx sdk.Context, proposalID uint64) (types.Proposal, bool) { 86 store := ctx.KVStore(k.storeKey) 87 88 bz := store.Get(GetProposalKey(proposalID)) 89 if bz == nil { 90 return types.Proposal{}, false 91 } 92 93 var prop types.Proposal 94 k.cdc.MustUnmarshal(bz, &prop) 95 96 return prop, true 97 } 98 99 func (k Keeper) GetProposals(ctx sdk.Context) ([]types.Proposal, error) { 100 proposals := []types.Proposal{} 101 iterator := sdk.KVStorePrefixIterator(ctx.KVStore(k.storeKey), ProposalsPrefix) 102 defer iterator.Close() 103 104 for ; iterator.Valid(); iterator.Next() { 105 var proposal types.Proposal 106 bz := iterator.Value() 107 k.cdc.MustUnmarshal(bz, &proposal) 108 proposals = append(proposals, proposal) 109 } 110 111 return proposals, nil 112 } 113 114 func (k Keeper) SaveVote(ctx sdk.Context, vote types.Vote) { 115 store := ctx.KVStore(k.storeKey) 116 bz := k.cdc.MustMarshal(&vote) 117 store.Set(VoteKey(vote.ProposalId, vote.Voter), bz) 118 } 119 120 func (k Keeper) DeleteVote(ctx sdk.Context, vote types.Vote) { 121 store := ctx.KVStore(k.storeKey) 122 store.Delete(VoteKey(vote.ProposalId, vote.Voter)) 123 } 124 125 func (k Keeper) GetVote(ctx sdk.Context, proposalID uint64, address sdk.AccAddress) (types.Vote, bool) { 126 store := ctx.KVStore(k.storeKey) 127 128 bz := store.Get(VoteKey(proposalID, address)) 129 if bz == nil { 130 return types.Vote{}, false 131 } 132 133 var vote types.Vote 134 k.cdc.MustUnmarshal(bz, &vote) 135 136 return vote, true 137 } 138 139 func (k Keeper) GetVotes(ctx sdk.Context) []types.Vote { 140 votes := []types.Vote{} 141 iterator := sdk.KVStorePrefixIterator(ctx.KVStore(k.storeKey), VotesPrefix) 142 defer iterator.Close() 143 144 for ; iterator.Valid(); iterator.Next() { 145 var vote types.Vote 146 bz := iterator.Value() 147 k.cdc.MustUnmarshal(bz, &vote) 148 votes = append(votes, vote) 149 } 150 151 return votes 152 } 153 154 func (k Keeper) GetProposalVotesIterator(ctx sdk.Context, proposalID uint64) sdk.Iterator { 155 store := ctx.KVStore(k.storeKey) 156 return sdk.KVStorePrefixIterator(store, VotesKey(proposalID)) 157 } 158 159 func (k Keeper) GetProposalVotes(ctx sdk.Context, proposalID uint64) types.Votes { 160 var votes types.Votes 161 162 iterator := k.GetProposalVotesIterator(ctx, proposalID) 163 defer iterator.Close() 164 for ; iterator.Valid(); iterator.Next() { 165 var vote types.Vote 166 k.cdc.MustUnmarshal(iterator.Value(), &vote) 167 votes = append(votes, vote) 168 } 169 170 return votes 171 } 172 173 func (k Keeper) GetAverageVotesSlash(ctx sdk.Context, proposalID uint64) sdk.Dec { 174 votes := k.GetProposalVotes(ctx, proposalID) 175 totalSlash := sdk.ZeroDec() 176 totalCount := int64(0) 177 for _, vote := range votes { 178 if vote.Option == types.OptionYes { 179 totalSlash = totalSlash.Add(vote.Slash) 180 totalCount++ 181 } 182 } 183 if totalCount == 0 { 184 return sdk.ZeroDec() 185 } 186 return totalSlash.QuoInt64(totalCount) 187 } 188 189 func (k Keeper) AddToActiveProposals(ctx sdk.Context, proposal types.Proposal) { 190 store := ctx.KVStore(k.storeKey) 191 store.Set(ActiveProposalKey(proposal), ProposalIDToBytes(proposal.ProposalId)) 192 } 193 194 func (k Keeper) RemoveActiveProposal(ctx sdk.Context, proposal types.Proposal) { 195 store := ctx.KVStore(k.storeKey) 196 store.Delete(ActiveProposalKey(proposal)) 197 } 198 199 func (k Keeper) AddToEnactmentProposals(ctx sdk.Context, proposal types.Proposal) { 200 store := ctx.KVStore(k.storeKey) 201 store.Set(EnactmentProposalKey(proposal), ProposalIDToBytes(proposal.ProposalId)) 202 } 203 204 func (k Keeper) RemoveEnactmentProposal(ctx sdk.Context, proposal types.Proposal) { 205 store := ctx.KVStore(k.storeKey) 206 store.Delete(EnactmentProposalKey(proposal)) 207 } 208 209 // GetActiveProposalsWithFinishedVotingEndTimeIterator returns the proposals that have endtime finished. 210 func (k Keeper) GetActiveProposalsWithFinishedVotingEndTimeIterator(ctx sdk.Context, endTime time.Time) sdk.Iterator { 211 store := ctx.KVStore(k.storeKey) 212 return store.Iterator(ActiveProposalsPrefix, sdk.PrefixEndBytes(ActiveProposalByTimeKey(endTime))) 213 } 214 215 // GetEnactmentProposalsWithFinishedEnactmentEndTimeIterator returns the proposals that have finished the enactment time. 216 func (k Keeper) GetEnactmentProposalsWithFinishedEnactmentEndTimeIterator(ctx sdk.Context, endTime time.Time) sdk.Iterator { 217 store := ctx.KVStore(k.storeKey) 218 return store.Iterator(EnactmentProposalsPrefix, sdk.PrefixEndBytes(EnactmentProposalByTimeKey(endTime))) 219 } 220 221 func ActiveProposalByTimeKey(endTime time.Time) []byte { 222 return append(ActiveProposalsPrefix, sdk.FormatTimeBytes(endTime)...) 223 } 224 225 func EnactmentProposalByTimeKey(endTime time.Time) []byte { 226 return append(EnactmentProposalsPrefix, sdk.FormatTimeBytes(endTime)...) 227 } 228 229 func ActiveProposalKey(prop types.Proposal) []byte { 230 return append(ActiveProposalByTimeKey(prop.VotingEndTime), ProposalIDToBytes(prop.ProposalId)...) 231 } 232 233 func EnactmentProposalKey(prop types.Proposal) []byte { 234 return append(EnactmentProposalByTimeKey(prop.EnactmentEndTime), ProposalIDToBytes(prop.ProposalId)...) 235 } 236 237 func VotesKey(proposalID uint64) []byte { 238 return append(VotesPrefix, ProposalIDToBytes(proposalID)...) 239 } 240 241 func VoteKey(proposalId uint64, address sdk.AccAddress) []byte { 242 return append(VotesKey(proposalId), address.Bytes()...) 243 } 244 245 func GetProposalKey(proposalID uint64) []byte { 246 return append(ProposalsPrefix, ProposalIDToBytes(proposalID)...) 247 }