Search Apps Documentation Source Content File Folder Download Copy Actions Download

instance.gno

4.87 Kb · 179 lines
  1package v1
  2
  3import (
  4	bptree "gno.land/p/nt/bptree/v0"
  5	ufmt "gno.land/p/nt/ufmt/v0"
  6	"gno.land/r/gnoswap/gov/governance"
  7)
  8
  9type governanceV1 struct {
 10	store          governance.IGovernanceStore
 11	stakerAccessor governance.GovStakerAccessor
 12}
 13
 14func NewGovernanceV1(
 15	governanceStore governance.IGovernanceStore,
 16	stakerAccessor governance.GovStakerAccessor,
 17) governance.IGovernance {
 18	return &governanceV1{
 19		store:          governanceStore,
 20		stakerAccessor: stakerAccessor,
 21	}
 22}
 23
 24// Config version methods
 25func (g *governanceV1) getCurrentConfigVersion() int64 {
 26	return g.store.GetConfigCounter().Get()
 27}
 28
 29// nextConfigVersion increments and persists the config counter. It mutates the
 30// underlying KV store, so it requires a realm value that resolves to the
 31// governance proxy realm (the only writer-permitted address).
 32func (g *governanceV1) nextConfigVersion(_ int, rlm realm) int64 {
 33	counter := g.store.GetConfigCounter()
 34	next := counter.Next()
 35	if err := g.store.SetConfigCounter(0, rlm, counter); err != nil {
 36		panic(err)
 37	}
 38	return next
 39}
 40
 41// Proposal ID methods
 42func (g *governanceV1) getCurrentProposalID() int64 {
 43	return g.store.GetProposalCounter().Get()
 44}
 45
 46// nextProposalID increments and persists the proposal counter. Same realm
 47// rules as nextConfigVersion.
 48func (g *governanceV1) nextProposalID(_ int, rlm realm) int64 {
 49	counter := g.store.GetProposalCounter()
 50	next := counter.Next()
 51	if err := g.store.SetProposalCounter(0, rlm, counter); err != nil {
 52		panic(err)
 53	}
 54	return next
 55}
 56
 57// Config methods
 58func (g *governanceV1) getConfig(version int64) (governance.Config, bool) {
 59	return g.store.GetConfig(version)
 60}
 61
 62func (g *governanceV1) setConfig(_ int, rlm realm, version int64, config governance.Config) error {
 63	return g.store.SetConfig(0, rlm, version, config)
 64}
 65
 66func (g *governanceV1) getCurrentConfig() (governance.Config, bool) {
 67	return g.getConfig(g.getCurrentConfigVersion())
 68}
 69
 70// Proposal methods
 71func (g *governanceV1) getProposal(id int64) (*governance.Proposal, bool) {
 72	proposal, exists := g.store.GetProposal(id)
 73	if !exists {
 74		return nil, false
 75	}
 76
 77	return proposal, true
 78}
 79
 80func (g *governanceV1) addProposal(_ int, rlm realm, proposal *governance.Proposal) bool {
 81	// Set the proposal (ID already set in proposal)
 82	err := g.store.SetProposal(0, rlm, proposal.ID(), proposal)
 83	if err != nil {
 84		return false
 85	}
 86
 87	// Add to user proposals
 88	err = g.store.AddUserProposal(0, rlm, proposal.Proposer().String(), proposal.ID())
 89	if err != nil {
 90		return false
 91	}
 92
 93	return true
 94}
 95
 96// User proposals methods
 97func (g *governanceV1) getUserProposals(user string) []*governance.Proposal {
 98	proposalIDs, exists := g.store.GetUserProposalIDs(user)
 99	if !exists {
100		return []*governance.Proposal{}
101	}
102
103	proposals := make([]*governance.Proposal, 0)
104
105	for _, id := range proposalIDs {
106		proposal, exists := g.store.GetProposal(id)
107		if !exists {
108			continue
109		}
110
111		proposals = append(proposals, proposal)
112	}
113
114	return proposals
115}
116
117// hasActiveProposal assumes removeInactiveUserProposals has already pruned stale proposals.
118func (g *governanceV1) hasActiveProposal(proposerAddress address) bool {
119	proposals := g.getUserProposals(proposerAddress.String())
120
121	return len(proposals) > 0
122}
123
124// Remove inactive user proposals
125// This function is used to remove inactive proposals from the user proposals list.
126// It is used to clean up user's active proposal list when creating a new proposal.
127func (g *governanceV1) removeInactiveUserProposals(_ int, rlm realm, proposerAddress address, current int64) error {
128	proposals := g.getUserProposals(proposerAddress.String())
129
130	for _, proposal := range proposals {
131		proposalResolver := NewProposalResolver(proposal)
132
133		if !proposalResolver.IsActive(current) {
134			err := g.store.RemoveUserProposal(0, rlm, proposerAddress.String(), proposal.ID())
135			if err != nil {
136				return err
137			}
138		}
139	}
140
141	return nil
142}
143
144// Proposal voting info methods
145func (g *governanceV1) getProposalUserVotingInfos(proposalID int64) (*bptree.BPTree, bool) {
146	return g.store.GetProposalVotingInfos(proposalID)
147}
148
149func (g *governanceV1) updateProposalUserVotes(_ int, rlm realm, proposal *governance.Proposal, userVotingInfos *bptree.BPTree) error {
150	return g.store.SetProposalVotingInfos(0, rlm, proposal.ID(), userVotingInfos)
151}
152
153// Helper methods for API
154func (g *governanceV1) mustGetProposal(id int64) *governance.Proposal {
155	proposal, exists := g.getProposal(id)
156	if !exists {
157		panic(makeErrorWithDetails(errProposalNotFound, ufmt.Sprintf("proposal(%d) not found", id)))
158	}
159	return proposal
160}
161
162func (g *governanceV1) getProposalUserVotingInfo(proposalID int64, addr address) (*governance.VotingInfo, bool) {
163	votingInfosTree, exists := g.getProposalUserVotingInfos(proposalID)
164	if !exists {
165		return nil, false
166	}
167
168	votingInfoRaw, exists := votingInfosTree.Get(addr.String())
169	if !exists {
170		return nil, false
171	}
172
173	votingInfo, ok := votingInfoRaw.(*governance.VotingInfo)
174	if !ok {
175		return nil, false
176	}
177
178	return votingInfo, true
179}