1use crate::{AccountVote, Conviction, Vote, VoteThreshold};
21use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
22use scale_info::TypeInfo;
23use sp_runtime::{
24 traits::{Bounded, CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, Saturating, Zero},
25 Debug,
26};
27
28pub type PropIndex = u32;
30
31pub type ReferendumIndex = u32;
33
34#[derive(Encode, MaxEncodedLen, Decode, Default, Clone, PartialEq, Eq, Debug, TypeInfo)]
36pub struct Tally<Balance> {
37 pub ayes: Balance,
39 pub nays: Balance,
41 pub turnout: Balance,
43}
44
45#[derive(Encode, MaxEncodedLen, Decode, Default, Copy, Clone, PartialEq, Eq, Debug, TypeInfo)]
47pub struct Delegations<Balance> {
48 pub votes: Balance,
50 pub capital: Balance,
52}
53
54impl<Balance: Saturating> Saturating for Delegations<Balance> {
55 fn saturating_add(self, o: Self) -> Self {
56 Self {
57 votes: self.votes.saturating_add(o.votes),
58 capital: self.capital.saturating_add(o.capital),
59 }
60 }
61
62 fn saturating_sub(self, o: Self) -> Self {
63 Self {
64 votes: self.votes.saturating_sub(o.votes),
65 capital: self.capital.saturating_sub(o.capital),
66 }
67 }
68
69 fn saturating_mul(self, o: Self) -> Self {
70 Self {
71 votes: self.votes.saturating_mul(o.votes),
72 capital: self.capital.saturating_mul(o.capital),
73 }
74 }
75
76 fn saturating_pow(self, exp: usize) -> Self {
77 Self { votes: self.votes.saturating_pow(exp), capital: self.capital.saturating_pow(exp) }
78 }
79}
80
81impl<
82 Balance: From<u8>
83 + Zero
84 + Copy
85 + CheckedAdd
86 + CheckedSub
87 + CheckedMul
88 + CheckedDiv
89 + Bounded
90 + Saturating,
91 > Tally<Balance>
92{
93 pub fn new(vote: Vote, balance: Balance) -> Self {
95 let Delegations { votes, capital } = vote.conviction.votes(balance);
96 Self {
97 ayes: if vote.aye { votes } else { Zero::zero() },
98 nays: if vote.aye { Zero::zero() } else { votes },
99 turnout: capital,
100 }
101 }
102
103 pub fn add(&mut self, vote: AccountVote<Balance>) -> Option<()> {
105 match vote {
106 AccountVote::Standard { vote, balance } => {
107 let Delegations { votes, capital } = vote.conviction.votes(balance);
108 self.turnout = self.turnout.checked_add(&capital)?;
109 match vote.aye {
110 true => self.ayes = self.ayes.checked_add(&votes)?,
111 false => self.nays = self.nays.checked_add(&votes)?,
112 }
113 },
114 AccountVote::Split { aye, nay } => {
115 let aye = Conviction::None.votes(aye);
116 let nay = Conviction::None.votes(nay);
117 self.turnout = self.turnout.checked_add(&aye.capital)?.checked_add(&nay.capital)?;
118 self.ayes = self.ayes.checked_add(&aye.votes)?;
119 self.nays = self.nays.checked_add(&nay.votes)?;
120 },
121 }
122 Some(())
123 }
124
125 pub fn remove(&mut self, vote: AccountVote<Balance>) -> Option<()> {
127 match vote {
128 AccountVote::Standard { vote, balance } => {
129 let Delegations { votes, capital } = vote.conviction.votes(balance);
130 self.turnout = self.turnout.checked_sub(&capital)?;
131 match vote.aye {
132 true => self.ayes = self.ayes.checked_sub(&votes)?,
133 false => self.nays = self.nays.checked_sub(&votes)?,
134 }
135 },
136 AccountVote::Split { aye, nay } => {
137 let aye = Conviction::None.votes(aye);
138 let nay = Conviction::None.votes(nay);
139 self.turnout = self.turnout.checked_sub(&aye.capital)?.checked_sub(&nay.capital)?;
140 self.ayes = self.ayes.checked_sub(&aye.votes)?;
141 self.nays = self.nays.checked_sub(&nay.votes)?;
142 },
143 }
144 Some(())
145 }
146
147 pub fn increase(&mut self, approve: bool, delegations: Delegations<Balance>) -> Option<()> {
149 self.turnout = self.turnout.saturating_add(delegations.capital);
150 match approve {
151 true => self.ayes = self.ayes.saturating_add(delegations.votes),
152 false => self.nays = self.nays.saturating_add(delegations.votes),
153 }
154 Some(())
155 }
156
157 pub fn reduce(&mut self, approve: bool, delegations: Delegations<Balance>) -> Option<()> {
159 self.turnout = self.turnout.saturating_sub(delegations.capital);
160 match approve {
161 true => self.ayes = self.ayes.saturating_sub(delegations.votes),
162 false => self.nays = self.nays.saturating_sub(delegations.votes),
163 }
164 Some(())
165 }
166}
167
168#[derive(
170 Encode, MaxEncodedLen, Decode, DecodeWithMemTracking, Clone, PartialEq, Eq, Debug, TypeInfo,
171)]
172pub struct ReferendumStatus<BlockNumber, Proposal, Balance> {
173 pub end: BlockNumber,
175 pub proposal: Proposal,
177 pub threshold: VoteThreshold,
179 pub delay: BlockNumber,
181 pub tally: Tally<Balance>,
183}
184
185#[derive(
187 Encode, MaxEncodedLen, Decode, DecodeWithMemTracking, Clone, PartialEq, Eq, Debug, TypeInfo,
188)]
189pub enum ReferendumInfo<BlockNumber, Proposal, Balance> {
190 Ongoing(ReferendumStatus<BlockNumber, Proposal, Balance>),
192 Finished { approved: bool, end: BlockNumber },
194}
195
196impl<BlockNumber, Proposal, Balance: Default> ReferendumInfo<BlockNumber, Proposal, Balance> {
197 pub fn new(
199 end: BlockNumber,
200 proposal: Proposal,
201 threshold: VoteThreshold,
202 delay: BlockNumber,
203 ) -> Self {
204 let s = ReferendumStatus { end, proposal, threshold, delay, tally: Tally::default() };
205 ReferendumInfo::Ongoing(s)
206 }
207}
208
209pub enum UnvoteScope {
212 Any,
214 OnlyExpired,
216}
217
218#[derive(
220 Encode, Decode, DecodeWithMemTracking, Clone, PartialEq, Eq, Debug, TypeInfo, MaxEncodedLen,
221)]
222pub enum MetadataOwner {
223 External,
225 Proposal(PropIndex),
227 Referendum(ReferendumIndex),
229}