lib.rs 89 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422
  1. // Ensure we're `no_std` when compiling for Wasm.
  2. #![cfg_attr(not(feature = "std"), no_std)]
  3. //#[cfg(feature = "std")]
  4. //use serde::{Deserialize, Serialize};
  5. use codec::{Decode, Encode}; // Codec
  6. //use rstd::collections::btree_map::BTreeMap;
  7. use crate::membership::{members, role_types};
  8. use hiring;
  9. use minting;
  10. use recurringrewards;
  11. use rstd::collections::btree_set::BTreeSet;
  12. use rstd::convert::From;
  13. use rstd::prelude::*;
  14. use runtime_primitives::traits::{One, Zero}; // Member, SimpleArithmetic, MaybeSerialize
  15. use srml_support::traits::{Currency, ExistenceRequirement, WithdrawReasons};
  16. use srml_support::{
  17. decl_event,
  18. decl_module,
  19. decl_storage,
  20. dispatch, // , StorageMap, , Parameter
  21. ensure,
  22. };
  23. use stake;
  24. use system::{self, ensure_root, ensure_signed};
  25. use versioned_store_permissions;
  26. /// DIRTY IMPORT BECAUSE
  27. /// InputValidationLengthConstraint has not been factored out yet!!!
  28. use forum::InputValidationLengthConstraint;
  29. /// Module configuration trait for this Substrate module.
  30. pub trait Trait:
  31. system::Trait
  32. + minting::Trait
  33. + recurringrewards::Trait
  34. + stake::Trait
  35. + hiring::Trait
  36. + versioned_store_permissions::Trait
  37. + members::Trait
  38. {
  39. // + Sized
  40. /// The event type.
  41. type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
  42. }
  43. /// Type constraint for identifer used for actors in members module in this runtime.
  44. pub type ActorIdInMembersModule<T> = <T as members::Trait>::ActorId;
  45. /// Type for identifier for channels.
  46. /// The ChannelId must be capable of behaving like an actor id for membership module,
  47. /// since publishers are identified by their channel id.
  48. pub type ChannelId<T> = ActorIdInMembersModule<T>;
  49. /// Type identifier for lead role, which must be same as membership actor identifeir
  50. pub type LeadId<T> = ActorIdInMembersModule<T>;
  51. /// Type identifier for curator role, which must be same as membership actor identifeir
  52. pub type CuratorId<T> = ActorIdInMembersModule<T>;
  53. /// Type for the identifer for an opening for a curator.
  54. pub type CuratorOpeningId<T> = <T as hiring::Trait>::OpeningId;
  55. /// Tyoe for the indentifier for an application as a curator.
  56. pub type CuratorApplicationId<T> = <T as hiring::Trait>::ApplicationId;
  57. /// Balance type of runtime
  58. pub type BalanceOf<T> =
  59. <<T as stake::Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::Balance;
  60. /// Balance type of runtime
  61. pub type CurrencyOf<T> = <T as stake::Trait>::Currency;
  62. /// Negative imbalance of runtime.
  63. pub type NegativeImbalance<T> =
  64. <<T as stake::Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::NegativeImbalance;
  65. /// Type of mintin reward relationship identifiers
  66. pub type RewardRelationshipId<T> = <T as recurringrewards::Trait>::RewardRelationshipId;
  67. /// Stake identifier in staking module
  68. pub type StakeId<T> = <T as stake::Trait>::StakeId;
  69. /// Type of permissions module prinicipal identifiers
  70. pub type PrincipalId<T> = <T as versioned_store_permissions::Trait>::Credential;
  71. /*
  72. * MOVE ALL OF THESE OUT TO COMMON LATER
  73. */
  74. static MSG_CHANNEL_CREATION_DISABLED: &str = "Channel creation currently disabled.";
  75. static MSG_CHANNEL_HANDLE_TOO_SHORT: &str = "Channel handle too short.";
  76. static MSG_CHANNEL_HANDLE_TOO_LONG: &str = "Channel handle too long.";
  77. static MSG_CHANNEL_DESCRIPTION_TOO_SHORT: &str = "Channel description too short";
  78. static MSG_CHANNEL_DESCRIPTION_TOO_LONG: &str = "Channel description too long";
  79. //static MSG_MEMBER_CANNOT_BECOME_PUBLISHER: &str =
  80. // "Member cannot become a publisher";
  81. static MSG_CHANNEL_ID_INVALID: &str = "Channel id invalid";
  82. static MSG_ORIGIN_DOES_NOT_MATCH_CHANNEL_ROLE_ACCOUNT: &str =
  83. "Origin does not match channel role account";
  84. static MSG_CURRENT_LEAD_ALREADY_SET: &str = "Current lead is already set";
  85. static MSG_CURRENT_LEAD_NOT_SET: &str = "Current lead is not set";
  86. //static MSG_MEMBER_CANNOT_BECOME_CURATOR_LEAD: &str =
  87. // "The member cannot become curator lead";
  88. //static MSG_LEAD_IS_NOT_SET: &str =
  89. // "Lead is not set";
  90. static MSG_ORIGIN_IS_NOT_LEAD: &str = "Origin is not lead";
  91. static MSG_ORIGIN_IS_NOT_APPLICANT: &str = "Origin is not applicant";
  92. //static MSG_OPENING_CANNOT_ACTIVATE_IN_THE_PAST: &str =
  93. // "Opening cannot activate in the past";
  94. static MSG_CURATOR_OPENING_DOES_NOT_EXIST: &str = "Curator opening does not exist";
  95. static MSG_CURATOR_APPLICATION_DOES_NOT_EXIST: &str = "Curator application does not exist";
  96. //static MSG_INSUFFICIENT_BALANCE_TO_COVER_ROLE_STAKE: &str =
  97. // "Insufficient balance to cover role stake";
  98. //static MSG_INSUFFICIENT_BALANCE_TO_COVER_APPLICATION_STAKE: &str =
  99. // "Insufficient balance to cover application stake";
  100. static MSG_INSUFFICIENT_BALANCE_TO_APPLY: &str = "Insufficient balance to apply";
  101. static MSG_SUCCESSFUL_CURATOR_APPLICATION_DOES_NOT_EXIST: &str =
  102. "Successful curatora pplication does not exist";
  103. static MSG_MEMBER_NO_LONGER_REGISTRABLE_AS_CURATOR: &str =
  104. "Member no longer registrable as curator";
  105. static MSG_CURATOR_DOES_NOT_EXIST: &str = "Curator does not exist";
  106. static MSG_CURATOR_IS_NOT_ACTIVE: &str = "Curator is not active";
  107. static MSG_CURATOR_EXIT_RATIOANEL_TEXT_TOO_LONG: &str = "Curator exit rationale text is too long";
  108. static MSG_CURATOR_EXIT_RATIOANEL_TEXT_TOO_SHORT: &str = "Curator exit rationale text is too short";
  109. static MSG_CURATOR_APPLICATION_TEXT_TOO_LONG: &str = "Curator application text too long";
  110. static MSG_CURATOR_APPLICATION_TEXT_TOO_SHORT: &str = "Curator application text too short";
  111. static MSG_SIGNER_IS_NOT_CURATOR_ROLE_ACCOUNT: &str = "Signer is not curator role account";
  112. static MSG_UNSTAKER_DOES_NOT_EXIST: &str = "Unstaker does not exist";
  113. static MSG_CURATOR_HAS_NO_REWARD: &str = "Curator has no recurring reward";
  114. static MSG_CURATOR_NOT_CONTROLLED_BY_MEMBER: &str = "Curator not controlled by member";
  115. static MSG_CHANNEL_NAME_ALREADY_TAKEN: &str = "Channel name is already taken";
  116. /// The exit stage of a lead involvement in the working group.
  117. #[derive(Encode, Decode, Debug, Clone)]
  118. pub struct ExitedLeadRole<BlockNumber> {
  119. /// When exit was initiated.
  120. pub initiated_at_block_number: BlockNumber,
  121. }
  122. /// The stage of the involvement of a lead in the working group.
  123. #[derive(Encode, Decode, Debug, Clone)]
  124. pub enum LeadRoleState<BlockNumber> {
  125. /// Currently active.
  126. Active,
  127. /// No longer active, for some reason
  128. Exited(ExitedLeadRole<BlockNumber>),
  129. }
  130. /// Must be default constructible because it indirectly is a value in a storage map.
  131. /// ***SHOULD NEVER ACTUALLY GET CALLED, IS REQUIRED TO DUE BAD STORAGE MODEL IN SUBSTRATE***
  132. impl<BlockNumber> Default for LeadRoleState<BlockNumber> {
  133. fn default() -> Self {
  134. LeadRoleState::Active
  135. }
  136. }
  137. /// Working group lead: curator lead
  138. /// For now this role is not staked or inducted through an structured process, like the hiring module,
  139. /// hence information about this is missing. Recurring rewards is included, somewhat arbitrarily!
  140. #[derive(Encode, Decode, Default, Debug, Clone)]
  141. pub struct Lead<AccountId, RewardRelationshipId, BlockNumber> {
  142. /// Account used to authenticate in this role,
  143. pub role_account: AccountId,
  144. /// Whether the role has recurring reward, and if so an identifier for this.
  145. pub reward_relationship: Option<RewardRelationshipId>,
  146. /// When was inducted
  147. /// TODO: Add richer information about circumstances of induction, like referencing a council proposal?
  148. pub inducted: BlockNumber,
  149. /// The stage of the involvement of this lead in the working group.
  150. pub stage: LeadRoleState<BlockNumber>,
  151. }
  152. /// Origin of exit initiation on behalf of a curator.'
  153. #[derive(Encode, Decode, Debug, Clone)]
  154. pub enum CuratorExitInitiationOrigin {
  155. /// Lead is origin.
  156. Lead,
  157. /// The curator exiting is the origin.
  158. Curator,
  159. }
  160. /// The exit stage of a curators involvement in the working group.
  161. #[derive(Encode, Decode, Debug, Clone)]
  162. pub struct CuratorExitSummary<BlockNumber> {
  163. /// Origin for exit.
  164. pub origin: CuratorExitInitiationOrigin,
  165. /// When exit was initiated.
  166. pub initiated_at_block_number: BlockNumber,
  167. /// Explainer for why exit was initited.
  168. pub rationale_text: Vec<u8>,
  169. }
  170. impl<BlockNumber: Clone> CuratorExitSummary<BlockNumber> {
  171. pub fn new(
  172. origin: &CuratorExitInitiationOrigin,
  173. initiated_at_block_number: &BlockNumber,
  174. rationale_text: &Vec<u8>,
  175. ) -> Self {
  176. CuratorExitSummary {
  177. origin: (*origin).clone(),
  178. initiated_at_block_number: (*initiated_at_block_number).clone(),
  179. rationale_text: (*rationale_text).clone(),
  180. }
  181. }
  182. }
  183. /// The stage of the involvement of a curator in the working group.
  184. #[derive(Encode, Decode, Debug, Clone)]
  185. pub enum CuratorRoleStage<BlockNumber> {
  186. /// Currently active.
  187. Active,
  188. /// Currently unstaking
  189. Unstaking(CuratorExitSummary<BlockNumber>),
  190. /// No longer active and unstaked
  191. Exited(CuratorExitSummary<BlockNumber>),
  192. }
  193. /// Must be default constructible because it indirectly is a value in a storage map.
  194. /// ***SHOULD NEVER ACTUALLY GET CALLED, IS REQUIRED TO DUE BAD STORAGE MODEL IN SUBSTRATE***
  195. impl<BlockNumber> Default for CuratorRoleStage<BlockNumber> {
  196. fn default() -> Self {
  197. CuratorRoleStage::Active
  198. }
  199. }
  200. /// The induction of a curator in the working group.
  201. #[derive(Encode, Decode, Default, Debug, Clone)]
  202. pub struct CuratorInduction<LeadId, CuratorApplicationId, BlockNumber> {
  203. /// Lead responsible for inducting curator
  204. pub lead: LeadId,
  205. /// Application through which curator was inducted
  206. pub curator_application_id: CuratorApplicationId,
  207. /// When induction occurred
  208. pub at_block: BlockNumber,
  209. }
  210. impl<LeadId: Clone, CuratorApplicationId: Clone, BlockNumber: Clone>
  211. CuratorInduction<LeadId, CuratorApplicationId, BlockNumber>
  212. {
  213. pub fn new(
  214. lead: &LeadId,
  215. curator_application_id: &CuratorApplicationId,
  216. at_block: &BlockNumber,
  217. ) -> Self {
  218. CuratorInduction {
  219. lead: (*lead).clone(),
  220. curator_application_id: (*curator_application_id).clone(),
  221. at_block: (*at_block).clone(),
  222. }
  223. }
  224. }
  225. /// Role stake information for a curator.
  226. #[derive(Encode, Decode, Default, Debug, Clone)]
  227. pub struct CuratorRoleStakeProfile<StakeId, BlockNumber> {
  228. /// Whether participant is staked, and if so, the identifier for this staking in the staking module.
  229. pub stake_id: StakeId,
  230. /// Unstaking period when terminated.
  231. pub termination_unstaking_period: Option<BlockNumber>,
  232. /// Unstaking period when exiting.
  233. pub exit_unstaking_period: Option<BlockNumber>,
  234. }
  235. impl<StakeId: Clone, BlockNumber: Clone> CuratorRoleStakeProfile<StakeId, BlockNumber> {
  236. pub fn new(
  237. stake_id: &StakeId,
  238. termination_unstaking_period: &Option<BlockNumber>,
  239. exit_unstaking_period: &Option<BlockNumber>,
  240. ) -> Self {
  241. Self {
  242. stake_id: (*stake_id).clone(),
  243. termination_unstaking_period: (*termination_unstaking_period).clone(),
  244. exit_unstaking_period: (*exit_unstaking_period).clone(),
  245. }
  246. }
  247. }
  248. /// Working group participant: curator
  249. /// This role can be staked, have reward and be inducted through the hiring module.
  250. #[derive(Encode, Decode, Default, Debug, Clone)]
  251. pub struct Curator<
  252. AccountId,
  253. RewardRelationshipId,
  254. StakeId,
  255. BlockNumber,
  256. LeadId,
  257. CuratorApplicationId,
  258. PrincipalId,
  259. > {
  260. /// Account used to authenticate in this role,
  261. pub role_account: AccountId,
  262. /// Whether the role has recurring reward, and if so an identifier for this.
  263. pub reward_relationship: Option<RewardRelationshipId>,
  264. /// When set, describes role stake of curator.
  265. pub role_stake_profile: Option<CuratorRoleStakeProfile<StakeId, BlockNumber>>,
  266. /// The stage of this curator in the working group.
  267. pub stage: CuratorRoleStage<BlockNumber>,
  268. /// How the curator was inducted into the working group.
  269. pub induction: CuratorInduction<LeadId, CuratorApplicationId, BlockNumber>,
  270. /// Whether this curator can unilaterally alter the curation status of a channel.
  271. //pub can_update_channel_curation_status: bool,
  272. /// Permissions module principal id
  273. pub principal_id: PrincipalId,
  274. }
  275. impl<
  276. AccountId: Clone,
  277. RewardRelationshipId: Clone,
  278. StakeId: Clone,
  279. BlockNumber: Clone,
  280. LeadId: Clone,
  281. ApplicationId: Clone,
  282. PrincipalId: Clone,
  283. >
  284. Curator<
  285. AccountId,
  286. RewardRelationshipId,
  287. StakeId,
  288. BlockNumber,
  289. LeadId,
  290. ApplicationId,
  291. PrincipalId,
  292. >
  293. {
  294. pub fn new(
  295. role_account: &AccountId,
  296. reward_relationship: &Option<RewardRelationshipId>,
  297. role_stake_profile: &Option<CuratorRoleStakeProfile<StakeId, BlockNumber>>,
  298. stage: &CuratorRoleStage<BlockNumber>,
  299. induction: &CuratorInduction<LeadId, ApplicationId, BlockNumber>,
  300. //can_update_channel_curation_status: bool,
  301. principal_id: &PrincipalId,
  302. ) -> Self {
  303. Curator {
  304. role_account: (*role_account).clone(),
  305. reward_relationship: (*reward_relationship).clone(),
  306. role_stake_profile: (*role_stake_profile).clone(),
  307. stage: (*stage).clone(),
  308. induction: (*induction).clone(),
  309. //can_update_channel_curation_status: can_update_channel_curation_status,
  310. principal_id: (*principal_id).clone(),
  311. }
  312. }
  313. }
  314. /// An opening for a curator role.
  315. #[derive(Encode, Decode, Default, Debug, Clone)]
  316. pub struct CuratorOpening<OpeningId, BlockNumber, Balance, CuratorApplicationId: core::cmp::Ord> {
  317. /// Identifer for underlying opening in the hiring module.
  318. pub opening_id: OpeningId,
  319. /// Set of identifiers for all curator applications ever added
  320. pub curator_applications: BTreeSet<CuratorApplicationId>,
  321. /// Commitment to policies in opening.
  322. pub policy_commitment: OpeningPolicyCommitment<BlockNumber, Balance>, /*
  323. * Add other stuff here in the future?
  324. * Like default payment terms, privilidges etc.?
  325. * Not obvious that it serves much of a purpose, they are mutable
  326. * after all, they need to be.
  327. * Revisit.
  328. */
  329. }
  330. /// An application for the curator role.
  331. #[derive(Encode, Decode, Default, Debug, Clone)]
  332. pub struct CuratorApplication<AccountId, CuratorOpeningId, MemberId, ApplicationId> {
  333. /// Account used to authenticate in this role,
  334. pub role_account: AccountId,
  335. /// Opening on which this application applies
  336. pub curator_opening_id: CuratorOpeningId,
  337. /// Member applying
  338. pub member_id: MemberId,
  339. /// Underlying application in hiring module
  340. pub application_id: ApplicationId,
  341. }
  342. impl<AccountId: Clone, CuratorOpeningId: Clone, MemberId: Clone, ApplicationId: Clone>
  343. CuratorApplication<AccountId, CuratorOpeningId, MemberId, ApplicationId>
  344. {
  345. pub fn new(
  346. role_account: &AccountId,
  347. curator_opening_id: &CuratorOpeningId,
  348. member_id: &MemberId,
  349. application_id: &ApplicationId,
  350. ) -> Self {
  351. CuratorApplication {
  352. role_account: (*role_account).clone(),
  353. curator_opening_id: (*curator_opening_id).clone(),
  354. member_id: (*member_id).clone(),
  355. application_id: (*application_id).clone(),
  356. }
  357. }
  358. }
  359. /// Type of .... .
  360. #[derive(Encode, Decode, Debug, Clone, PartialEq, Eq)]
  361. pub enum CurationActor<CuratorId> {
  362. Lead,
  363. Curator(CuratorId),
  364. }
  365. /*
  366. * BEGIN: =========================================================
  367. * Channel stuff
  368. */
  369. /// Type of channel content.
  370. #[derive(Encode, Decode, Debug, Clone, PartialEq)]
  371. pub enum ChannelContentType {
  372. Video,
  373. Music,
  374. Ebook,
  375. }
  376. /// Must be default constructible because it indirectly is a value in a storage map.
  377. /// ***SHOULD NEVER ACTUALLY GET CALLED, IS REQUIRED TO DUE BAD STORAGE MODEL IN SUBSTRATE***
  378. impl Default for ChannelContentType {
  379. fn default() -> Self {
  380. ChannelContentType::Video
  381. }
  382. }
  383. /// Status of channel, as set by the owner.
  384. /// Is only meant to affect visibility, mutation of channel and child content
  385. /// is unaffected on runtime.
  386. #[derive(Encode, Decode, Debug, Clone, PartialEq)]
  387. pub enum ChannelPublishingStatus {
  388. /// Compliant UIs should render.
  389. Published,
  390. /// Compliant UIs should not render it or any child content.
  391. NotPublished,
  392. }
  393. /// Must be default constructible because it indirectly is a value in a storage map.
  394. /// ***SHOULD NEVER ACTUALLY GET CALLED, IS REQUIRED TO DUE BAD STORAGE MODEL IN SUBSTRATE***
  395. impl Default for ChannelPublishingStatus {
  396. fn default() -> Self {
  397. ChannelPublishingStatus::Published
  398. }
  399. }
  400. /// Status of channel, as set by curators.
  401. /// Is only meant to affect visibility currently, but in the future
  402. /// it will also gate publication of new child content,
  403. /// editing properties, revenue flows, etc.
  404. #[derive(Encode, Decode, Debug, Clone, Copy, PartialEq, Eq)]
  405. pub enum ChannelCurationStatus {
  406. Normal,
  407. Censored,
  408. }
  409. /// Must be default constructible because it indirectly is a value in a storage map.
  410. /// ***SHOULD NEVER ACTUALLY GET CALLED, IS REQUIRED TO DUE BAD STORAGE MODEL IN SUBSTRATE***
  411. impl Default for ChannelCurationStatus {
  412. fn default() -> Self {
  413. ChannelCurationStatus::Normal
  414. }
  415. }
  416. /// A channel for publishing content.
  417. #[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]
  418. pub struct Channel<MemberId, AccountId, BlockNumber, PrincipalId> {
  419. /// Unique human readble channel name.
  420. pub channel_name: Vec<u8>,
  421. /// Whether channel has been verified, in the normal Web2.0 platform sense of being authenticated.
  422. pub verified: bool,
  423. /// Human readable description of channel purpose and scope.
  424. pub description: Vec<u8>,
  425. /// The type of channel.
  426. pub content: ChannelContentType,
  427. /// Member who owns channel.
  428. pub owner: MemberId,
  429. /// Account used to authenticate as owner.
  430. /// Can be updated through membership role key.
  431. pub role_account: AccountId,
  432. /// Publication status of channel.
  433. pub publishing_status: ChannelPublishingStatus,
  434. /// Curation status of channel.
  435. pub curation_status: ChannelCurationStatus,
  436. /// When channel was established.
  437. pub created: BlockNumber,
  438. /// Permissions module principal id
  439. pub principal_id: PrincipalId,
  440. }
  441. /*
  442. * END: =========================================================
  443. * Channel stuff
  444. */
  445. /// Permissions module principal
  446. #[derive(Encode, Decode, Debug, Clone)]
  447. pub enum Principal<CuratorId, ChannelId> {
  448. /// Its sloppy to have this here, less safe,
  449. /// but its not worth the ffort to solve.
  450. Lead,
  451. Curator(CuratorId),
  452. ChannelOwner(ChannelId),
  453. }
  454. /// Must be default constructible because it indirectly is a value in a storage map.
  455. /// ***SHOULD NEVER ACTUALLY GET CALLED, IS REQUIRED TO DUE BAD STORAGE MODEL IN SUBSTRATE***
  456. impl<CuratorId, ChannelId> Default for Principal<CuratorId, ChannelId> {
  457. fn default() -> Self {
  458. Principal::Lead
  459. }
  460. }
  461. /// Terms for slashings applied to a given role
  462. #[derive(Encode, Decode, Debug, Clone, PartialEq, Eq)]
  463. pub struct SlashableTerms {
  464. /// Maximum number of slashes.
  465. pub max_count: u16,
  466. /// Maximum percentage points of remaining stake which may be slashed in a single slash.
  467. pub max_percent_pts_per_time: u16,
  468. }
  469. /// Terms for what slashing can be applied in some context
  470. #[derive(Encode, Decode, Debug, Clone, PartialEq, Eq)]
  471. pub enum SlashingTerms {
  472. Unslashable,
  473. Slashable(SlashableTerms),
  474. }
  475. /// Must be default constructible because it indirectly is a value in a storage map.
  476. /// ***SHOULD NEVER ACTUALLY GET CALLED, IS REQUIRED TO DUE BAD STORAGE MODEL IN SUBSTRATE***
  477. impl Default for SlashingTerms {
  478. fn default() -> Self {
  479. Self::Unslashable
  480. }
  481. }
  482. /// A commitment to the set of policy variables relevant to an opening.
  483. /// An applicant can observe this commitment and be secure that the terms
  484. /// of the application process cannot be changed ex-post.
  485. #[derive(Encode, Decode, Debug, Clone, Default, PartialEq, Eq)]
  486. pub struct OpeningPolicyCommitment<BlockNumber, Balance> {
  487. /// Rationing to be used
  488. pub application_rationing_policy: Option<hiring::ApplicationRationingPolicy>,
  489. /// Maximum length of review period of applications
  490. pub max_review_period_length: BlockNumber,
  491. /// Staking policy for application
  492. pub application_staking_policy: Option<hiring::StakingPolicy<Balance, BlockNumber>>,
  493. /// Staking policy for role itself
  494. pub role_staking_policy: Option<hiring::StakingPolicy<Balance, BlockNumber>>,
  495. // Slashing terms during application
  496. // pub application_slashing_terms: SlashingTerms,
  497. // Slashing terms during role, NOT application itself!
  498. pub role_slashing_terms: SlashingTerms,
  499. /// When filling an opening: Unstaking period for application stake of successful applicants
  500. pub fill_opening_successful_applicant_application_stake_unstaking_period: Option<BlockNumber>,
  501. /// When filling an opening:
  502. pub fill_opening_failed_applicant_application_stake_unstaking_period: Option<BlockNumber>,
  503. /// When filling an opening:
  504. pub fill_opening_failed_applicant_role_stake_unstaking_period: Option<BlockNumber>,
  505. /// When terminating a curator:
  506. pub terminate_curator_application_stake_unstaking_period: Option<BlockNumber>,
  507. /// When terminating a curator:
  508. pub terminate_curator_role_stake_unstaking_period: Option<BlockNumber>,
  509. /// When a curator exists: ..
  510. pub exit_curator_role_application_stake_unstaking_period: Option<BlockNumber>,
  511. /// When a curator exists: ..
  512. pub exit_curator_role_stake_unstaking_period: Option<BlockNumber>,
  513. }
  514. /// Represents a possible unstaker in working group.
  515. #[derive(Encode, Decode, Debug, Eq, PartialEq, Clone, PartialOrd)]
  516. pub enum WorkingGroupUnstaker<LeadId, CuratorId> {
  517. ///
  518. Lead(LeadId),
  519. ///
  520. Curator(CuratorId),
  521. }
  522. /// Must be default constructible because it indirectly is a value in a storage map.
  523. /// ***SHOULD NEVER ACTUALLY GET CALLED, IS REQUIRED TO DUE BAD STORAGE MODEL IN SUBSTRATE***
  524. impl<LeadId: Default, CuratorId> Default for WorkingGroupUnstaker<LeadId, CuratorId> {
  525. fn default() -> Self {
  526. Self::Lead(LeadId::default())
  527. }
  528. }
  529. /*
  530. pub enum ChannelActor<T: Trait> {
  531. ///
  532. WorkingGroupActor(WorkingGroupActor<T>),
  533. ///
  534. Owner
  535. }
  536. */
  537. // ======================================================================== //
  538. // Move this out in its own file later //
  539. // ======================================================================== //
  540. /*
  541. struct WrappedBeginAcceptingApplicationsError { // can this be made generic, or does that undermine the whole orhpan rule spirit?
  542. pub error: hiring::BeginAcceptingApplicationsError
  543. }
  544. */
  545. struct WrappedError<E> {
  546. // can this be made generic, or does that undermine the whole orhpan rule spirit?
  547. pub error: E,
  548. }
  549. /// ....
  550. macro_rules! ensure_on_wrapped_error {
  551. ($call:expr) => {{
  552. { $call }.map_err(|err| WrappedError { error: err })
  553. }};
  554. }
  555. // Add macro here to make this
  556. //derive_from_impl(hiring::BeginAcceptingApplicationsError)
  557. //derive_from_impl(hiring::BeginAcceptingApplicationsError)
  558. impl rstd::convert::From<WrappedError<hiring::BeginAcceptingApplicationsError>> for &str {
  559. fn from(wrapper: WrappedError<hiring::BeginAcceptingApplicationsError>) -> Self {
  560. match wrapper.error {
  561. hiring::BeginAcceptingApplicationsError::OpeningDoesNotExist => {
  562. "Opening does not exist"
  563. }
  564. hiring::BeginAcceptingApplicationsError::OpeningIsNotInWaitingToBeginStage => {
  565. "Opening Is Not in Waiting"
  566. }
  567. }
  568. }
  569. }
  570. impl rstd::convert::From<WrappedError<hiring::AddOpeningError>> for &str {
  571. fn from(wrapper: WrappedError<hiring::AddOpeningError>) -> Self {
  572. match wrapper.error {
  573. hiring::AddOpeningError::OpeningMustActivateInTheFuture => {
  574. "Opening must activate in the future"
  575. }
  576. hiring::AddOpeningError::StakeAmountLessThanMinimumCurrencyBalance(purpose) => {
  577. match purpose {
  578. hiring::StakePurpose::Role => {
  579. "Role stake amount less than minimum currency balance"
  580. }
  581. hiring::StakePurpose::Application => {
  582. "Application stake amount less than minimum currency balance"
  583. }
  584. }
  585. }
  586. }
  587. }
  588. }
  589. impl rstd::convert::From<WrappedError<hiring::BeginReviewError>> for &str {
  590. fn from(wrapper: WrappedError<hiring::BeginReviewError>) -> Self {
  591. match wrapper.error {
  592. hiring::BeginReviewError::OpeningDoesNotExist => "Opening does not exist",
  593. hiring::BeginReviewError::OpeningNotInAcceptingApplicationsStage => {
  594. "Opening not in accepting applications stage"
  595. }
  596. }
  597. }
  598. }
  599. impl<T: hiring::Trait> rstd::convert::From<WrappedError<hiring::FillOpeningError<T>>> for &str {
  600. fn from(wrapper: WrappedError<hiring::FillOpeningError<T>>) -> Self {
  601. match wrapper.error {
  602. hiring::FillOpeningError::<T>::OpeningDoesNotExist => "OpeningDoesNotExist",
  603. hiring::FillOpeningError::<T>::OpeningNotInReviewPeriodStage => {
  604. "OpeningNotInReviewPeriodStage"
  605. }
  606. hiring::FillOpeningError::<T>::UnstakingPeriodTooShort(
  607. stake_purpose,
  608. outcome_in_filled_opening,
  609. ) => match stake_purpose {
  610. hiring::StakePurpose::Application => match outcome_in_filled_opening {
  611. hiring::ApplicationOutcomeInFilledOpening::Success => {
  612. "Application stake unstaking period for successful applicants too short"
  613. }
  614. hiring::ApplicationOutcomeInFilledOpening::Failure => {
  615. "Application stake unstaking period for failed applicants too short"
  616. }
  617. },
  618. hiring::StakePurpose::Role => match outcome_in_filled_opening {
  619. hiring::ApplicationOutcomeInFilledOpening::Success => {
  620. "Role stake unstaking period for successful applicants too short"
  621. }
  622. hiring::ApplicationOutcomeInFilledOpening::Failure => {
  623. "Role stake unstaking period for failed applicants too short"
  624. }
  625. },
  626. },
  627. hiring::FillOpeningError::<T>::RedundantUnstakingPeriodProvided(
  628. stake_purpose,
  629. outcome_in_filled_opening,
  630. ) => match stake_purpose {
  631. hiring::StakePurpose::Application => match outcome_in_filled_opening {
  632. hiring::ApplicationOutcomeInFilledOpening::Success => {
  633. "Application stake unstaking period for successful applicants redundant"
  634. }
  635. hiring::ApplicationOutcomeInFilledOpening::Failure => {
  636. "Application stake unstaking period for failed applicants redundant"
  637. }
  638. },
  639. hiring::StakePurpose::Role => match outcome_in_filled_opening {
  640. hiring::ApplicationOutcomeInFilledOpening::Success => {
  641. "Role stake unstaking period for successful applicants redundant"
  642. }
  643. hiring::ApplicationOutcomeInFilledOpening::Failure => {
  644. "Role stake unstaking period for failed applicants redundant"
  645. }
  646. },
  647. },
  648. hiring::FillOpeningError::<T>::ApplicationDoesNotExist(_application_id) => {
  649. "ApplicationDoesNotExist"
  650. }
  651. hiring::FillOpeningError::<T>::ApplicationNotInActiveStage(_application_id) => {
  652. "ApplicationNotInActiveStage"
  653. }
  654. }
  655. }
  656. }
  657. impl rstd::convert::From<WrappedError<hiring::DeactivateApplicationError>> for &str {
  658. fn from(wrapper: WrappedError<hiring::DeactivateApplicationError>) -> Self {
  659. match wrapper.error {
  660. hiring::DeactivateApplicationError::ApplicationDoesNotExist => {
  661. "ApplicationDoesNotExist"
  662. }
  663. hiring::DeactivateApplicationError::ApplicationNotActive => "ApplicationNotActive",
  664. hiring::DeactivateApplicationError::OpeningNotAcceptingApplications => {
  665. "OpeningNotAcceptingApplications"
  666. }
  667. hiring::DeactivateApplicationError::UnstakingPeriodTooShort(_stake_purpose) => {
  668. "UnstakingPeriodTooShort ..."
  669. }
  670. hiring::DeactivateApplicationError::RedundantUnstakingPeriodProvided(
  671. _stake_purpose,
  672. ) => "RedundantUnstakingPeriodProvided ...",
  673. }
  674. }
  675. }
  676. impl rstd::convert::From<WrappedError<members::ControllerAccountForMemberCheckFailed>> for &str {
  677. fn from(wrapper: WrappedError<members::ControllerAccountForMemberCheckFailed>) -> Self {
  678. match wrapper.error {
  679. members::ControllerAccountForMemberCheckFailed::NotMember => "Is not a member",
  680. members::ControllerAccountForMemberCheckFailed::NotControllerAccount => {
  681. "Account is not controller account of member"
  682. }
  683. }
  684. }
  685. }
  686. impl rstd::convert::From<WrappedError<hiring::AddApplicationError>> for &str {
  687. fn from(wrapper: WrappedError<hiring::AddApplicationError>) -> Self {
  688. match wrapper.error {
  689. hiring::AddApplicationError::OpeningDoesNotExist => "OpeningDoesNotExist",
  690. hiring::AddApplicationError::StakeProvidedWhenRedundant(_stake_purpose) => {
  691. "StakeProvidedWhenRedundant ..."
  692. }
  693. hiring::AddApplicationError::StakeMissingWhenRequired(_stake_purpose) => {
  694. "StakeMissingWhenRequired ..."
  695. }
  696. hiring::AddApplicationError::StakeAmountTooLow(_stake_purpose) => {
  697. "StakeAmountTooLow ..."
  698. }
  699. hiring::AddApplicationError::OpeningNotInAcceptingApplicationsStage => {
  700. "OpeningNotInAcceptingApplicationsStage"
  701. }
  702. hiring::AddApplicationError::NewApplicationWasCrowdedOut => {
  703. "NewApplicationWasCrowdedOut"
  704. }
  705. }
  706. }
  707. }
  708. impl rstd::convert::From<WrappedError<members::MemberControllerAccountDidNotSign>> for &str {
  709. fn from(wrapper: WrappedError<members::MemberControllerAccountDidNotSign>) -> Self {
  710. match wrapper.error {
  711. members::MemberControllerAccountDidNotSign::UnsignedOrigin => "Unsigned origin",
  712. members::MemberControllerAccountDidNotSign::MemberIdInvalid => "Member id is invalid",
  713. members::MemberControllerAccountDidNotSign::SignerControllerAccountMismatch => {
  714. "Signer does not match controller account"
  715. }
  716. }
  717. }
  718. }
  719. // ======================================================================== //
  720. decl_storage! {
  721. trait Store for Module<T: Trait> as ContentWorkingGroup {
  722. /// The mint currently funding the rewards for this module.
  723. pub Mint get(mint) config(): <T as minting::Trait>::MintId;
  724. /// The current lead.
  725. pub CurrentLeadId get(current_lead_id) config(): Option<LeadId<T>>;
  726. /// Maps identifier to corresponding lead.
  727. pub LeadById get(lead_by_id) config(): linked_map LeadId<T> => Lead<T::AccountId, T::RewardRelationshipId, T::BlockNumber>;
  728. /// Next identifier for new current lead.
  729. pub NextLeadId get(next_lead_id) config(): LeadId<T>;
  730. /// Maps identifeir to curator opening.
  731. pub CuratorOpeningById get(curator_opening_by_id) config(): linked_map CuratorOpeningId<T> => CuratorOpening<T::OpeningId, T::BlockNumber, BalanceOf<T>, CuratorApplicationId<T>>;
  732. /// Next identifier valuefor new curator opening.
  733. pub NextCuratorOpeningId get(next_curator_opening_id) config(): CuratorOpeningId<T>;
  734. /// Maps identifier to curator application on opening.
  735. pub CuratorApplicationById get(curator_application_by_id) config(): linked_map CuratorApplicationId<T> => CuratorApplication<T::AccountId, CuratorOpeningId<T>, T::MemberId, T::ApplicationId>;
  736. /// Next identifier value for new curator application.
  737. pub NextCuratorApplicationId get(next_curator_application_id) config(): CuratorApplicationId<T>;
  738. /// Maps identifier to corresponding channel.
  739. pub ChannelById get(channel_by_id) config(): linked_map ChannelId<T> => Channel<T::MemberId, T::AccountId, T::BlockNumber, PrincipalId<T>>;
  740. /// Identifier to be used by the next channel introduced.
  741. pub NextChannelId get(next_channel_id) config(): ChannelId<T>;
  742. /// Maps (unique) channel handle to the corresponding identifier for the channel.
  743. /// Mapping is required to allow efficient (O(log N)) on-chain verification that a proposed handle is indeed unique
  744. /// at the time it is being proposed.
  745. pub ChannelIdByName get(channel_id_by_handle) config(): linked_map Vec<u8> => ChannelId<T>;
  746. /// Maps identifier to corresponding curator.
  747. pub CuratorById get(curator_by_id) config(): linked_map CuratorId<T> => Curator<T::AccountId, T::RewardRelationshipId, T::StakeId, T::BlockNumber, LeadId<T>, CuratorApplicationId<T>, PrincipalId<T>>;
  748. /// Next identifier for new curator.
  749. pub NextCuratorId get(next_curator_id) config(): CuratorId<T>;
  750. /// Maps identifier to principal.
  751. pub PrincipalById get(principal_by_id) config(): linked_map PrincipalId<T> => Principal<CuratorId<T>, ChannelId<T>>;
  752. /// Next identifier for
  753. pub NextPrincipalId get(next_principal_id) config(): PrincipalId<T>;
  754. /// Whether it is currently possible to create a channel via `create_channel` extrinsic.
  755. pub ChannelCreationEnabled get(channel_creation_enabled) config(): bool;
  756. /// Recover curator by the role stake which is currently unstaking.
  757. pub UnstakerByStakeId get(unstaker_by_stake_id) config(): linked_map StakeId<T> => WorkingGroupUnstaker<LeadId<T>, CuratorId<T>>;
  758. // Limits
  759. /// Limits the total number of curators which can be active.
  760. //pub MaxSimultanouslyActiveCurators get(max_simultanously_active_curators) config(): Option<u16>;
  761. // Limits the total number of openings which are not yet deactivated.
  762. // pub MaxSimultaneouslyActiveOpenings get(max_simultaneously_active_openings) config(): Option<u16>,
  763. // Vector length input guards
  764. pub ChannelHandleConstraint get(channel_handle_constraint) config(): InputValidationLengthConstraint;
  765. pub ChannelDescriptionConstraint get(channel_description_constraint) config(): InputValidationLengthConstraint;
  766. pub OpeningHumanReadableText get(opening_human_readble_text) config(): InputValidationLengthConstraint;
  767. pub CuratorApplicationHumanReadableText get(curator_application_human_readable_text) config(): InputValidationLengthConstraint;
  768. pub CuratorExitRationaleText get(curator_exit_rationale_text) config(): InputValidationLengthConstraint;
  769. }
  770. }
  771. decl_event! {
  772. pub enum Event<T> where
  773. ChannelId = ChannelId<T>,
  774. LeadId = LeadId<T>,
  775. CuratorOpeningId = CuratorOpeningId<T>,
  776. CuratorApplicationId = CuratorApplicationId<T>,
  777. CuratorId = CuratorId<T>,
  778. <T as system::Trait>::AccountId,
  779. {
  780. ChannelCreated(ChannelId),
  781. ChannelOwnershipTransferred(ChannelId),
  782. LeadSet(LeadId),
  783. LeadUnset(LeadId),
  784. CuratorOpeningAdded(CuratorOpeningId),
  785. //LeadRewardUpdated
  786. //LeadRoleAccountUpdated
  787. //LeadRewardAccountUpdated
  788. //PermissionGroupAdded
  789. //PermissionGroupUpdated
  790. AcceptedCuratorApplications(CuratorOpeningId),
  791. BeganCuratorApplicationReview(CuratorOpeningId),
  792. CuratorOpeningFilled(CuratorOpeningId, BTreeSet<CuratorApplicationId>),
  793. //CuratorSlashed
  794. TerminatedCurator(CuratorId),
  795. AppliedOnCuratorOpening(CuratorOpeningId, CuratorApplicationId),
  796. //CuratorRewardUpdated
  797. //CuratorRoleAccountUpdated
  798. //CuratorRewardAccountUpdated
  799. CuratorExited(CuratorId),
  800. CuratorUnstaking(CuratorId),
  801. CuratorApplicationTerminated(CuratorApplicationId),
  802. CuratorApplicationWithdrawn(CuratorApplicationId),
  803. CuratorRoleAccountUpdated(CuratorId, AccountId),
  804. CuratorRewardAccountUpdated(CuratorId, AccountId),
  805. ChannelUpdatedByCurationActor(ChannelId),
  806. }
  807. }
  808. decl_module! {
  809. pub struct Module<T: Trait> for enum Call where origin: T::Origin {
  810. fn deposit_event() = default;
  811. /*
  812. * Channel management
  813. */
  814. /// Create a new channel.
  815. pub fn create_channel(origin, owner: T::MemberId, role_account: T::AccountId, channel_name: Vec<u8>, description: Vec<u8>, content: ChannelContentType) {
  816. // Ensure that it is signed
  817. let signer_account = ensure_signed(origin)?;
  818. // Ensure that owner member can authenticate with signer account
  819. ensure_on_wrapped_error!(
  820. members::Module::<T>::ensure_is_controller_account_for_member(&owner, &signer_account)
  821. )?;
  822. // Ensure it is currently possible to create channels (ChannelCreationEnabled).
  823. ensure!(
  824. ChannelCreationEnabled::get(),
  825. MSG_CHANNEL_CREATION_DISABLED
  826. );
  827. // Ensure prospective owner member is currently allowed to become channel owner
  828. let (member_in_role, next_channel_id) = Self::ensure_can_register_channel_owner_role_on_member(&owner, None)?;
  829. // Ensure channel name is acceptable length
  830. Self::ensure_channel_name_is_valid(&channel_name)?;
  831. // Ensure description is acceptable length
  832. Self::ensure_channel_description_is_valid(&description)?;
  833. //
  834. // == MUTATION SAFE ==
  835. //
  836. // Make and add new principal
  837. let principal_id = Self::add_new_principal(&Principal::ChannelOwner(next_channel_id));
  838. // Construct channel
  839. let new_channel = Channel {
  840. channel_name: channel_name.clone(),
  841. verified: false,
  842. description: description,
  843. content: content,
  844. owner: owner,
  845. role_account: role_account,
  846. publishing_status: ChannelPublishingStatus::NotPublished,
  847. curation_status: ChannelCurationStatus::Normal,
  848. created: <system::Module<T>>::block_number(),
  849. principal_id: principal_id
  850. };
  851. // Add channel to ChannelById under id
  852. ChannelById::<T>::insert(next_channel_id, new_channel);
  853. // Add id to ChannelIdByName under handle
  854. ChannelIdByName::<T>::insert(channel_name.clone(), next_channel_id);
  855. // Increment NextChannelId
  856. NextChannelId::<T>::mutate(|id| *id += <ChannelId<T> as One>::one());
  857. /// CREDENTIAL STUFF ///
  858. // Dial out to membership module and inform about new role as channe owner.
  859. let registered_role = <members::Module<T>>::register_role_on_member(owner, &member_in_role).is_ok();
  860. assert!(registered_role);
  861. // Trigger event
  862. Self::deposit_event(RawEvent::ChannelCreated(next_channel_id));
  863. }
  864. /// An owner transfers channel ownership to a new owner.
  865. ///
  866. /// Notice that working group participants cannot do this.
  867. /// Notice that censored or unpublished channel may still be transferred.
  868. /// Notice that transfers are unilateral, so new owner cannot block. This may be problematic: https://github.com/Joystream/substrate-runtime-joystream/issues/95
  869. pub fn transfer_channel_ownership(origin, channel_id: ChannelId<T>, new_owner: T::MemberId, new_role_account: T::AccountId) {
  870. // Ensure channel owner has signed
  871. let channel = Self::ensure_channel_owner_signed(origin, &channel_id)?;
  872. // Ensure prospective new owner can actually become a channel owner
  873. let (new_owner_as_channel_owner, _next_channel_id) = Self::ensure_can_register_channel_owner_role_on_member(&new_owner, Some(channel_id))?;
  874. //
  875. // == MUTATION SAFE ==
  876. //
  877. // Construct new channel with altered properties
  878. let new_channel = Channel {
  879. owner: new_owner,
  880. role_account: new_role_account.clone(),
  881. ..channel
  882. };
  883. // Overwrite entry in ChannelById
  884. ChannelById::<T>::insert(channel_id, new_channel);
  885. // Remove
  886. let unregistered_role = <members::Module<T>>::unregister_role(role_types::ActorInRole::new(role_types::Role::ChannelOwner, channel_id)).is_ok();
  887. assert!(unregistered_role);
  888. // Dial out to membership module and inform about new role as channe owner.
  889. let registered_role = <members::Module<T>>::register_role_on_member(
  890. new_owner,
  891. &new_owner_as_channel_owner)
  892. .is_ok();
  893. assert!(registered_role);
  894. // Trigger event
  895. Self::deposit_event(RawEvent::ChannelOwnershipTransferred(channel_id));
  896. }
  897. /// Channel owner updates some channel properties
  898. pub fn update_channel_as_owner(
  899. origin,
  900. channel_id: ChannelId<T>,
  901. new_channel_name: Option<Vec<u8>>,
  902. new_description: Option<Vec<u8>>,
  903. new_publishing_status: Option<ChannelPublishingStatus>) {
  904. // Ensure channel owner has signed
  905. Self::ensure_channel_owner_signed(origin, &channel_id)?;
  906. // If set, ensure handle is acceptable length
  907. if let Some(ref channel_name) = new_channel_name {
  908. Self::ensure_channel_name_is_valid(channel_name)?;
  909. }
  910. // If set, ensure description is acceptable length
  911. if let Some(ref description) = new_description {
  912. Self::ensure_channel_description_is_valid(description)?;
  913. }
  914. //
  915. // == MUTATION SAFE ==
  916. //
  917. Self::update_channel(
  918. &channel_id,
  919. &None,
  920. &None,
  921. &new_description,
  922. &new_publishing_status,
  923. &None
  924. );
  925. }
  926. /// Update channel as a curation actor
  927. pub fn update_channel_as_curation_actor(
  928. origin,
  929. curation_actor: CurationActor<CuratorId<T>>,
  930. channel_id: ChannelId<T>,
  931. new_verified: Option<bool>,
  932. new_description: Option<Vec<u8>>,
  933. new_curation_status: Option<ChannelCurationStatus>
  934. ) {
  935. // Ensure curation actor signed
  936. Self::ensure_curation_actor_signed(origin, &curation_actor)?;
  937. // If set, ensure description is acceptable length
  938. if let Some(ref description) = new_description {
  939. Self::ensure_channel_description_is_valid(description)?;
  940. }
  941. //
  942. // == MUTATION SAFE ==
  943. //
  944. Self::update_channel(
  945. &channel_id,
  946. &None,
  947. &new_verified,
  948. &new_description,
  949. &None,
  950. &new_curation_status
  951. );
  952. }
  953. /// Add an opening for a curator role.
  954. pub fn add_curator_opening(origin, activate_at: hiring::ActivateOpeningAt<T::BlockNumber>, commitment: OpeningPolicyCommitment<T::BlockNumber, BalanceOf<T>>, human_readable_text: Vec<u8>) {
  955. // Ensure lead is set and is origin signer
  956. Self::ensure_origin_is_set_lead(origin)?;
  957. // Ensure human radable text is valid
  958. Self::ensure_opening_human_readable_text_is_valid(&human_readable_text)?;
  959. // Add opening
  960. // NB: This call can in principle fail, because the staking policies
  961. // may not respect the minimum currency requirement.
  962. let policy_commitment = commitment.clone();
  963. let opening_id = ensure_on_wrapped_error!(
  964. hiring::Module::<T>::add_opening(
  965. activate_at,
  966. commitment.max_review_period_length,
  967. commitment.application_rationing_policy,
  968. commitment.application_staking_policy,
  969. commitment.role_staking_policy,
  970. human_readable_text,
  971. ))?;
  972. //
  973. // == MUTATION SAFE ==
  974. //
  975. let new_curator_opening_id = NextCuratorOpeningId::<T>::get();
  976. // Create and add curator opening.
  977. let new_opening_by_id = CuratorOpening {
  978. opening_id : opening_id,
  979. curator_applications: BTreeSet::new(),
  980. policy_commitment: policy_commitment
  981. };
  982. CuratorOpeningById::<T>::insert(new_curator_opening_id, new_opening_by_id);
  983. // Update NextCuratorOpeningId
  984. NextCuratorOpeningId::<T>::mutate(|id| *id += <CuratorOpeningId<T> as One>::one());
  985. // Trigger event
  986. Self::deposit_event(RawEvent::CuratorOpeningAdded(new_curator_opening_id));
  987. }
  988. /// Begin accepting curator applications to an opening that is active.
  989. pub fn accept_curator_applications(origin, curator_opening_id: CuratorOpeningId<T>) {
  990. // Ensure lead is set and is origin signer
  991. Self::ensure_origin_is_set_lead(origin)?;
  992. // Ensure opening exists in this working group
  993. // NB: Even though call to hiring modul will have implicit check for
  994. // existence of opening as well, this check is to make sure that the opening is for
  995. // this working group, not something else.
  996. let (curator_opening, _opening) = Self::ensure_curator_opening_exists(&curator_opening_id)?;
  997. // Attempt to begin accepting applicationsa
  998. // NB: Combined ensure check and mutation in hiring module
  999. ensure_on_wrapped_error!(
  1000. hiring::Module::<T>::begin_accepting_applications(curator_opening.opening_id)
  1001. )?;
  1002. //
  1003. // == MUTATION SAFE ==
  1004. //
  1005. // Trigger event
  1006. Self::deposit_event(RawEvent::AcceptedCuratorApplications(curator_opening_id));
  1007. }
  1008. /// Begin reviewing, and therefore not accepting new applications.
  1009. pub fn begin_curator_applicant_review(origin, curator_opening_id: CuratorOpeningId<T>) {
  1010. // Ensure lead is set and is origin signer
  1011. let (_lead_id, _lead) = Self::ensure_origin_is_set_lead(origin)?;
  1012. // Ensure opening exists
  1013. // NB: Even though call to hiring modul will have implicit check for
  1014. // existence of opening as well, this check is to make sure that the opening is for
  1015. // this working group, not something else.
  1016. let (curator_opening, _opening) = Self::ensure_curator_opening_exists(&curator_opening_id)?;
  1017. // Attempt to begin review of applications
  1018. // NB: Combined ensure check and mutation in hiring module
  1019. ensure_on_wrapped_error!(
  1020. hiring::Module::<T>::begin_review(curator_opening.opening_id)
  1021. )?;
  1022. //
  1023. // == MUTATION SAFE ==
  1024. //
  1025. // Trigger event
  1026. Self::deposit_event(RawEvent::BeganCuratorApplicationReview(curator_opening_id));
  1027. }
  1028. /// Fill opening for curator
  1029. pub fn fill_curator_opening(
  1030. origin,
  1031. curator_opening_id: CuratorOpeningId<T>,
  1032. successful_curator_application_ids: BTreeSet<CuratorApplicationId<T>>
  1033. ) {
  1034. // Ensure lead is set and is origin signer
  1035. let (lead_id, _lead) = Self::ensure_origin_is_set_lead(origin)?;
  1036. // Ensure curator opening exists
  1037. let (curator_opening, _) = Self::ensure_curator_opening_exists(&curator_opening_id)?;
  1038. // Make iterator over successful curator application
  1039. let successful_iter = successful_curator_application_ids
  1040. .iter()
  1041. // recover curator application from id
  1042. .map(|curator_application_id| { Self::ensure_curator_application_exists(curator_application_id) })
  1043. // remove Err cases, i.e. non-existing applications
  1044. .filter_map(|result| result.ok());
  1045. // Count number of successful curators provided
  1046. let num_provided_successful_curator_application_ids = successful_curator_application_ids.len();
  1047. // Ensure all curator applications exist
  1048. let number_of_successful_applications = successful_iter
  1049. .clone()
  1050. .collect::<Vec<_>>()
  1051. .len();
  1052. ensure!(
  1053. number_of_successful_applications == num_provided_successful_curator_application_ids,
  1054. MSG_SUCCESSFUL_CURATOR_APPLICATION_DOES_NOT_EXIST
  1055. );
  1056. // Attempt to fill opening
  1057. let successful_application_ids = successful_iter
  1058. .clone()
  1059. .map(|(successful_curator_application, _, _)| successful_curator_application.application_id)
  1060. .collect::<BTreeSet<_>>();
  1061. // Ensure all applications are from members that _still_ can step into the given role
  1062. let num_successful_applications_that_can_register_as_curator = successful_iter
  1063. .clone()
  1064. .map(|(successful_curator_application, _, _)| successful_curator_application.member_id)
  1065. .filter_map(|successful_member_id| Self::ensure_can_register_curator_role_on_member(&successful_member_id).ok() )
  1066. .collect::<Vec<_>>().len();
  1067. ensure!(
  1068. num_successful_applications_that_can_register_as_curator == num_provided_successful_curator_application_ids,
  1069. MSG_MEMBER_NO_LONGER_REGISTRABLE_AS_CURATOR
  1070. );
  1071. // NB: Combined ensure check and mutation in hiring module
  1072. ensure_on_wrapped_error!(
  1073. hiring::Module::<T>::fill_opening(
  1074. curator_opening.opening_id,
  1075. successful_application_ids,
  1076. curator_opening.policy_commitment.fill_opening_successful_applicant_application_stake_unstaking_period,
  1077. curator_opening.policy_commitment.fill_opening_failed_applicant_application_stake_unstaking_period,
  1078. curator_opening.policy_commitment.fill_opening_failed_applicant_role_stake_unstaking_period
  1079. )
  1080. )?;
  1081. //
  1082. // == MUTATION SAFE ==
  1083. //
  1084. let current_block = <system::Module<T>>::block_number();
  1085. // For each successful application
  1086. // - create and hold on to curator
  1087. // - register role with membership module
  1088. successful_iter
  1089. .clone()
  1090. .for_each(|(successful_curator_application, id, _)| {
  1091. // No reward is established by default
  1092. let reward_relationship: Option<RewardRelationshipId<T>> = None;
  1093. // Get possible stake for role
  1094. let application = hiring::ApplicationById::<T>::get(successful_curator_application.application_id);
  1095. // Staking profile for curator
  1096. let stake_profile =
  1097. if let Some(ref stake_id) = application.active_role_staking_id {
  1098. Some(
  1099. CuratorRoleStakeProfile::new(
  1100. stake_id,
  1101. &curator_opening.policy_commitment.terminate_curator_role_stake_unstaking_period,
  1102. &curator_opening.policy_commitment.exit_curator_role_stake_unstaking_period
  1103. )
  1104. )
  1105. } else {
  1106. None
  1107. };
  1108. // Get curator id
  1109. let new_curator_id = NextCuratorId::<T>::get();
  1110. // Make and add new principal
  1111. let principal_id = Self::add_new_principal(&Principal::Curator(new_curator_id));
  1112. // Construct curator
  1113. let curator = Curator::new(
  1114. &(successful_curator_application.role_account),
  1115. &reward_relationship,
  1116. &stake_profile,
  1117. &CuratorRoleStage::Active,
  1118. &CuratorInduction::new(&lead_id, &id, &current_block),
  1119. //false,
  1120. &principal_id
  1121. );
  1122. // Store curator
  1123. CuratorById::<T>::insert(new_curator_id, curator);
  1124. // Register role on member
  1125. let registered_role = members::Module::<T>::register_role_on_member(
  1126. successful_curator_application.member_id,
  1127. &role_types::ActorInRole::new(role_types::Role::Curator, new_curator_id)
  1128. ).is_ok();
  1129. assert!(registered_role);
  1130. // Update next curator id
  1131. NextCuratorId::<T>::mutate(|id| *id += <CuratorId<T> as One>::one());
  1132. });
  1133. // Trigger event
  1134. Self::deposit_event(RawEvent::CuratorOpeningFilled(curator_opening_id, successful_curator_application_ids));
  1135. }
  1136. /*
  1137. /// ...
  1138. pub fn update_curator_reward(_origin) {
  1139. }
  1140. */
  1141. /*
  1142. /// ...
  1143. pub fn slash_curator(_origin) {
  1144. }
  1145. */
  1146. pub fn withdraw_curator_application(
  1147. origin,
  1148. curator_application_id: CuratorApplicationId<T>
  1149. ) {
  1150. // Ensuring curator application actually exists
  1151. let (curator_application, _, curator_opening) = Self::ensure_curator_application_exists(&curator_application_id)?;
  1152. // Ensure that it is signed
  1153. let signer_account = ensure_signed(origin)?;
  1154. // Ensure that signer is applicant role account
  1155. ensure!(
  1156. signer_account == curator_application.role_account,
  1157. MSG_ORIGIN_IS_NOT_APPLICANT
  1158. );
  1159. // Attempt to deactivate application
  1160. // NB: Combined ensure check and mutation in hiring module
  1161. ensure_on_wrapped_error!(
  1162. hiring::Module::<T>::deactive_application(
  1163. curator_application.application_id,
  1164. curator_opening.policy_commitment.exit_curator_role_application_stake_unstaking_period,
  1165. curator_opening.policy_commitment.exit_curator_role_stake_unstaking_period
  1166. )
  1167. )?;
  1168. //
  1169. // == MUTATION SAFE ==
  1170. //
  1171. // Trigger event
  1172. Self::deposit_event(RawEvent::CuratorApplicationWithdrawn(curator_application_id));
  1173. }
  1174. /// Lead terminate curator application
  1175. pub fn terminate_curator_application(
  1176. origin,
  1177. curator_application_id: CuratorApplicationId<T>
  1178. ) {
  1179. // Ensure lead is set and is origin signer
  1180. Self::ensure_origin_is_set_lead(origin)?;
  1181. // Ensuring curator application actually exists
  1182. let (curator_application, _, curator_opening) = Self::ensure_curator_application_exists(&curator_application_id)?;
  1183. // Attempt to deactivate application
  1184. // NB: Combined ensure check and mutation in hiring module
  1185. ensure_on_wrapped_error!(
  1186. hiring::Module::<T>::deactive_application(
  1187. curator_application.application_id,
  1188. curator_opening.policy_commitment.terminate_curator_application_stake_unstaking_period,
  1189. curator_opening.policy_commitment.terminate_curator_role_stake_unstaking_period
  1190. )
  1191. )?;
  1192. //
  1193. // == MUTATION SAFE ==
  1194. //
  1195. // Trigger event
  1196. Self::deposit_event(RawEvent::CuratorApplicationTerminated(curator_application_id));
  1197. }
  1198. /// Apply on a curator opening.
  1199. pub fn apply_on_curator_opening(
  1200. origin,
  1201. member_id: T::MemberId,
  1202. curator_opening_id: CuratorOpeningId<T>,
  1203. role_account: T::AccountId,
  1204. source_account: T::AccountId,
  1205. opt_role_stake_balance: Option<BalanceOf<T>>,
  1206. opt_application_stake_balance: Option<BalanceOf<T>>,
  1207. human_readable_text: Vec<u8>
  1208. ) {
  1209. // Ensure that origin is signed by member with given id.
  1210. ensure_on_wrapped_error!(
  1211. members::Module::<T>::ensure_member_controller_account_signed(origin, &member_id)
  1212. )?;
  1213. // Ensure curator opening exists
  1214. let (curator_opening, _opening) = Self::ensure_curator_opening_exists(&curator_opening_id)?;
  1215. // Ensure new owner can actually become a curator
  1216. let (_member_as_curator, _new_curator_id) = Self::ensure_can_register_curator_role_on_member(&member_id)?;
  1217. // Ensure that there is sufficient balance to cover stake proposed
  1218. Self::ensure_can_make_stake_imbalance(
  1219. vec![&opt_role_stake_balance, &opt_application_stake_balance],
  1220. &source_account)
  1221. .map_err(|_err| MSG_INSUFFICIENT_BALANCE_TO_APPLY)?;
  1222. // Ensure application text is valid
  1223. Self::ensure_curator_application_text_is_valid(&human_readable_text)?;
  1224. // Ensure application can actually be added
  1225. ensure_on_wrapped_error!(
  1226. hiring::Module::<T>::ensure_can_add_application(curator_opening.opening_id, opt_role_stake_balance, opt_application_stake_balance)
  1227. )?;
  1228. //
  1229. // == MUTATION SAFE ==
  1230. //
  1231. // Make imbalances for staking
  1232. let opt_role_stake_imbalance = Self::make_stake_opt_imbalance(&opt_role_stake_balance, &source_account);
  1233. let opt_application_stake_imbalance = Self::make_stake_opt_imbalance(&opt_application_stake_balance, &source_account);
  1234. // Call hiring module to add application
  1235. let add_application_result = hiring::Module::<T>::add_application(
  1236. curator_opening.opening_id,
  1237. opt_role_stake_imbalance,
  1238. opt_application_stake_imbalance,
  1239. human_readable_text
  1240. );
  1241. // Has to hold
  1242. assert!(add_application_result.is_ok());
  1243. let application_id = add_application_result.unwrap().application_id_added;
  1244. // Get id of new curator application
  1245. let new_curator_application_id = NextCuratorApplicationId::<T>::get();
  1246. // Make curator application
  1247. let curator_application = CuratorApplication::new(&role_account, &curator_opening_id, &member_id, &application_id);
  1248. // Store application
  1249. CuratorApplicationById::<T>::insert(new_curator_application_id, curator_application);
  1250. // Update next curator application identifier value
  1251. NextCuratorApplicationId::<T>::mutate(|id| *id += <CuratorApplicationId<T> as One>::one());
  1252. // Add application to set of application in curator opening
  1253. CuratorOpeningById::<T>::mutate(curator_opening_id, |curator_opening| {
  1254. curator_opening.curator_applications.insert(new_curator_application_id);
  1255. });
  1256. // Trigger event
  1257. Self::deposit_event(RawEvent::AppliedOnCuratorOpening(curator_opening_id, new_curator_application_id));
  1258. }
  1259. /// An active curator can update the associated role account.
  1260. pub fn update_curator_role_account(
  1261. origin,
  1262. member_id: T::MemberId,
  1263. curator_id: CuratorId<T>,
  1264. new_role_account: T::AccountId
  1265. ) {
  1266. // Ensure that origin is signed by member with given id.
  1267. ensure_on_wrapped_error!(
  1268. members::Module::<T>::ensure_member_controller_account_signed(origin, &member_id)
  1269. )?;
  1270. // Ensure that member is this curator
  1271. let actor_in_role = role_types::ActorInRole::new(role_types::Role::Curator, curator_id);
  1272. ensure!(
  1273. members::MembershipIdByActorInRole::<T>::get(actor_in_role) == member_id,
  1274. MSG_CURATOR_NOT_CONTROLLED_BY_MEMBER
  1275. );
  1276. //
  1277. // == MUTATION SAFE ==
  1278. //
  1279. // Update role account
  1280. CuratorById::<T>::mutate(curator_id, |curator| {
  1281. curator.role_account = new_role_account.clone()
  1282. });
  1283. // Trigger event
  1284. Self::deposit_event(RawEvent::CuratorRoleAccountUpdated(curator_id, new_role_account));
  1285. }
  1286. /// An active curator can update the reward account associated
  1287. /// with a set reward relationship.
  1288. pub fn update_curator_reward_account(
  1289. origin,
  1290. curator_id: CuratorId<T>,
  1291. new_reward_account: T::AccountId
  1292. ) {
  1293. // Ensure there is a signer which matches role account of curator corresponding to provided id.
  1294. let curator = Self::ensure_active_curator_signed(origin, &curator_id)?;
  1295. // Ensure the curator actually has a recurring reward
  1296. let relationship_id = Self::ensure_curator_has_recurring_reward(&curator)?;
  1297. //
  1298. // == MUTATION SAFE ==
  1299. //
  1300. // Update, only, reward account.
  1301. recurringrewards::Module::<T>::set_reward_relationship(
  1302. relationship_id,
  1303. Some(new_reward_account.clone()), // new_account
  1304. None, // new_payout
  1305. None, //new_next_payment_at
  1306. None //new_payout_interval
  1307. )
  1308. .expect("Must be set, since curator has recurring reward");
  1309. // Trigger event
  1310. Self::deposit_event(RawEvent::CuratorRewardAccountUpdated(curator_id, new_reward_account));
  1311. }
  1312. /// An active curator leaves role
  1313. pub fn leave_curator_role(
  1314. origin,
  1315. curator_id: CuratorId<T>,
  1316. rationale_text: Vec<u8>
  1317. ) {
  1318. // Ensure there is a signer which matches role account of curator corresponding to provided id.
  1319. let active_curator = Self::ensure_active_curator_signed(origin, &curator_id)?;
  1320. //
  1321. // == MUTATION SAFE ==
  1322. //
  1323. Self::deactivate_curator(
  1324. &curator_id,
  1325. &active_curator,
  1326. &CuratorExitInitiationOrigin::Curator,
  1327. &rationale_text
  1328. );
  1329. }
  1330. /// Lead can terminate and active curator
  1331. pub fn terminate_curator_role(
  1332. origin,
  1333. curator_id: CuratorId<T>,
  1334. rationale_text: Vec<u8>
  1335. ) {
  1336. // Ensure lead is set and is origin signer
  1337. Self::ensure_origin_is_set_lead(origin)?;
  1338. // Ensuring curator actually exists and is active
  1339. let curator = Self::ensure_active_curator_exists(&curator_id)?;
  1340. // Ensure rationale text is valid
  1341. Self::ensure_curator_exit_rationale_text_is_valid(&rationale_text)?;
  1342. //
  1343. // == MUTATION SAFE ==
  1344. //
  1345. Self::deactivate_curator(
  1346. &curator_id,
  1347. &curator,
  1348. &CuratorExitInitiationOrigin::Lead,
  1349. &rationale_text
  1350. );
  1351. }
  1352. /*
  1353. * Root origin routines for managing lead.
  1354. */
  1355. /// Introduce a lead when one is not currently set.
  1356. pub fn set_lead(origin, member: T::MemberId, role_account: T::AccountId) {
  1357. // Ensure root is origin
  1358. ensure_root(origin)?;
  1359. // Ensure there is no current lead
  1360. ensure!(
  1361. <CurrentLeadId<T>>::get().is_none(),
  1362. MSG_CURRENT_LEAD_ALREADY_SET
  1363. );
  1364. // Ensure that member can actually become lead
  1365. let new_lead_id = <NextLeadId<T>>::get();
  1366. let _profile = <members::Module<T>>::can_register_role_on_member(
  1367. &member,
  1368. &role_types::ActorInRole::new(role_types::Role::CuratorLead, new_lead_id)
  1369. )?;
  1370. //
  1371. // == MUTATION SAFE ==
  1372. //
  1373. // Construct lead
  1374. let new_lead = Lead{
  1375. role_account: role_account.clone(),
  1376. reward_relationship: None,
  1377. inducted: <system::Module<T>>::block_number(),
  1378. stage: LeadRoleState::Active
  1379. };
  1380. // Store lead
  1381. <LeadById<T>>::insert(new_lead_id, new_lead);
  1382. // Update current lead
  1383. <CurrentLeadId<T>>::put(new_lead_id); // Some(new_lead_id)
  1384. // Update next lead counter
  1385. <NextLeadId<T>>::mutate(|id| *id += <LeadId<T> as One>::one());
  1386. // Trigger event
  1387. Self::deposit_event(RawEvent::LeadSet(new_lead_id));
  1388. }
  1389. /// Evict the currently unset lead
  1390. pub fn unset_lead(origin) {
  1391. // Ensure root is origin
  1392. ensure_root(origin)?;
  1393. // Ensure there is a lead set
  1394. let (lead_id,lead) = Self::ensure_lead_is_set()?;
  1395. //
  1396. // == MUTATION SAFE ==
  1397. //
  1398. // Unregister from role in membership model
  1399. let current_lead_role = role_types::ActorInRole{
  1400. role: role_types::Role::CuratorLead,
  1401. actor_id: lead_id
  1402. };
  1403. let unregistered_role = <members::Module<T>>::unregister_role(current_lead_role).is_ok();
  1404. assert!(unregistered_role);
  1405. // Update lead stage as exited
  1406. let current_block = <system::Module<T>>::block_number();
  1407. let new_lead = Lead{
  1408. stage: LeadRoleState::Exited(ExitedLeadRole { initiated_at_block_number: current_block}),
  1409. ..lead
  1410. };
  1411. <LeadById<T>>::insert(lead_id, new_lead);
  1412. // Update current lead
  1413. <CurrentLeadId<T>>::take(); // None
  1414. // Trigger event
  1415. Self::deposit_event(RawEvent::LeadUnset(lead_id));
  1416. }
  1417. /// The stake, with the given id, was unstaked.
  1418. pub fn unstaked(
  1419. origin,
  1420. stake_id: StakeId<T>
  1421. ) {
  1422. // Ensure its a runtime root origin
  1423. ensure_root(origin)?;
  1424. // Ensure its an unstaker in this group
  1425. let unstaker = Self::ensure_unstaker_exists(&stake_id)?;
  1426. // Get curator doing the unstaking,
  1427. // urrently the only possible unstaker in this module.
  1428. let curator_id =
  1429. if let WorkingGroupUnstaker::Curator(curator_id) = unstaker {
  1430. curator_id
  1431. } else {
  1432. panic!("Should not be possible, only curators unstake in this module currently.");
  1433. };
  1434. // Grab curator from id, unwrap, because this curator _must_ exist.
  1435. let unstaking_curator = Self::ensure_curator_exists(&curator_id).unwrap();
  1436. //
  1437. // == MUTATION SAFE ==
  1438. //
  1439. // Update stage of curator
  1440. let curator_exit_summary =
  1441. if let CuratorRoleStage::Unstaking(summary) = unstaking_curator.stage {
  1442. summary
  1443. } else {
  1444. panic!("Curator must be in unstaking stage.");
  1445. };
  1446. let new_curator = Curator{
  1447. stage: CuratorRoleStage::Exited(curator_exit_summary.clone()),
  1448. ..unstaking_curator
  1449. };
  1450. CuratorById::<T>::insert(curator_id, new_curator);
  1451. // Remove from unstaker
  1452. UnstakerByStakeId::<T>::remove(stake_id);
  1453. // Trigger event
  1454. let event = match curator_exit_summary.origin {
  1455. CuratorExitInitiationOrigin::Lead => RawEvent::TerminatedCurator(curator_id),
  1456. CuratorExitInitiationOrigin::Curator => RawEvent::CuratorExited(curator_id),
  1457. };
  1458. Self::deposit_event(event);
  1459. }
  1460. }
  1461. }
  1462. impl<T: Trait> versioned_store_permissions::CredentialChecker<T> for Module<T> {
  1463. fn account_has_credential(account: &T::AccountId, id: PrincipalId<T>) -> bool {
  1464. // Check that principal exists
  1465. if !PrincipalById::<T>::exists(&id) {
  1466. return false;
  1467. }
  1468. // Get principal
  1469. let principal = PrincipalById::<T>::get(&id);
  1470. // Get possible
  1471. let opt_prinicipal_account = match principal {
  1472. Principal::Lead => {
  1473. // Try to get lead
  1474. match Self::ensure_lead_is_set() {
  1475. Ok((_, lead)) => Some(lead.role_account),
  1476. Err(_) => None,
  1477. }
  1478. }
  1479. Principal::Curator(curator_id) => Some(
  1480. Self::ensure_curator_exists(&curator_id)
  1481. .expect("Curator must exist")
  1482. .role_account,
  1483. ),
  1484. Principal::ChannelOwner(channel_id) => Some(
  1485. Self::ensure_channel_id_is_valid(&channel_id)
  1486. .expect("Channel must exist")
  1487. .role_account,
  1488. ),
  1489. };
  1490. // Compare, possibly set, principal account with the given account
  1491. match opt_prinicipal_account {
  1492. Some(principal_account) => *account == principal_account,
  1493. None => false,
  1494. }
  1495. }
  1496. }
  1497. impl<T: Trait> Module<T> {
  1498. fn ensure_can_register_role_on_member(
  1499. member_id: &T::MemberId,
  1500. role: role_types::Role,
  1501. actor_id: &ActorIdInMembersModule<T>,
  1502. ) -> Result<members::ActorInRole<ActorIdInMembersModule<T>>, &'static str> {
  1503. let new_actor_in_role = role_types::ActorInRole::new(role, *actor_id);
  1504. <members::Module<T>>::can_register_role_on_member(member_id, &new_actor_in_role)
  1505. .map(|_| new_actor_in_role)
  1506. }
  1507. fn ensure_can_register_curator_role_on_member(
  1508. member_id: &T::MemberId,
  1509. ) -> Result<
  1510. (
  1511. members::ActorInRole<ActorIdInMembersModule<T>>,
  1512. CuratorId<T>,
  1513. ),
  1514. &'static str,
  1515. > {
  1516. let next_id = <NextCuratorId<T>>::get();
  1517. Self::ensure_can_register_role_on_member(member_id, role_types::Role::Curator, &next_id)
  1518. .map(|curator_in_role| (curator_in_role, next_id))
  1519. }
  1520. fn ensure_can_register_channel_owner_role_on_member(
  1521. member_id: &T::MemberId,
  1522. opt_channel_id: Option<ChannelId<T>>,
  1523. ) -> Result<
  1524. (
  1525. members::ActorInRole<ActorIdInMembersModule<T>>,
  1526. CuratorId<T>,
  1527. ),
  1528. &'static str,
  1529. > {
  1530. let next_channel_id = opt_channel_id.unwrap_or(NextChannelId::<T>::get());
  1531. Self::ensure_can_register_role_on_member(
  1532. member_id,
  1533. role_types::Role::ChannelOwner,
  1534. &next_channel_id,
  1535. )
  1536. .map(|member_in_role| (member_in_role, next_channel_id))
  1537. }
  1538. // TODO: convert InputConstraint ensurer routines into macroes
  1539. fn ensure_channel_name_is_valid(channel_name: &Vec<u8>) -> dispatch::Result {
  1540. ChannelHandleConstraint::get().ensure_valid(
  1541. channel_name.len(),
  1542. MSG_CHANNEL_HANDLE_TOO_SHORT,
  1543. MSG_CHANNEL_HANDLE_TOO_LONG,
  1544. )?;
  1545. // Has to not already be occupied
  1546. ensure!(
  1547. ChannelIdByName::<T>::exists(channel_name),
  1548. MSG_CHANNEL_NAME_ALREADY_TAKEN
  1549. );
  1550. Ok(())
  1551. }
  1552. fn ensure_channel_description_is_valid(description: &Vec<u8>) -> dispatch::Result {
  1553. ChannelDescriptionConstraint::get().ensure_valid(
  1554. description.len(),
  1555. MSG_CHANNEL_DESCRIPTION_TOO_SHORT,
  1556. MSG_CHANNEL_DESCRIPTION_TOO_LONG,
  1557. )
  1558. }
  1559. fn ensure_curator_application_text_is_valid(text: &Vec<u8>) -> dispatch::Result {
  1560. CuratorApplicationHumanReadableText::get().ensure_valid(
  1561. text.len(),
  1562. MSG_CURATOR_APPLICATION_TEXT_TOO_SHORT,
  1563. MSG_CURATOR_APPLICATION_TEXT_TOO_LONG,
  1564. )
  1565. }
  1566. fn ensure_curator_exit_rationale_text_is_valid(text: &Vec<u8>) -> dispatch::Result {
  1567. CuratorExitRationaleText::get().ensure_valid(
  1568. text.len(),
  1569. MSG_CURATOR_EXIT_RATIOANEL_TEXT_TOO_SHORT,
  1570. MSG_CURATOR_EXIT_RATIOANEL_TEXT_TOO_LONG,
  1571. )
  1572. }
  1573. fn ensure_opening_human_readable_text_is_valid(text: &Vec<u8>) -> dispatch::Result {
  1574. OpeningHumanReadableText::get().ensure_valid(
  1575. text.len(),
  1576. MSG_CHANNEL_DESCRIPTION_TOO_SHORT,
  1577. MSG_CHANNEL_DESCRIPTION_TOO_LONG,
  1578. )
  1579. }
  1580. fn ensure_channel_id_is_valid(
  1581. channel_id: &ChannelId<T>,
  1582. ) -> Result<Channel<T::MemberId, T::AccountId, T::BlockNumber, PrincipalId<T>>, &'static str>
  1583. {
  1584. if ChannelById::<T>::exists(channel_id) {
  1585. let channel = ChannelById::<T>::get(channel_id);
  1586. Ok(channel)
  1587. } else {
  1588. Err(MSG_CHANNEL_ID_INVALID)
  1589. }
  1590. }
  1591. fn ensure_lead_is_set() -> Result<
  1592. (
  1593. LeadId<T>,
  1594. Lead<T::AccountId, T::RewardRelationshipId, T::BlockNumber>,
  1595. ),
  1596. &'static str,
  1597. > {
  1598. // Ensure lead id is set
  1599. let lead_id = Self::ensure_lead_id_set()?;
  1600. // If so, grab actual lead
  1601. let lead = <LeadById<T>>::get(lead_id);
  1602. // and return both
  1603. Ok((lead_id, lead))
  1604. }
  1605. fn ensure_lead_id_set() -> Result<LeadId<T>, &'static str> {
  1606. let opt_current_lead_id = <CurrentLeadId<T>>::get();
  1607. if let Some(lead_id) = opt_current_lead_id {
  1608. Ok(lead_id)
  1609. } else {
  1610. Err(MSG_CURRENT_LEAD_NOT_SET)
  1611. }
  1612. }
  1613. fn ensure_origin_is_set_lead(
  1614. origin: T::Origin,
  1615. ) -> Result<
  1616. (
  1617. LeadId<T>,
  1618. Lead<T::AccountId, T::RewardRelationshipId, T::BlockNumber>,
  1619. ),
  1620. &'static str,
  1621. > {
  1622. // Ensure lead is actually set
  1623. let (lead_id, lead) = Self::ensure_lead_is_set()?;
  1624. // Ensure is signed
  1625. let signer = ensure_signed(origin)?;
  1626. // Ensure signer is lead
  1627. ensure!(signer == lead.role_account, MSG_ORIGIN_IS_NOT_LEAD);
  1628. Ok((lead_id, lead))
  1629. }
  1630. /*
  1631. fn ensure_activate_opening_at_valid(activate_at: &hiring::ActivateOpeningAt<T::BlockNumber>) -> Result<T::BlockNumber, &'static str>{
  1632. let current_block = <system::Module<T>>::block_number();
  1633. let starting_block =
  1634. match activate_at {
  1635. hiring::ActivateOpeningAt::CurrentBlock => current_block,
  1636. hiring::ActivateOpeningAt::ExactBlock(block_number) => block_number.clone()
  1637. };
  1638. ensure!(
  1639. starting_block >= current_block,
  1640. MSG_OPENING_CANNOT_ACTIVATE_IN_THE_PAST
  1641. );
  1642. Ok(starting_block)
  1643. }
  1644. */
  1645. fn ensure_curator_opening_exists(
  1646. curator_opening_id: &CuratorOpeningId<T>,
  1647. ) -> Result<
  1648. (
  1649. CuratorOpening<T::OpeningId, T::BlockNumber, BalanceOf<T>, CuratorApplicationId<T>>,
  1650. hiring::Opening<BalanceOf<T>, T::BlockNumber, <T as hiring::Trait>::ApplicationId>,
  1651. ),
  1652. &'static str,
  1653. > {
  1654. ensure!(
  1655. CuratorOpeningById::<T>::exists(curator_opening_id),
  1656. MSG_CURATOR_OPENING_DOES_NOT_EXIST
  1657. );
  1658. let curator_opening = CuratorOpeningById::<T>::get(curator_opening_id);
  1659. let opening = hiring::OpeningById::<T>::get(curator_opening.opening_id);
  1660. Ok((curator_opening, opening))
  1661. }
  1662. fn ensure_curator_exists(
  1663. curator_id: &CuratorId<T>,
  1664. ) -> Result<
  1665. Curator<
  1666. T::AccountId,
  1667. T::RewardRelationshipId,
  1668. T::StakeId,
  1669. T::BlockNumber,
  1670. LeadId<T>,
  1671. T::ApplicationId,
  1672. PrincipalId<T>,
  1673. >,
  1674. &'static str,
  1675. > {
  1676. ensure!(
  1677. CuratorById::<T>::exists(curator_id),
  1678. MSG_CURATOR_DOES_NOT_EXIST
  1679. );
  1680. let curator = CuratorById::<T>::get(curator_id);
  1681. Ok(curator)
  1682. }
  1683. fn ensure_unstaker_exists(
  1684. stake_id: &StakeId<T>,
  1685. ) -> Result<WorkingGroupUnstaker<LeadId<T>, CuratorId<T>>, &'static str> {
  1686. ensure!(
  1687. UnstakerByStakeId::<T>::exists(stake_id),
  1688. MSG_UNSTAKER_DOES_NOT_EXIST
  1689. );
  1690. let unstaker = UnstakerByStakeId::<T>::get(stake_id);
  1691. Ok(unstaker)
  1692. }
  1693. fn ensure_active_curator_exists(
  1694. curator_id: &CuratorId<T>,
  1695. ) -> Result<
  1696. Curator<
  1697. T::AccountId,
  1698. T::RewardRelationshipId,
  1699. T::StakeId,
  1700. T::BlockNumber,
  1701. LeadId<T>,
  1702. T::ApplicationId,
  1703. PrincipalId<T>,
  1704. >,
  1705. &'static str,
  1706. > {
  1707. // Ensuring curator actually exists
  1708. let curator = Self::ensure_curator_exists(curator_id)?;
  1709. // Ensure curator is still active
  1710. ensure!(
  1711. match curator.stage {
  1712. CuratorRoleStage::Active => true,
  1713. _ => false,
  1714. },
  1715. MSG_CURATOR_IS_NOT_ACTIVE
  1716. );
  1717. Ok(curator)
  1718. }
  1719. fn ensure_active_curator_signed(
  1720. origin: T::Origin,
  1721. curator_id: &CuratorId<T>,
  1722. ) -> Result<
  1723. Curator<
  1724. T::AccountId,
  1725. T::RewardRelationshipId,
  1726. T::StakeId,
  1727. T::BlockNumber,
  1728. LeadId<T>,
  1729. T::ApplicationId,
  1730. PrincipalId<T>,
  1731. >,
  1732. &'static str,
  1733. > {
  1734. // Ensure that it is signed
  1735. let signer_account = ensure_signed(origin)?;
  1736. // Ensure that id corresponds to active curator
  1737. let curator = Self::ensure_active_curator_exists(&curator_id)?;
  1738. // Ensure that signer is actually role account of curator
  1739. ensure!(
  1740. signer_account == curator.role_account,
  1741. MSG_SIGNER_IS_NOT_CURATOR_ROLE_ACCOUNT
  1742. );
  1743. Ok(curator)
  1744. }
  1745. fn ensure_curation_actor_signed(
  1746. origin: T::Origin,
  1747. curation_actor: &CurationActor<CuratorId<T>>,
  1748. ) -> Result<(), &'static str> {
  1749. match curation_actor {
  1750. CurationActor::Lead => {
  1751. // Ensure lead is set and is origin signer
  1752. Self::ensure_origin_is_set_lead(origin).map(|_| ())
  1753. }
  1754. CurationActor::Curator(curator_id) => {
  1755. // Ensure there is a signer which matches role account of curator corresponding to provided id.
  1756. Self::ensure_active_curator_signed(origin, &curator_id).map(|_| ())
  1757. }
  1758. }
  1759. }
  1760. /// Ensure origin is signed by account matching role account corresponding to the channel
  1761. fn ensure_channel_owner_signed(
  1762. origin: T::Origin,
  1763. channel_id: &ChannelId<T>,
  1764. ) -> Result<Channel<T::MemberId, T::AccountId, T::BlockNumber, PrincipalId<T>>, &'static str>
  1765. {
  1766. // Ensure that it is signed
  1767. let signer_account = ensure_signed(origin)?;
  1768. // Ensure channel id is valid
  1769. let channel = Self::ensure_channel_id_is_valid(&channel_id)?;
  1770. // Ensure origin matches channel role account
  1771. ensure!(
  1772. signer_account == channel.role_account,
  1773. MSG_ORIGIN_DOES_NOT_MATCH_CHANNEL_ROLE_ACCOUNT
  1774. );
  1775. Ok(channel)
  1776. }
  1777. fn ensure_curator_application_exists(
  1778. curator_application_id: &CuratorApplicationId<T>,
  1779. ) -> Result<
  1780. (
  1781. CuratorApplication<T::AccountId, CuratorOpeningId<T>, T::MemberId, T::ApplicationId>,
  1782. CuratorApplicationId<T>,
  1783. CuratorOpening<T::OpeningId, T::BlockNumber, BalanceOf<T>, CuratorApplicationId<T>>,
  1784. ),
  1785. &'static str,
  1786. > {
  1787. //Result<(hiring::Application<<T as hiring::Trait>::OpeningId, T::BlockNumber, <T as stake::Trait>::StakeId>, CuratorOpening<T::OpeningId, T::BlockNumber, BalanceOf<T>, CuratorApplicationId<T>> ,hiring::Opening<BalanceOf<T>, T::BlockNumber, <T as hiring::Trait>::ApplicationId>), &'static str> {
  1788. ensure!(
  1789. CuratorApplicationById::<T>::exists(curator_application_id),
  1790. MSG_CURATOR_APPLICATION_DOES_NOT_EXIST
  1791. );
  1792. let curator_application = CuratorApplicationById::<T>::get(curator_application_id);
  1793. //let application = hiring::ApplicationById::<T>::get(curator_application.application_id);
  1794. let curator_opening = CuratorOpeningById::<T>::get(curator_application.curator_opening_id);
  1795. //let opening = hiring::OpeningById::<T>::get(curator_opening.opening_id);
  1796. Ok((
  1797. curator_application,
  1798. curator_application_id.clone(),
  1799. curator_opening,
  1800. ))
  1801. }
  1802. fn ensure_curator_has_recurring_reward(
  1803. curator: &Curator<
  1804. T::AccountId,
  1805. T::RewardRelationshipId,
  1806. T::StakeId,
  1807. T::BlockNumber,
  1808. LeadId<T>,
  1809. T::ApplicationId,
  1810. PrincipalId<T>,
  1811. >,
  1812. ) -> Result<T::RewardRelationshipId, &'static str> {
  1813. ensure!(
  1814. curator.reward_relationship.is_some(),
  1815. MSG_CURATOR_HAS_NO_REWARD
  1816. );
  1817. let relationship_id = curator.reward_relationship.unwrap();
  1818. Ok(relationship_id)
  1819. }
  1820. /// CRITICAL:
  1821. /// https://github.com/Joystream/substrate-runtime-joystream/issues/92
  1822. /// This assumes that ensure_can_withdraw can be don
  1823. /// for a sum of balance that later will be actually withdrawn
  1824. /// using individual terms in that sum.
  1825. /// This needs to be fully checked across all possibly scenarios
  1826. /// of actual balance, minimum balance limit, reservation, vesting and locking.
  1827. fn ensure_can_make_stake_imbalance(
  1828. opt_balances: Vec<&Option<BalanceOf<T>>>,
  1829. source_account: &T::AccountId,
  1830. ) -> Result<(), &'static str> {
  1831. let zero_balance = <BalanceOf<T> as Zero>::zero();
  1832. // Total amount to be staked
  1833. let total_amount = opt_balances.iter().fold(zero_balance, |sum, opt_balance| {
  1834. sum + if let Some(balance) = opt_balance {
  1835. *balance
  1836. } else {
  1837. zero_balance
  1838. }
  1839. });
  1840. if total_amount > zero_balance {
  1841. let new_balance = CurrencyOf::<T>::free_balance(source_account) - total_amount;
  1842. CurrencyOf::<T>::ensure_can_withdraw(
  1843. source_account,
  1844. total_amount,
  1845. WithdrawReasons::all(),
  1846. new_balance,
  1847. )
  1848. } else {
  1849. Ok(())
  1850. }
  1851. }
  1852. fn make_stake_opt_imbalance(
  1853. opt_balance: &Option<BalanceOf<T>>,
  1854. source_account: &T::AccountId,
  1855. ) -> Option<NegativeImbalance<T>> {
  1856. if let Some(balance) = opt_balance {
  1857. let withdraw_result = CurrencyOf::<T>::withdraw(
  1858. source_account,
  1859. *balance,
  1860. WithdrawReasons::all(),
  1861. ExistenceRequirement::AllowDeath,
  1862. );
  1863. assert!(withdraw_result.is_ok());
  1864. withdraw_result.ok()
  1865. } else {
  1866. None
  1867. }
  1868. }
  1869. fn deactivate_curator(
  1870. curator_id: &CuratorId<T>,
  1871. curator: &Curator<
  1872. T::AccountId,
  1873. T::RewardRelationshipId,
  1874. T::StakeId,
  1875. T::BlockNumber,
  1876. LeadId<T>,
  1877. CuratorApplicationId<T>,
  1878. PrincipalId<T>,
  1879. >,
  1880. exit_initiation_origin: &CuratorExitInitiationOrigin,
  1881. rationale_text: &Vec<u8>,
  1882. ) {
  1883. // Stop any possible recurring rewards
  1884. let _did_deactivate_recurring_reward = if let Some(ref reward_relationship_id) =
  1885. curator.reward_relationship
  1886. {
  1887. // Attempt to deactivate
  1888. recurringrewards::Module::<T>::try_to_deactivate_relationship(*reward_relationship_id)
  1889. .expect("Relatioship must exist")
  1890. } else {
  1891. // Did not deactivate, there was no reward relationship!
  1892. false
  1893. };
  1894. // When the curator is staked, unstaking must first be initated,
  1895. // otherwise they can be terminted right away.
  1896. // Create exit summary for this termination
  1897. let current_block = <system::Module<T>>::block_number();
  1898. let curator_exit_summary =
  1899. CuratorExitSummary::new(exit_initiation_origin, &current_block, rationale_text);
  1900. // Determine new curator stage and event to emit
  1901. let (new_curator_stage, unstake_directions, event) =
  1902. if let Some(ref stake_profile) = curator.role_stake_profile {
  1903. // Determine unstaknig period based on who initiated deactivation
  1904. let unstaking_period = match curator_exit_summary.origin {
  1905. CuratorExitInitiationOrigin::Lead => stake_profile.termination_unstaking_period,
  1906. CuratorExitInitiationOrigin::Curator => stake_profile.exit_unstaking_period,
  1907. };
  1908. (
  1909. CuratorRoleStage::Unstaking(curator_exit_summary),
  1910. Some((stake_profile.stake_id.clone(), unstaking_period)),
  1911. RawEvent::CuratorUnstaking(curator_id.clone()),
  1912. )
  1913. } else {
  1914. (
  1915. CuratorRoleStage::Exited(curator_exit_summary.clone()),
  1916. None,
  1917. match curator_exit_summary.origin {
  1918. CuratorExitInitiationOrigin::Lead => {
  1919. RawEvent::TerminatedCurator(curator_id.clone())
  1920. }
  1921. CuratorExitInitiationOrigin::Curator => {
  1922. RawEvent::CuratorExited(curator_id.clone())
  1923. }
  1924. },
  1925. )
  1926. };
  1927. // Update curator
  1928. let new_curator = Curator {
  1929. stage: new_curator_stage,
  1930. ..(curator.clone())
  1931. };
  1932. CuratorById::<T>::insert(curator_id, new_curator);
  1933. // Unstake if directions provided
  1934. if let Some(directions) = unstake_directions {
  1935. // Unstake
  1936. stake::Module::<T>::initiate_unstaking(&directions.0, directions.1)
  1937. .expect("Unstaking must be possible at this time.");
  1938. }
  1939. // Trigger event
  1940. Self::deposit_event(event);
  1941. }
  1942. /// Adds the given principal to storage under the returned identifier.
  1943. fn add_new_principal(principal: &Principal<CuratorId<T>, ChannelId<T>>) -> PrincipalId<T> {
  1944. // Get principal id for curator
  1945. let principal_id = NextPrincipalId::<T>::get();
  1946. // Update next principal id value
  1947. NextPrincipalId::<T>::mutate(|id| *id += PrincipalId::<T>::one());
  1948. // Store principal
  1949. PrincipalById::<T>::insert(principal_id, principal);
  1950. // Return id
  1951. principal_id
  1952. }
  1953. fn update_channel(
  1954. channel_id: &ChannelId<T>,
  1955. new_channel_name: &Option<Vec<u8>>,
  1956. new_verified: &Option<bool>,
  1957. new_descriptin: &Option<Vec<u8>>,
  1958. new_publishing_status: &Option<ChannelPublishingStatus>,
  1959. new_curation_status: &Option<ChannelCurationStatus>,
  1960. ) {
  1961. // Update name to channel mapping if there is a new name mapping
  1962. if let Some(ref channel_name) = new_channel_name {
  1963. // Remove mapping under old name
  1964. let current_channel_name = ChannelById::<T>::get(channel_id).channel_name;
  1965. ChannelIdByName::<T>::remove(current_channel_name);
  1966. // Establish mapping under new name
  1967. ChannelIdByName::<T>::insert(channel_name.clone(), channel_id);
  1968. }
  1969. // Update channel
  1970. ChannelById::<T>::mutate(channel_id, |channel| {
  1971. if let Some(ref channel_name) = new_channel_name {
  1972. channel.channel_name = channel_name.clone();
  1973. }
  1974. if let Some(ref verified) = new_verified {
  1975. channel.verified = *verified;
  1976. }
  1977. if let Some(ref description) = new_descriptin {
  1978. channel.description = description.clone();
  1979. }
  1980. if let Some(ref publishing_status) = new_publishing_status {
  1981. channel.publishing_status = publishing_status.clone();
  1982. }
  1983. if let Some(ref curation_status) = new_curation_status {
  1984. channel.curation_status = *curation_status;
  1985. }
  1986. });
  1987. // Trigger event
  1988. Self::deposit_event(RawEvent::ChannelUpdatedByCurationActor(*channel_id));
  1989. }
  1990. }