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  }