referrerpolicy=no-referrer-when-downgrade

collectives_westend_runtime/fellowship/
tracks.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Cumulus.
3// SPDX-License-Identifier: Apache-2.0
4
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// 	http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17//! Track configurations for Fellowship.
18
19use crate::{Balance, BlockNumber, RuntimeOrigin, DAYS, DOLLARS, HOURS, MINUTES};
20use pallet_ranked_collective::Rank;
21use sp_runtime::{str_array as s, traits::Convert, Perbill};
22use sp_std::borrow::Cow;
23
24/// Referendum `TrackId` type.
25pub type TrackId = u16;
26
27/// Referendum track IDs.
28pub mod constants {
29	use super::TrackId;
30
31	// Regular tracks (7 days) used for general operations. The required rank for voting is the
32	// same as that which is named (and also the track ID).
33	pub const MEMBERS: TrackId = 1;
34	pub const PROFICIENTS: TrackId = 2;
35	pub const FELLOWS: TrackId = 3;
36	pub const ARCHITECTS: TrackId = 4;
37	pub const ARCHITECTS_ADEPT: TrackId = 5;
38	pub const GRAND_ARCHITECTS: TrackId = 6;
39	pub const MASTERS: TrackId = 7;
40	pub const MASTERS_CONSTANT: TrackId = 8;
41	pub const GRAND_MASTERS: TrackId = 9;
42
43	// Longer tracks (14 days) used for rank retention. These require a rank of two more than the
44	// grade at which they retain (as per the whitepaper). This works out as the track ID minus 8.
45	pub const RETAIN_AT_1DAN: TrackId = 11;
46	pub const RETAIN_AT_2DAN: TrackId = 12;
47	pub const RETAIN_AT_3DAN: TrackId = 13;
48	pub const RETAIN_AT_4DAN: TrackId = 14;
49	pub const RETAIN_AT_5DAN: TrackId = 15;
50	pub const RETAIN_AT_6DAN: TrackId = 16;
51
52	// Longest tracks (30 days) used for promotions. These require a rank of two more than the
53	// grade to which they promote (as per the whitepaper). This works out as the track ID minus 18.
54	pub const PROMOTE_TO_1DAN: TrackId = 21;
55	pub const PROMOTE_TO_2DAN: TrackId = 22;
56	pub const PROMOTE_TO_3DAN: TrackId = 23;
57	pub const PROMOTE_TO_4DAN: TrackId = 24;
58	pub const PROMOTE_TO_5DAN: TrackId = 25;
59	pub const PROMOTE_TO_6DAN: TrackId = 26;
60}
61
62/// Convert the track ID (defined above) into the minimum rank (i.e. fellowship Dan grade) required
63/// to vote on the track.
64pub struct MinRankOfClass;
65impl Convert<TrackId, Rank> for MinRankOfClass {
66	fn convert(a: TrackId) -> Rank {
67		match a {
68			// Just a regular vote: the track ID is conveniently the same as the minimum rank.
69			regular @ 1..=9 => regular,
70			// A retention vote; the track ID turns out to be 8 more than the minimum required rank.
71			retention @ 11..=16 => retention - 8,
72			// A promotion vote; the track ID turns out to be 18 more than the minimum required
73			// rank.
74			promotion @ 21..=26 => promotion - 18,
75			_ => Rank::max_value(),
76		}
77	}
78}
79
80const RETAIN_MAX_DECIDING: u32 = 25;
81const RETAIN_DECISION_DEPOSIT: Balance = 5 * DOLLARS;
82const RETAIN_PREPARE_PERIOD: BlockNumber = 0;
83const RETAIN_DECISION_PERIOD: BlockNumber = 14 * DAYS;
84const RETAIN_CONFIRM_PERIOD: BlockNumber = 1 * HOURS;
85const RETAIN_MIN_ENACTMENT_PERIOD: BlockNumber = 0;
86const RETAIN_MIN_APPROVAL: pallet_referenda::Curve = pallet_referenda::Curve::LinearDecreasing {
87	length: Perbill::from_percent(100),
88	floor: Perbill::from_percent(60),
89	ceil: Perbill::from_percent(100),
90};
91const RETAIN_MIN_SUPPORT: pallet_referenda::Curve = pallet_referenda::Curve::LinearDecreasing {
92	length: Perbill::from_percent(100),
93	floor: Perbill::from_percent(10),
94	ceil: Perbill::from_percent(100),
95};
96
97const PROMOTE_MAX_DECIDING: u32 = 10;
98const PROMOTE_DECISION_DEPOSIT: Balance = 5 * DOLLARS;
99const PROMOTE_PREPARE_PERIOD: BlockNumber = 0;
100const PROMOTE_DECISION_PERIOD: BlockNumber = 30 * DAYS;
101const PROMOTE_CONFIRM_PERIOD: BlockNumber = 1 * HOURS;
102const PROMOTE_MIN_ENACTMENT_PERIOD: BlockNumber = 0;
103const PROMOTE_MIN_APPROVAL: pallet_referenda::Curve = pallet_referenda::Curve::LinearDecreasing {
104	length: Perbill::from_percent(100),
105	floor: Perbill::from_percent(60),
106	ceil: Perbill::from_percent(100),
107};
108const PROMOTE_MIN_SUPPORT: pallet_referenda::Curve = pallet_referenda::Curve::LinearDecreasing {
109	length: Perbill::from_percent(100),
110	floor: Perbill::from_percent(10),
111	ceil: Perbill::from_percent(100),
112};
113
114pub struct TracksInfo;
115impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo {
116	type Id = TrackId;
117	type RuntimeOrigin = <RuntimeOrigin as frame_support::traits::OriginTrait>::PalletsOrigin;
118
119	fn tracks(
120	) -> impl Iterator<Item = Cow<'static, pallet_referenda::Track<Self::Id, Balance, BlockNumber>>>
121	{
122		use constants as tracks;
123		static DATA: [pallet_referenda::Track<TrackId, Balance, BlockNumber>; 21] = [
124			pallet_referenda::Track {
125				id: tracks::MEMBERS,
126				info: pallet_referenda::TrackInfo {
127					name: s("members"),
128					max_deciding: 10,
129					decision_deposit: 5 * DOLLARS,
130					prepare_period: 30 * MINUTES,
131					decision_period: 1 * DAYS,
132					confirm_period: 30 * MINUTES,
133					min_enactment_period: 5 * MINUTES,
134					min_approval: pallet_referenda::Curve::LinearDecreasing {
135						length: Perbill::from_percent(100),
136						floor: Perbill::from_percent(50),
137						ceil: Perbill::from_percent(100),
138					},
139					min_support: pallet_referenda::Curve::LinearDecreasing {
140						length: Perbill::from_percent(100),
141						floor: Perbill::from_percent(0),
142						ceil: Perbill::from_percent(100),
143					},
144				},
145			},
146			pallet_referenda::Track {
147				id: tracks::PROFICIENTS,
148				info: pallet_referenda::TrackInfo {
149					name: s("proficient members"),
150					max_deciding: 10,
151					decision_deposit: 5 * DOLLARS,
152					prepare_period: 30 * MINUTES,
153					decision_period: 1 * DAYS,
154					confirm_period: 30 * MINUTES,
155					min_enactment_period: 5 * MINUTES,
156					min_approval: pallet_referenda::Curve::LinearDecreasing {
157						length: Perbill::from_percent(100),
158						floor: Perbill::from_percent(50),
159						ceil: Perbill::from_percent(100),
160					},
161					min_support: pallet_referenda::Curve::LinearDecreasing {
162						length: Perbill::from_percent(100),
163						floor: Perbill::from_percent(0),
164						ceil: Perbill::from_percent(100),
165					},
166				},
167			},
168			pallet_referenda::Track {
169				id: tracks::FELLOWS,
170				info: pallet_referenda::TrackInfo {
171					name: s("fellows"),
172					max_deciding: 10,
173					decision_deposit: 5 * DOLLARS,
174					prepare_period: 30 * MINUTES,
175					decision_period: 1 * DAYS,
176					confirm_period: 30 * MINUTES,
177					min_enactment_period: 5 * MINUTES,
178					min_approval: pallet_referenda::Curve::LinearDecreasing {
179						length: Perbill::from_percent(100),
180						floor: Perbill::from_percent(50),
181						ceil: Perbill::from_percent(100),
182					},
183					min_support: pallet_referenda::Curve::LinearDecreasing {
184						length: Perbill::from_percent(100),
185						floor: Perbill::from_percent(0),
186						ceil: Perbill::from_percent(100),
187					},
188				},
189			},
190			pallet_referenda::Track {
191				id: tracks::ARCHITECTS,
192				info: pallet_referenda::TrackInfo {
193					name: s("architects"),
194					max_deciding: 10,
195					decision_deposit: 5 * DOLLARS,
196					prepare_period: 30 * MINUTES,
197					decision_period: 1 * DAYS,
198					confirm_period: 30 * MINUTES,
199					min_enactment_period: 5 * MINUTES,
200					min_approval: pallet_referenda::Curve::LinearDecreasing {
201						length: Perbill::from_percent(100),
202						floor: Perbill::from_percent(50),
203						ceil: Perbill::from_percent(100),
204					},
205					min_support: pallet_referenda::Curve::LinearDecreasing {
206						length: Perbill::from_percent(100),
207						floor: Perbill::from_percent(0),
208						ceil: Perbill::from_percent(100),
209					},
210				},
211			},
212			pallet_referenda::Track {
213				id: tracks::ARCHITECTS_ADEPT,
214				info: pallet_referenda::TrackInfo {
215					name: s("architects adept"),
216					max_deciding: 10,
217					decision_deposit: 5 * DOLLARS,
218					prepare_period: 30 * MINUTES,
219					decision_period: 1 * DAYS,
220					confirm_period: 30 * MINUTES,
221					min_enactment_period: 5 * MINUTES,
222					min_approval: pallet_referenda::Curve::LinearDecreasing {
223						length: Perbill::from_percent(100),
224						floor: Perbill::from_percent(50),
225						ceil: Perbill::from_percent(100),
226					},
227					min_support: pallet_referenda::Curve::LinearDecreasing {
228						length: Perbill::from_percent(100),
229						floor: Perbill::from_percent(0),
230						ceil: Perbill::from_percent(100),
231					},
232				},
233			},
234			pallet_referenda::Track {
235				id: tracks::GRAND_ARCHITECTS,
236				info: pallet_referenda::TrackInfo {
237					name: s("grand architects"),
238					max_deciding: 10,
239					decision_deposit: 5 * DOLLARS,
240					prepare_period: 30 * MINUTES,
241					decision_period: 1 * DAYS,
242					confirm_period: 30 * MINUTES,
243					min_enactment_period: 5 * MINUTES,
244					min_approval: pallet_referenda::Curve::LinearDecreasing {
245						length: Perbill::from_percent(100),
246						floor: Perbill::from_percent(50),
247						ceil: Perbill::from_percent(100),
248					},
249					min_support: pallet_referenda::Curve::LinearDecreasing {
250						length: Perbill::from_percent(100),
251						floor: Perbill::from_percent(0),
252						ceil: Perbill::from_percent(100),
253					},
254				},
255			},
256			pallet_referenda::Track {
257				id: tracks::MASTERS,
258				info: pallet_referenda::TrackInfo {
259					name: s("masters"),
260					max_deciding: 10,
261					decision_deposit: 5 * DOLLARS,
262					prepare_period: 30 * MINUTES,
263					decision_period: 1 * DAYS,
264					confirm_period: 30 * MINUTES,
265					min_enactment_period: 5 * MINUTES,
266					min_approval: pallet_referenda::Curve::LinearDecreasing {
267						length: Perbill::from_percent(100),
268						floor: Perbill::from_percent(50),
269						ceil: Perbill::from_percent(100),
270					},
271					min_support: pallet_referenda::Curve::LinearDecreasing {
272						length: Perbill::from_percent(100),
273						floor: Perbill::from_percent(0),
274						ceil: Perbill::from_percent(100),
275					},
276				},
277			},
278			pallet_referenda::Track {
279				id: tracks::MASTERS_CONSTANT,
280				info: pallet_referenda::TrackInfo {
281					name: s("masters constant"),
282					max_deciding: 10,
283					decision_deposit: 5 * DOLLARS,
284					prepare_period: 30 * MINUTES,
285					decision_period: 1 * DAYS,
286					confirm_period: 30 * MINUTES,
287					min_enactment_period: 5 * MINUTES,
288					min_approval: pallet_referenda::Curve::LinearDecreasing {
289						length: Perbill::from_percent(100),
290						floor: Perbill::from_percent(50),
291						ceil: Perbill::from_percent(100),
292					},
293					min_support: pallet_referenda::Curve::LinearDecreasing {
294						length: Perbill::from_percent(100),
295						floor: Perbill::from_percent(0),
296						ceil: Perbill::from_percent(100),
297					},
298				},
299			},
300			pallet_referenda::Track {
301				id: tracks::GRAND_MASTERS,
302				info: pallet_referenda::TrackInfo {
303					name: s("grand masters"),
304					max_deciding: 10,
305					decision_deposit: 5 * DOLLARS,
306					prepare_period: 30 * MINUTES,
307					decision_period: 1 * DAYS,
308					confirm_period: 30 * MINUTES,
309					min_enactment_period: 5 * MINUTES,
310					min_approval: pallet_referenda::Curve::LinearDecreasing {
311						length: Perbill::from_percent(100),
312						floor: Perbill::from_percent(50),
313						ceil: Perbill::from_percent(100),
314					},
315					min_support: pallet_referenda::Curve::LinearDecreasing {
316						length: Perbill::from_percent(100),
317						floor: Perbill::from_percent(0),
318						ceil: Perbill::from_percent(100),
319					},
320				},
321			},
322			pallet_referenda::Track {
323				id: tracks::RETAIN_AT_1DAN,
324				info: pallet_referenda::TrackInfo {
325					name: s("retain at I Dan"),
326					max_deciding: RETAIN_MAX_DECIDING,
327					decision_deposit: RETAIN_DECISION_DEPOSIT,
328					prepare_period: RETAIN_PREPARE_PERIOD,
329					decision_period: RETAIN_DECISION_PERIOD,
330					confirm_period: RETAIN_CONFIRM_PERIOD,
331					min_enactment_period: RETAIN_MIN_ENACTMENT_PERIOD,
332					min_approval: RETAIN_MIN_APPROVAL,
333					min_support: RETAIN_MIN_SUPPORT,
334				},
335			},
336			pallet_referenda::Track {
337				id: tracks::RETAIN_AT_2DAN,
338				info: pallet_referenda::TrackInfo {
339					name: s("retain at II Dan"),
340					max_deciding: RETAIN_MAX_DECIDING,
341					decision_deposit: RETAIN_DECISION_DEPOSIT,
342					prepare_period: RETAIN_PREPARE_PERIOD,
343					decision_period: RETAIN_DECISION_PERIOD,
344					confirm_period: RETAIN_CONFIRM_PERIOD,
345					min_enactment_period: RETAIN_MIN_ENACTMENT_PERIOD,
346					min_approval: RETAIN_MIN_APPROVAL,
347					min_support: RETAIN_MIN_SUPPORT,
348				},
349			},
350			pallet_referenda::Track {
351				id: tracks::RETAIN_AT_3DAN,
352				info: pallet_referenda::TrackInfo {
353					name: s("retain at III Dan"),
354					max_deciding: RETAIN_MAX_DECIDING,
355					decision_deposit: RETAIN_DECISION_DEPOSIT,
356					prepare_period: RETAIN_PREPARE_PERIOD,
357					decision_period: RETAIN_DECISION_PERIOD,
358					confirm_period: RETAIN_CONFIRM_PERIOD,
359					min_enactment_period: RETAIN_MIN_ENACTMENT_PERIOD,
360					min_approval: RETAIN_MIN_APPROVAL,
361					min_support: RETAIN_MIN_SUPPORT,
362				},
363			},
364			pallet_referenda::Track {
365				id: tracks::RETAIN_AT_4DAN,
366				info: pallet_referenda::TrackInfo {
367					name: s("retain at IV Dan"),
368					max_deciding: RETAIN_MAX_DECIDING,
369					decision_deposit: RETAIN_DECISION_DEPOSIT,
370					prepare_period: RETAIN_PREPARE_PERIOD,
371					decision_period: RETAIN_DECISION_PERIOD,
372					confirm_period: RETAIN_CONFIRM_PERIOD,
373					min_enactment_period: RETAIN_MIN_ENACTMENT_PERIOD,
374					min_approval: RETAIN_MIN_APPROVAL,
375					min_support: RETAIN_MIN_SUPPORT,
376				},
377			},
378			pallet_referenda::Track {
379				id: tracks::RETAIN_AT_5DAN,
380				info: pallet_referenda::TrackInfo {
381					name: s("retain at V Dan"),
382					max_deciding: RETAIN_MAX_DECIDING,
383					decision_deposit: RETAIN_DECISION_DEPOSIT,
384					prepare_period: RETAIN_PREPARE_PERIOD,
385					decision_period: RETAIN_DECISION_PERIOD,
386					confirm_period: RETAIN_CONFIRM_PERIOD,
387					min_enactment_period: RETAIN_MIN_ENACTMENT_PERIOD,
388					min_approval: RETAIN_MIN_APPROVAL,
389					min_support: RETAIN_MIN_SUPPORT,
390				},
391			},
392			pallet_referenda::Track {
393				id: tracks::RETAIN_AT_6DAN,
394				info: pallet_referenda::TrackInfo {
395					name: s("retain at VI Dan"),
396					max_deciding: RETAIN_MAX_DECIDING,
397					decision_deposit: RETAIN_DECISION_DEPOSIT,
398					prepare_period: RETAIN_PREPARE_PERIOD,
399					decision_period: RETAIN_DECISION_PERIOD,
400					confirm_period: RETAIN_CONFIRM_PERIOD,
401					min_enactment_period: RETAIN_MIN_ENACTMENT_PERIOD,
402					min_approval: RETAIN_MIN_APPROVAL,
403					min_support: RETAIN_MIN_SUPPORT,
404				},
405			},
406			pallet_referenda::Track {
407				id: tracks::PROMOTE_TO_1DAN,
408				info: pallet_referenda::TrackInfo {
409					name: s("promote to I Dan"),
410					max_deciding: PROMOTE_MAX_DECIDING,
411					decision_deposit: PROMOTE_DECISION_DEPOSIT,
412					prepare_period: PROMOTE_PREPARE_PERIOD,
413					decision_period: PROMOTE_DECISION_PERIOD,
414					confirm_period: PROMOTE_CONFIRM_PERIOD,
415					min_enactment_period: PROMOTE_MIN_ENACTMENT_PERIOD,
416					min_approval: PROMOTE_MIN_APPROVAL,
417					min_support: PROMOTE_MIN_SUPPORT,
418				},
419			},
420			pallet_referenda::Track {
421				id: tracks::PROMOTE_TO_2DAN,
422				info: pallet_referenda::TrackInfo {
423					name: s("promote to II Dan"),
424					max_deciding: PROMOTE_MAX_DECIDING,
425					decision_deposit: PROMOTE_DECISION_DEPOSIT,
426					prepare_period: PROMOTE_PREPARE_PERIOD,
427					decision_period: PROMOTE_DECISION_PERIOD,
428					confirm_period: PROMOTE_CONFIRM_PERIOD,
429					min_enactment_period: PROMOTE_MIN_ENACTMENT_PERIOD,
430					min_approval: PROMOTE_MIN_APPROVAL,
431					min_support: PROMOTE_MIN_SUPPORT,
432				},
433			},
434			pallet_referenda::Track {
435				id: tracks::PROMOTE_TO_3DAN,
436				info: pallet_referenda::TrackInfo {
437					name: s("promote to III Dan"),
438					max_deciding: PROMOTE_MAX_DECIDING,
439					decision_deposit: PROMOTE_DECISION_DEPOSIT,
440					prepare_period: PROMOTE_PREPARE_PERIOD,
441					decision_period: PROMOTE_DECISION_PERIOD,
442					confirm_period: PROMOTE_CONFIRM_PERIOD,
443					min_enactment_period: PROMOTE_MIN_ENACTMENT_PERIOD,
444					min_approval: PROMOTE_MIN_APPROVAL,
445					min_support: PROMOTE_MIN_SUPPORT,
446				},
447			},
448			pallet_referenda::Track {
449				id: tracks::PROMOTE_TO_4DAN,
450				info: pallet_referenda::TrackInfo {
451					name: s("promote to IV Dan"),
452					max_deciding: PROMOTE_MAX_DECIDING,
453					decision_deposit: PROMOTE_DECISION_DEPOSIT,
454					prepare_period: PROMOTE_PREPARE_PERIOD,
455					decision_period: PROMOTE_DECISION_PERIOD,
456					confirm_period: PROMOTE_CONFIRM_PERIOD,
457					min_enactment_period: PROMOTE_MIN_ENACTMENT_PERIOD,
458					min_approval: PROMOTE_MIN_APPROVAL,
459					min_support: PROMOTE_MIN_SUPPORT,
460				},
461			},
462			pallet_referenda::Track {
463				id: tracks::PROMOTE_TO_5DAN,
464				info: pallet_referenda::TrackInfo {
465					name: s("promote to V Dan"),
466					max_deciding: PROMOTE_MAX_DECIDING,
467					decision_deposit: PROMOTE_DECISION_DEPOSIT,
468					prepare_period: PROMOTE_PREPARE_PERIOD,
469					decision_period: PROMOTE_DECISION_PERIOD,
470					confirm_period: PROMOTE_CONFIRM_PERIOD,
471					min_enactment_period: PROMOTE_MIN_ENACTMENT_PERIOD,
472					min_approval: PROMOTE_MIN_APPROVAL,
473					min_support: PROMOTE_MIN_SUPPORT,
474				},
475			},
476			pallet_referenda::Track {
477				id: tracks::PROMOTE_TO_6DAN,
478				info: pallet_referenda::TrackInfo {
479					name: s("promote to VI Dan"),
480					max_deciding: PROMOTE_MAX_DECIDING,
481					decision_deposit: PROMOTE_DECISION_DEPOSIT,
482					prepare_period: PROMOTE_PREPARE_PERIOD,
483					decision_period: PROMOTE_DECISION_PERIOD,
484					confirm_period: PROMOTE_CONFIRM_PERIOD,
485					min_enactment_period: PROMOTE_MIN_ENACTMENT_PERIOD,
486					min_approval: PROMOTE_MIN_APPROVAL,
487					min_support: PROMOTE_MIN_SUPPORT,
488				},
489			},
490		];
491		DATA.iter().map(Cow::Borrowed)
492	}
493	fn track_for(id: &Self::RuntimeOrigin) -> Result<Self::Id, ()> {
494		use super::origins::Origin;
495		use constants as tracks;
496
497		#[cfg(feature = "runtime-benchmarks")]
498		{
499			// For benchmarks, we enable a root origin.
500			// It is important that this is not available in production!
501			let root: Self::RuntimeOrigin = frame_system::RawOrigin::Root.into();
502			if &root == id {
503				return Ok(tracks::GRAND_MASTERS)
504			}
505		}
506
507		match Origin::try_from(id.clone()) {
508			Ok(Origin::Members) => Ok(tracks::MEMBERS),
509			Ok(Origin::Fellowship2Dan) => Ok(tracks::PROFICIENTS),
510			Ok(Origin::Fellows) => Ok(tracks::FELLOWS),
511			Ok(Origin::Architects) => Ok(tracks::ARCHITECTS),
512			Ok(Origin::Fellowship5Dan) => Ok(tracks::ARCHITECTS_ADEPT),
513			Ok(Origin::Fellowship6Dan) => Ok(tracks::GRAND_ARCHITECTS),
514			Ok(Origin::Masters) => Ok(tracks::MASTERS),
515			Ok(Origin::Fellowship8Dan) => Ok(tracks::MASTERS_CONSTANT),
516			Ok(Origin::Fellowship9Dan) => Ok(tracks::GRAND_MASTERS),
517
518			Ok(Origin::RetainAt1Dan) => Ok(tracks::RETAIN_AT_1DAN),
519			Ok(Origin::RetainAt2Dan) => Ok(tracks::RETAIN_AT_2DAN),
520			Ok(Origin::RetainAt3Dan) => Ok(tracks::RETAIN_AT_3DAN),
521			Ok(Origin::RetainAt4Dan) => Ok(tracks::RETAIN_AT_4DAN),
522			Ok(Origin::RetainAt5Dan) => Ok(tracks::RETAIN_AT_5DAN),
523			Ok(Origin::RetainAt6Dan) => Ok(tracks::RETAIN_AT_6DAN),
524
525			Ok(Origin::PromoteTo1Dan) => Ok(tracks::PROMOTE_TO_1DAN),
526			Ok(Origin::PromoteTo2Dan) => Ok(tracks::PROMOTE_TO_2DAN),
527			Ok(Origin::PromoteTo3Dan) => Ok(tracks::PROMOTE_TO_3DAN),
528			Ok(Origin::PromoteTo4Dan) => Ok(tracks::PROMOTE_TO_4DAN),
529			Ok(Origin::PromoteTo5Dan) => Ok(tracks::PROMOTE_TO_5DAN),
530			Ok(Origin::PromoteTo6Dan) => Ok(tracks::PROMOTE_TO_6DAN),
531
532			_ => Err(()),
533		}
534	}
535}