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}