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 RuntimeDebug,
26};
27
28pub type PropIndex = u32;
30
31pub type ReferendumIndex = u32;
33
34#[derive(Encode, MaxEncodedLen, Decode, Default, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
36pub struct Tally<Balance> {
37 pub ayes: Balance,
39 pub nays: Balance,
41 pub turnout: Balance,
43}
44
45#[derive(
47 Encode, MaxEncodedLen, Decode, Default, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo,
48)]
49pub struct Delegations<Balance> {
50 pub votes: Balance,
52 pub capital: Balance,
54}
55
56impl<Balance: Saturating> Saturating for Delegations<Balance> {
57 fn saturating_add(self, o: Self) -> Self {
58 Self {
59 votes: self.votes.saturating_add(o.votes),
60 capital: self.capital.saturating_add(o.capital),
61 }
62 }
63
64 fn saturating_sub(self, o: Self) -> Self {
65 Self {
66 votes: self.votes.saturating_sub(o.votes),
67 capital: self.capital.saturating_sub(o.capital),
68 }
69 }
70
71 fn saturating_mul(self, o: Self) -> Self {
72 Self {
73 votes: self.votes.saturating_mul(o.votes),
74 capital: self.capital.saturating_mul(o.capital),
75 }
76 }
77
78 fn saturating_pow(self, exp: usize) -> Self {
79 Self { votes: self.votes.saturating_pow(exp), capital: self.capital.saturating_pow(exp) }
80 }
81}
82
83impl<
84 Balance: From<u8>
85 + Zero
86 + Copy
87 + CheckedAdd
88 + CheckedSub
89 + CheckedMul
90 + CheckedDiv
91 + Bounded
92 + Saturating,
93 > Tally<Balance>
94{
95 pub fn new(vote: Vote, balance: Balance) -> Self {
97 let Delegations { votes, capital } = vote.conviction.votes(balance);
98 Self {
99 ayes: if vote.aye { votes } else { Zero::zero() },
100 nays: if vote.aye { Zero::zero() } else { votes },
101 turnout: capital,
102 }
103 }
104
105 pub fn add(&mut self, vote: AccountVote<Balance>) -> Option<()> {
107 match vote {
108 AccountVote::Standard { vote, balance } => {
109 let Delegations { votes, capital } = vote.conviction.votes(balance);
110 self.turnout = self.turnout.checked_add(&capital)?;
111 match vote.aye {
112 true => self.ayes = self.ayes.checked_add(&votes)?,
113 false => self.nays = self.nays.checked_add(&votes)?,
114 }
115 },
116 AccountVote::Split { aye, nay } => {
117 let aye = Conviction::None.votes(aye);
118 let nay = Conviction::None.votes(nay);
119 self.turnout = self.turnout.checked_add(&aye.capital)?.checked_add(&nay.capital)?;
120 self.ayes = self.ayes.checked_add(&aye.votes)?;
121 self.nays = self.nays.checked_add(&nay.votes)?;
122 },
123 }
124 Some(())
125 }
126
127 pub fn remove(&mut self, vote: AccountVote<Balance>) -> Option<()> {
129 match vote {
130 AccountVote::Standard { vote, balance } => {
131 let Delegations { votes, capital } = vote.conviction.votes(balance);
132 self.turnout = self.turnout.checked_sub(&capital)?;
133 match vote.aye {
134 true => self.ayes = self.ayes.checked_sub(&votes)?,
135 false => self.nays = self.nays.checked_sub(&votes)?,
136 }
137 },
138 AccountVote::Split { aye, nay } => {
139 let aye = Conviction::None.votes(aye);
140 let nay = Conviction::None.votes(nay);
141 self.turnout = self.turnout.checked_sub(&aye.capital)?.checked_sub(&nay.capital)?;
142 self.ayes = self.ayes.checked_sub(&aye.votes)?;
143 self.nays = self.nays.checked_sub(&nay.votes)?;
144 },
145 }
146 Some(())
147 }
148
149 pub fn increase(&mut self, approve: bool, delegations: Delegations<Balance>) -> Option<()> {
151 self.turnout = self.turnout.saturating_add(delegations.capital);
152 match approve {
153 true => self.ayes = self.ayes.saturating_add(delegations.votes),
154 false => self.nays = self.nays.saturating_add(delegations.votes),
155 }
156 Some(())
157 }
158
159 pub fn reduce(&mut self, approve: bool, delegations: Delegations<Balance>) -> Option<()> {
161 self.turnout = self.turnout.saturating_sub(delegations.capital);
162 match approve {
163 true => self.ayes = self.ayes.saturating_sub(delegations.votes),
164 false => self.nays = self.nays.saturating_sub(delegations.votes),
165 }
166 Some(())
167 }
168}
169
170#[derive(
172 Encode,
173 MaxEncodedLen,
174 Decode,
175 DecodeWithMemTracking,
176 Clone,
177 PartialEq,
178 Eq,
179 RuntimeDebug,
180 TypeInfo,
181)]
182pub struct ReferendumStatus<BlockNumber, Proposal, Balance> {
183 pub end: BlockNumber,
185 pub proposal: Proposal,
187 pub threshold: VoteThreshold,
189 pub delay: BlockNumber,
191 pub tally: Tally<Balance>,
193}
194
195#[derive(
197 Encode,
198 MaxEncodedLen,
199 Decode,
200 DecodeWithMemTracking,
201 Clone,
202 PartialEq,
203 Eq,
204 RuntimeDebug,
205 TypeInfo,
206)]
207pub enum ReferendumInfo<BlockNumber, Proposal, Balance> {
208 Ongoing(ReferendumStatus<BlockNumber, Proposal, Balance>),
210 Finished { approved: bool, end: BlockNumber },
212}
213
214impl<BlockNumber, Proposal, Balance: Default> ReferendumInfo<BlockNumber, Proposal, Balance> {
215 pub fn new(
217 end: BlockNumber,
218 proposal: Proposal,
219 threshold: VoteThreshold,
220 delay: BlockNumber,
221 ) -> Self {
222 let s = ReferendumStatus { end, proposal, threshold, delay, tally: Tally::default() };
223 ReferendumInfo::Ongoing(s)
224 }
225}
226
227pub enum UnvoteScope {
230 Any,
232 OnlyExpired,
234}
235
236#[derive(
238 Encode,
239 Decode,
240 DecodeWithMemTracking,
241 Clone,
242 PartialEq,
243 Eq,
244 RuntimeDebug,
245 TypeInfo,
246 MaxEncodedLen,
247)]
248pub enum MetadataOwner {
249 External,
251 Proposal(PropIndex),
253 Referendum(ReferendumIndex),
255}