moonbase_runtime/governance/
tracks.rsuse super::*;
use crate::currency::{KILOUNIT, SUPPLY_FACTOR, UNIT};
use core::str::from_utf8;
use sp_std::str::FromStr;
const fn percent(x: i32) -> sp_runtime::FixedI64 {
sp_runtime::FixedI64::from_rational(x as u128, 100)
}
const fn permill(x: i32) -> sp_runtime::FixedI64 {
sp_runtime::FixedI64::from_rational(x as u128, 1000)
}
use pallet_referenda::{Curve, Track};
use sp_runtime::str_array as s;
const TRACKS_DATA: [Track<u16, Balance, BlockNumber>; 6] = [
Track {
id: 0,
info: pallet_referenda::TrackInfo {
name: s("root"),
max_deciding: 5,
decision_deposit: 100 * KILOUNIT * SUPPLY_FACTOR,
prepare_period: 1 * DAYS,
decision_period: 14 * DAYS,
confirm_period: 1 * DAYS,
min_enactment_period: 1 * DAYS,
min_approval: Curve::make_reciprocal(4, 14, percent(80), percent(50), percent(100)),
min_support: Curve::make_linear(14, 14, permill(5), percent(25)),
},
},
Track {
id: 1,
info: pallet_referenda::TrackInfo {
name: s("whitelisted_caller"),
max_deciding: 100,
decision_deposit: 10 * KILOUNIT * SUPPLY_FACTOR,
prepare_period: 10 * MINUTES,
decision_period: 14 * DAYS,
confirm_period: 10 * MINUTES,
min_enactment_period: 30 * MINUTES,
min_approval: Curve::make_reciprocal(1, 14, percent(96), percent(50), percent(100)),
min_support: Curve::make_reciprocal(1, 14 * 24, percent(1), percent(0), percent(2)),
},
},
Track {
id: 2,
info: pallet_referenda::TrackInfo {
name: s("general_admin"),
max_deciding: 10,
decision_deposit: 500 * UNIT * SUPPLY_FACTOR,
prepare_period: 1 * HOURS,
decision_period: 14 * DAYS,
confirm_period: 1 * DAYS,
min_enactment_period: 1 * DAYS,
min_approval: Curve::make_reciprocal(4, 14, percent(80), percent(50), percent(100)),
min_support: Curve::make_reciprocal(7, 14, percent(10), percent(0), percent(50)),
},
},
Track {
id: 3,
info: pallet_referenda::TrackInfo {
name: s("referendum_canceller"),
max_deciding: 20,
decision_deposit: 10 * KILOUNIT * SUPPLY_FACTOR,
prepare_period: 1 * HOURS,
decision_period: 14 * DAYS,
confirm_period: 3 * HOURS,
min_enactment_period: 10 * MINUTES,
min_approval: Curve::make_reciprocal(1, 14, percent(96), percent(50), percent(100)),
min_support: Curve::make_reciprocal(1, 14, percent(1), percent(0), percent(50)),
},
},
Track {
id: 4,
info: pallet_referenda::TrackInfo {
name: s("referendum_killer"),
max_deciding: 100,
decision_deposit: 20 * KILOUNIT * SUPPLY_FACTOR,
prepare_period: 1 * HOURS,
decision_period: 14 * DAYS,
confirm_period: 3 * HOURS,
min_enactment_period: 10 * MINUTES,
min_approval: Curve::make_reciprocal(1, 14, percent(96), percent(50), percent(100)),
min_support: Curve::make_reciprocal(1, 14, percent(1), percent(0), percent(10)),
},
},
Track {
id: 5,
info: pallet_referenda::TrackInfo {
name: s("fast_general_admin"),
max_deciding: 10,
decision_deposit: 500 * UNIT * SUPPLY_FACTOR,
prepare_period: 1 * HOURS,
decision_period: 14 * DAYS,
confirm_period: 3 * HOURS,
min_enactment_period: 10 * MINUTES,
min_approval: Curve::make_reciprocal(4, 14, percent(80), percent(50), percent(100)),
min_support: Curve::make_reciprocal(5, 14, percent(1), percent(0), percent(50)),
},
},
];
pub struct TracksInfo;
impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo {
type Id = u16;
type RuntimeOrigin = <RuntimeOrigin as frame_support::traits::OriginTrait>::PalletsOrigin;
fn tracks() -> impl Iterator<Item = Cow<'static, Track<Self::Id, Balance, BlockNumber>>> {
TRACKS_DATA.iter().map(Cow::Borrowed)
}
fn track_for(id: &Self::RuntimeOrigin) -> Result<Self::Id, ()> {
if let Ok(system_origin) = frame_system::RawOrigin::try_from(id.clone()) {
match system_origin {
frame_system::RawOrigin::Root => {
if let Some(track) = Self::tracks()
.into_iter()
.find(|track| track.info.name == s("root"))
{
Ok(track.id)
} else {
Err(())
}
}
_ => Err(()),
}
} else if let Ok(custom_origin) = custom_origins::Origin::try_from(id.clone()) {
if let Some(track) = Self::tracks().into_iter().find(|track| {
let Ok(track_name) = from_utf8(&track.info.name) else {
return false;
};
let track_name = track_name.trim_end_matches('\0');
if let Ok(track_custom_origin) = custom_origins::Origin::from_str(track_name) {
track_custom_origin == custom_origin
} else {
false
}
}) {
Ok(track.id)
} else {
Err(())
}
} else {
Err(())
}
}
}
#[test]
fn vote_locking_always_longer_than_enactment_period() {
for track in TRACKS_DATA {
assert!(
<Runtime as pallet_conviction_voting::Config>::VoteLockingPeriod::get()
>= track.info.min_enactment_period,
"Track {} has enactment period {} < vote locking period {}",
from_utf8(&track.info.name).expect("Track name is valid UTF-8"),
track.info.min_enactment_period,
<Runtime as pallet_conviction_voting::Config>::VoteLockingPeriod::get(),
);
}
}
#[test]
fn all_tracks_have_origins() {
for track in TRACKS_DATA {
let track_is_root = track.info.name == s("root");
let track_name = from_utf8(&track.info.name)
.expect("Track name is valid UTF-8")
.trim_end_matches('\0');
let track_has_custom_origin = custom_origins::Origin::from_str(track_name).is_ok();
println!("{:?}", from_utf8(&track.info.name).unwrap());
assert!(track_is_root || track_has_custom_origin);
}
}