validationSchema.ts 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. import * as Yup from 'yup';
  2. import { schemaValidator, ActivateOpeningAtKeys } from '@joystream/types/hiring';
  3. import { ProposalTypes } from '@polkadot/joy-utils/types/proposals';
  4. import { GenericFormValues } from './forms/GenericProposalForm';
  5. import { InputValidationLengthConstraint } from '@joystream/types/common';
  6. import { FormValues as SignalFormValues } from './forms/SignalForm';
  7. import { FormValues as RuntimeUpgradeFormValues } from './forms/RuntimeUpgradeForm';
  8. import { FormValues as SetCouncilParamsFormValues } from './forms/SetCouncilParamsForm';
  9. import { FormValues as SpendingProposalFormValues } from './forms/SpendingProposalForm';
  10. import { FormValues as SetMaxValidatorCountFormValues } from './forms/SetMaxValidatorCountForm';
  11. import { FormValues as AddWorkingGroupLeaderOpeningFormValues } from './forms/AddWorkingGroupOpeningForm';
  12. import { FormValues as SetWorkingGroupMintCapacityFormValues } from './forms/SetWorkingGroupMintCapacityForm';
  13. import { FormValues as BeginReviewLeaderApplicationsFormValues } from './forms/BeginReviewLeaderApplicationsForm';
  14. import { FormValues as FillWorkingGroupLeaderOpeningFormValues } from './forms/FillWorkingGroupLeaderOpeningForm';
  15. import { FormValues as DecreaseWorkingGroupLeadStakeFormValues } from './forms/DecreaseWorkingGroupLeadStakeForm';
  16. import { FormValues as SlashWorkingGroupLeadStakeFormValues } from './forms/SlashWorkingGroupLeadStakeForm';
  17. import { FormValues as SetWorkingGroupLeadRewardFormValues } from './forms/SetWorkingGroupLeadRewardForm';
  18. import { FormValues as TerminateWorkingGroupLeaderFormValues } from './forms/TerminateWorkingGroupLeaderForm';
  19. // TODO: If we really need this (currency unit) we can we make "Validation" a functiction that returns an object.
  20. // We could then "instantialize" it in "withFormContainer" where instead of passing
  21. // "validationSchema" (in each form component file) we would just pass "validationSchemaKey" or just "proposalType" (ie. SetLead).
  22. // Then we could let the "withFormContainer" handle the actual "validationSchema" for "withFormik". In that case it could easily
  23. // pass stuff like totalIssuance or currencyUnit here (ie.: const validationSchema = Validation(currencyUnit, totalIssuance)[proposalType];)
  24. const CURRENCY_UNIT = undefined;
  25. // All
  26. const TITLE_MAX_LENGTH = 40;
  27. const RATIONALE_MAX_LENGTH = 3000;
  28. // Runtime Upgrade
  29. const FILE_SIZE_BYTES_MIN = 1;
  30. // Set Election Parameters
  31. const ANNOUNCING_PERIOD_MIN = 14400;
  32. const ANNOUNCING_PERIOD_MAX = 43200;
  33. const VOTING_PERIOD_MIN = 14400;
  34. const VOTING_PERIOD_MAX = 28800;
  35. const REVEALING_PERIOD_MIN = 14400;
  36. const REVEALING_PERIOD_MAX = 28800;
  37. const MIN_COUNCIL_STAKE_MIN = 1;
  38. const MIN_COUNCIL_STAKE_MAX = 100000;
  39. const NEW_TERM_DURATION_MIN = 14400;
  40. const NEW_TERM_DURATION_MAX = 432000;
  41. const CANDIDACY_LIMIT_MIN = 50;
  42. const CANDIDACY_LIMIT_MAX = 100;
  43. const COUNCIL_SIZE_MIN = 4;
  44. const COUNCIL_SIZE_MAX = 20;
  45. const MIN_VOTING_STAKE_MIN = 1;
  46. const MIN_VOTING_STAKE_MAX = 100000;
  47. // Spending
  48. const TOKENS_MIN = 0;
  49. const TOKENS_MAX = 5000000;
  50. // Set Validator Count
  51. const MAX_VALIDATOR_COUNT_MIN = 4;
  52. const MAX_VALIDATOR_COUNT_MAX = 300;
  53. // Add Working Group Leader Opening Parameters
  54. // TODO: Discuss the actual values
  55. const MIN_EXACT_BLOCK_MINUS_CURRENT = 14400 * 5; // ~5 days
  56. const MAX_EXACT_BLOCK_MINUS_CURRENT = 14400 * 60; // 2 months
  57. const MAX_REVIEW_PERIOD_LENGTH_MIN = 14400 * 5; // ~5 days
  58. const MAX_REVIEW_PERIOD_LENGTH_MAX = 14400 * 60; // 2 months
  59. const MAX_APPLICATIONS_MIN = 1;
  60. const MAX_APPLICATIONS_MAX = 1000;
  61. const APPLICATION_STAKE_VALUE_MIN = 1;
  62. const APPLICATION_STAKE_VALUE_MAX = 1000000;
  63. const ROLE_STAKE_VALUE_MIN = 1;
  64. const ROLE_STAKE_VALUE_MAX = 1000000;
  65. const TERMINATE_ROLE_UNSTAKING_MIN = 0;
  66. const TERMINATE_ROLE_UNSTAKING_MAX = 14 * 14400; // 14 days
  67. const LEAVE_ROLE_UNSTAKING_MIN = 0;
  68. const LEAVE_ROLE_UNSTAKING_MAX = 14 * 14400; // 14 days
  69. // Set Working Group Mint Capacity
  70. // TODO: Discuss the actual values
  71. const WG_MINT_CAP_MIN = 0;
  72. const WG_MINT_CAP_MAX = 5000000;
  73. // Fill Working Group Leader Opening / Set Working Group Lead Reward
  74. // TODO: Discuss the actual values
  75. const MIN_REWARD_AMOUNT = 1;
  76. const MAX_REWARD_AMOUNT = 100000;
  77. const MIN_REWARD_INTERVAL = 1;
  78. const MAX_REWARD_INTERVAL = 30 * 14400; // 30 days
  79. // 3 days margin (voting_period) to prevent FillOpeningInvalidNextPaymentBlock
  80. // Should we worry that much about it though?
  81. const MIN_NEXT_PAYMENT_BLOCK_MINUS_CURRENT = 3 * 14400;
  82. const MAX_NEXT_PAYMENT_BLOCK_MINUS_CURRENT = 30 * 14400; // 30 days
  83. // Decrease/Slash Working Group Leader Stake
  84. const DECREASE_LEAD_STAKE_MIN = 1;
  85. const SLASH_LEAD_STAKE_MIN = 1;
  86. // Max is validated in form component, because it depends on selected working group's leader stake
  87. function errorMessage (name: string, min: number | string, max: number | string, unit?: string): string {
  88. return `${name} should be at least ${min} and no more than ${max}${unit ? ` ${unit}.` : '.'}`;
  89. }
  90. /*
  91. Validation is used to validate a proposal form.
  92. Each proposal type should validate the fields of his form, anything is valid as long as it fits in a Yup Schema.
  93. In a form, validation should be injected in the Yup Schema just by accessing it in this object.
  94. Ex:
  95. // Text Form
  96. import Validation from 'path/to/validationSchema'
  97. ...
  98. validationSchema: Yup.object().shape({
  99. ...Validation.All()
  100. ...Validation.Text()
  101. }),
  102. */
  103. type ProposalTypeKeys = typeof ProposalTypes[number];
  104. type OutdatedProposals = 'EvictStorageProvider' | 'SetStorageRoleParameters' | 'SetLead' | 'SetContentWorkingGroupMintCapacity';
  105. type ValidationTypeKeys = Exclude<ProposalTypeKeys, OutdatedProposals> | 'All';
  106. /* eslint-disable @typescript-eslint/indent */
  107. // /\ This prevents eslint from trying to make "stairs" out of those multiple conditions.
  108. // They are more readable when one is directly under the other (switch-case style)
  109. type FormValuesByType<T extends ValidationTypeKeys> =
  110. T extends 'All' ? GenericFormValues :
  111. T extends 'Text' ? Omit<SignalFormValues, keyof GenericFormValues> :
  112. T extends 'RuntimeUpgrade' ? Omit<RuntimeUpgradeFormValues, keyof GenericFormValues> :
  113. T extends 'SetElectionParameters' ? Omit<SetCouncilParamsFormValues, keyof GenericFormValues> :
  114. T extends 'Spending' ? Omit<SpendingProposalFormValues, keyof GenericFormValues> :
  115. T extends 'SetValidatorCount' ? Omit<SetMaxValidatorCountFormValues, keyof GenericFormValues> :
  116. T extends 'AddWorkingGroupLeaderOpening' ? Omit<AddWorkingGroupLeaderOpeningFormValues, keyof GenericFormValues> :
  117. T extends 'SetWorkingGroupMintCapacity' ? Omit<SetWorkingGroupMintCapacityFormValues, keyof GenericFormValues> :
  118. T extends 'BeginReviewWorkingGroupLeaderApplication' ? Omit<BeginReviewLeaderApplicationsFormValues, keyof GenericFormValues> :
  119. T extends 'FillWorkingGroupLeaderOpening' ? Omit<FillWorkingGroupLeaderOpeningFormValues, keyof GenericFormValues> :
  120. T extends 'DecreaseWorkingGroupLeaderStake' ? Omit<DecreaseWorkingGroupLeadStakeFormValues, keyof GenericFormValues> :
  121. T extends 'SlashWorkingGroupLeaderStake' ? Omit<SlashWorkingGroupLeadStakeFormValues, keyof GenericFormValues> :
  122. T extends 'SetWorkingGroupLeaderReward' ? Omit<SetWorkingGroupLeadRewardFormValues, keyof GenericFormValues> :
  123. T extends 'TerminateWorkingGroupLeaderRole' ? Omit<TerminateWorkingGroupLeaderFormValues, keyof GenericFormValues> :
  124. never;
  125. type ValidationSchemaFuncParamsByType<T extends ValidationTypeKeys> =
  126. T extends 'Text' ? [number] :
  127. T extends 'RuntimeUpgrade' ? [number] :
  128. T extends 'AddWorkingGroupLeaderOpening' ? [number, InputValidationLengthConstraint | undefined] :
  129. T extends 'FillWorkingGroupLeaderOpening' ? [number] :
  130. T extends 'TerminateWorkingGroupLeaderRole' ? [InputValidationLengthConstraint | undefined] :
  131. [];
  132. /* eslint-enable @typescript-eslint/indent */
  133. type ValidationSchemaFunc<FieldValuesT extends Record<string, any>, ParamsT extends any[] = []> = (...params: ParamsT) =>
  134. ({ [fieldK in keyof FieldValuesT]: Yup.Schema<any> });
  135. type ValidationType = {
  136. [validationTypeK in ValidationTypeKeys]: ValidationSchemaFunc<
  137. FormValuesByType<validationTypeK>,
  138. ValidationSchemaFuncParamsByType<validationTypeK>
  139. >
  140. };
  141. // Helpers for common validation
  142. function minMaxInt (min: number, max: number, fieldName: string) {
  143. return Yup.number()
  144. .required(`${fieldName} is required!`)
  145. .integer(`${fieldName} must be an integer!`)
  146. .min(min, errorMessage(fieldName, min, max))
  147. .max(max, errorMessage(fieldName, min, max));
  148. }
  149. function minMaxStrFromConstraint (constraint: InputValidationLengthConstraint | undefined, fieldName: string) {
  150. const schema = Yup.string().required(`${fieldName} is required!`);
  151. return constraint
  152. ? (
  153. schema
  154. .min(
  155. constraint.min.toNumber(),
  156. `${fieldName} must be at least ${constraint.min.toNumber()} character(s) long`
  157. )
  158. .max(
  159. constraint.max.toNumber(),
  160. `${fieldName} cannot be more than ${constraint.max.toNumber()} character(s) long`
  161. )
  162. )
  163. : schema;
  164. }
  165. const Validation: ValidationType = {
  166. All: () => ({
  167. title: Yup.string()
  168. .required('Title is required!')
  169. .max(TITLE_MAX_LENGTH, `Title should be under ${TITLE_MAX_LENGTH} characters.`),
  170. rationale: Yup.string()
  171. .required('Rationale is required!')
  172. .max(RATIONALE_MAX_LENGTH, `Rationale should be under ${RATIONALE_MAX_LENGTH} characters.`)
  173. }),
  174. Text: (maxLength: number) => ({
  175. description: Yup.string()
  176. .required('Description is required!')
  177. .max(maxLength, `Description should be under ${maxLength}`)
  178. }),
  179. RuntimeUpgrade: (maxFileSize: number) => ({
  180. WASM: Yup.mixed()
  181. .test('fileArrayBuffer', 'Unexpected data format, file cannot be processed.', (value) => value instanceof ArrayBuffer)
  182. .test('fileSizeMin', `Minimum file size is ${FILE_SIZE_BYTES_MIN} bytes.`, (value: ArrayBuffer) => value.byteLength >= FILE_SIZE_BYTES_MIN)
  183. .test('fileSizeMax', `Maximum file size is ${maxFileSize} bytes.`, (value: ArrayBuffer) => value.byteLength <= maxFileSize)
  184. }),
  185. SetElectionParameters: () => ({
  186. announcingPeriod: Yup.number()
  187. .required('All fields must be filled!')
  188. .integer('This field must be an integer.')
  189. .min(
  190. ANNOUNCING_PERIOD_MIN,
  191. errorMessage('The announcing period', ANNOUNCING_PERIOD_MIN, ANNOUNCING_PERIOD_MAX, 'blocks')
  192. )
  193. .max(
  194. ANNOUNCING_PERIOD_MAX,
  195. errorMessage('The announcing period', ANNOUNCING_PERIOD_MIN, ANNOUNCING_PERIOD_MAX, 'blocks')
  196. ),
  197. votingPeriod: Yup.number()
  198. .required('All fields must be filled!')
  199. .integer('This field must be an integer.')
  200. .min(VOTING_PERIOD_MIN, errorMessage('The voting period', VOTING_PERIOD_MIN, VOTING_PERIOD_MAX, 'blocks'))
  201. .max(VOTING_PERIOD_MAX, errorMessage('The voting period', VOTING_PERIOD_MIN, VOTING_PERIOD_MAX, 'blocks')),
  202. minVotingStake: Yup.number()
  203. .required('All fields must be filled!')
  204. .integer('This field must be an integer.')
  205. .min(
  206. MIN_VOTING_STAKE_MIN,
  207. errorMessage('The minimum voting stake', MIN_VOTING_STAKE_MIN, MIN_VOTING_STAKE_MAX, CURRENCY_UNIT)
  208. )
  209. .max(
  210. MIN_VOTING_STAKE_MAX,
  211. errorMessage('The minimum voting stake', MIN_VOTING_STAKE_MIN, MIN_VOTING_STAKE_MAX, CURRENCY_UNIT)
  212. ),
  213. revealingPeriod: Yup.number()
  214. .required('All fields must be filled!')
  215. .integer('This field must be an integer.')
  216. .min(
  217. REVEALING_PERIOD_MIN,
  218. errorMessage('The revealing period', REVEALING_PERIOD_MIN, REVEALING_PERIOD_MAX, 'blocks')
  219. )
  220. .max(
  221. REVEALING_PERIOD_MAX,
  222. errorMessage('The revealing period', REVEALING_PERIOD_MIN, REVEALING_PERIOD_MAX, 'blocks')
  223. ),
  224. minCouncilStake: Yup.number()
  225. .required('All fields must be filled!')
  226. .integer('This field must be an integer.')
  227. .min(
  228. MIN_COUNCIL_STAKE_MIN,
  229. errorMessage('The minimum council stake', MIN_COUNCIL_STAKE_MIN, MIN_COUNCIL_STAKE_MAX, CURRENCY_UNIT)
  230. )
  231. .max(
  232. MIN_COUNCIL_STAKE_MAX,
  233. errorMessage('The minimum council stake', MIN_COUNCIL_STAKE_MIN, MIN_COUNCIL_STAKE_MAX, CURRENCY_UNIT)
  234. ),
  235. newTermDuration: Yup.number()
  236. .required('All fields must be filled!')
  237. .integer('This field must be an integer.')
  238. .min(
  239. NEW_TERM_DURATION_MIN,
  240. errorMessage('The new term duration', NEW_TERM_DURATION_MIN, NEW_TERM_DURATION_MAX, 'blocks')
  241. )
  242. .max(
  243. NEW_TERM_DURATION_MAX,
  244. errorMessage('The new term duration', NEW_TERM_DURATION_MIN, NEW_TERM_DURATION_MAX, 'blocks')
  245. ),
  246. candidacyLimit: Yup.number()
  247. .required('All fields must be filled!')
  248. .integer('This field must be an integer.')
  249. .min(CANDIDACY_LIMIT_MIN, errorMessage('The candidacy limit', CANDIDACY_LIMIT_MIN, CANDIDACY_LIMIT_MAX))
  250. .max(CANDIDACY_LIMIT_MAX, errorMessage('The candidacy limit', CANDIDACY_LIMIT_MIN, CANDIDACY_LIMIT_MAX)),
  251. councilSize: Yup.number()
  252. .required('All fields must be filled!')
  253. .integer('This field must be an integer.')
  254. .min(COUNCIL_SIZE_MIN, errorMessage('The council size', COUNCIL_SIZE_MIN, COUNCIL_SIZE_MAX))
  255. .max(COUNCIL_SIZE_MAX, errorMessage('The council size', COUNCIL_SIZE_MIN, COUNCIL_SIZE_MAX))
  256. }),
  257. Spending: () => ({
  258. tokens: Yup.number()
  259. .positive('The token amount should be positive.')
  260. .integer('This field must be an integer.')
  261. .max(TOKENS_MAX, errorMessage('The amount of tokens', TOKENS_MIN, TOKENS_MAX))
  262. .required('You need to specify an amount of tokens.'),
  263. destinationAccount: Yup.string()
  264. .required('Select a destination account!')
  265. }),
  266. SetValidatorCount: () => ({
  267. maxValidatorCount: Yup.number()
  268. .required('Enter the max validator count')
  269. .integer('This field must be an integer.')
  270. .min(
  271. MAX_VALIDATOR_COUNT_MIN,
  272. errorMessage('The max validator count', MAX_VALIDATOR_COUNT_MIN, MAX_VALIDATOR_COUNT_MAX)
  273. )
  274. .max(
  275. MAX_VALIDATOR_COUNT_MAX,
  276. errorMessage('The max validator count', MAX_VALIDATOR_COUNT_MIN, MAX_VALIDATOR_COUNT_MAX)
  277. )
  278. }),
  279. AddWorkingGroupLeaderOpening: (currentBlock: number, HRTConstraint?: InputValidationLengthConstraint) => ({
  280. workingGroup: Yup.string(),
  281. activateAt: Yup.string().required(),
  282. activateAtBlock: Yup.number()
  283. .when('activateAt', {
  284. is: ActivateOpeningAtKeys.ExactBlock,
  285. then: minMaxInt(
  286. MIN_EXACT_BLOCK_MINUS_CURRENT + currentBlock,
  287. MAX_EXACT_BLOCK_MINUS_CURRENT + currentBlock,
  288. 'Exact block'
  289. )
  290. }),
  291. maxReviewPeriodLength: minMaxInt(MAX_REVIEW_PERIOD_LENGTH_MIN, MAX_REVIEW_PERIOD_LENGTH_MAX, 'Max. review period length'),
  292. applicationsLimited: Yup.boolean(),
  293. maxApplications: Yup.number()
  294. .when('applicationsLimited', {
  295. is: true,
  296. then: minMaxInt(MAX_APPLICATIONS_MIN, MAX_APPLICATIONS_MAX, 'Max. number of applications')
  297. }),
  298. applicationStakeRequired: Yup.boolean(),
  299. applicationStakeMode: Yup.string(),
  300. applicationStakeValue: Yup.number()
  301. .when('applicationStakeRequired', {
  302. is: true,
  303. then: minMaxInt(APPLICATION_STAKE_VALUE_MIN, APPLICATION_STAKE_VALUE_MAX, 'Application stake value')
  304. }),
  305. roleStakeRequired: Yup.boolean(),
  306. roleStakeMode: Yup.string(),
  307. roleStakeValue: Yup.number()
  308. .when('roleStakeRequired', {
  309. is: true,
  310. then: minMaxInt(ROLE_STAKE_VALUE_MIN, ROLE_STAKE_VALUE_MAX, 'Role stake value')
  311. }),
  312. terminateRoleUnstakingPeriod: minMaxInt(
  313. TERMINATE_ROLE_UNSTAKING_MIN,
  314. TERMINATE_ROLE_UNSTAKING_MAX,
  315. 'Terminate role unstaking period'
  316. ),
  317. leaveRoleUnstakingPeriod: minMaxInt(
  318. LEAVE_ROLE_UNSTAKING_MIN,
  319. LEAVE_ROLE_UNSTAKING_MAX,
  320. 'Leave role unstaking period'
  321. ),
  322. humanReadableText: minMaxStrFromConstraint(HRTConstraint, 'human_readable_text')
  323. .test(
  324. 'schemaIsValid',
  325. 'Schema validation failed!',
  326. function (val: string) {
  327. let schemaObj: Record<string, unknown>;
  328. try {
  329. schemaObj = JSON.parse(val) as Record<string, unknown>;
  330. } catch (e) {
  331. return this.createError({ message: 'Schema validation failed: Invalid JSON' });
  332. }
  333. const isValid = schemaValidator(schemaObj);
  334. const errors = schemaValidator.errors || [];
  335. if (!isValid) {
  336. return this.createError({
  337. message: 'Schema validation failed: ' + errors.map((e) => `${e.message || ''}${e.dataPath && ` (${e.dataPath})`}`).join(', ')
  338. });
  339. }
  340. return true;
  341. }
  342. )
  343. }),
  344. SetWorkingGroupMintCapacity: () => ({
  345. workingGroup: Yup.string(),
  346. capacity: minMaxInt(WG_MINT_CAP_MIN, WG_MINT_CAP_MAX, 'Mint capacity')
  347. }),
  348. BeginReviewWorkingGroupLeaderApplication: () => ({
  349. workingGroup: Yup.string(),
  350. openingId: Yup.number().required('Select an opening!')
  351. }),
  352. FillWorkingGroupLeaderOpening: (currentBlock: number) => ({
  353. workingGroup: Yup.string(),
  354. openingId: Yup.number().required('Select an opening!'),
  355. successfulApplicant: Yup.number().required('Select a succesful applicant!'),
  356. includeReward: Yup.boolean(),
  357. rewardAmount: Yup.number()
  358. .when('includeReward', {
  359. is: true,
  360. then: minMaxInt(MIN_REWARD_AMOUNT, MAX_REWARD_AMOUNT, 'Reward amount')
  361. }),
  362. rewardNextBlock: Yup.number()
  363. .when('includeReward', {
  364. is: true,
  365. then: minMaxInt(
  366. MIN_NEXT_PAYMENT_BLOCK_MINUS_CURRENT + currentBlock,
  367. MAX_NEXT_PAYMENT_BLOCK_MINUS_CURRENT + currentBlock,
  368. 'Next payment block'
  369. )
  370. }),
  371. rewardRecurring: Yup.boolean(),
  372. rewardInterval: Yup.number()
  373. .when(['includeReward', 'rewardRecurring'], {
  374. is: true,
  375. then: minMaxInt(MIN_REWARD_INTERVAL, MAX_REWARD_INTERVAL, 'Reward interval')
  376. })
  377. }),
  378. DecreaseWorkingGroupLeaderStake: () => ({
  379. workingGroup: Yup.string(),
  380. amount: Yup.number()
  381. .required('Amount is required!')
  382. .min(DECREASE_LEAD_STAKE_MIN, `Amount must be greater than ${DECREASE_LEAD_STAKE_MIN}`)
  383. }),
  384. SlashWorkingGroupLeaderStake: () => ({
  385. workingGroup: Yup.string(),
  386. amount: Yup.number()
  387. .required('Amount is required!')
  388. .min(SLASH_LEAD_STAKE_MIN, `Amount must be greater than ${SLASH_LEAD_STAKE_MIN}`)
  389. }),
  390. SetWorkingGroupLeaderReward: () => ({
  391. workingGroup: Yup.string(),
  392. amount: minMaxInt(MIN_REWARD_AMOUNT, MAX_REWARD_AMOUNT, 'Reward amount')
  393. }),
  394. TerminateWorkingGroupLeaderRole: (rationaleConstraint?: InputValidationLengthConstraint) => ({
  395. workingGroup: Yup.string(),
  396. terminationRationale: minMaxStrFromConstraint(rationaleConstraint, 'Termination rationale'),
  397. slashStake: Yup.boolean()
  398. })
  399. };
  400. export default Validation;