From e5ea62d636dae6f43e2994d30ccca225d94f1749 Mon Sep 17 00:00:00 2001 From: Atatakai Date: Mon, 30 Sep 2024 12:22:50 +0400 Subject: [PATCH] (launch) fix: replace hardcode with form value --- .../MyStakingContracts/Create/index.spec.tsx | 6 + .../MyStakingContracts/Create/index.tsx | 6 +- .../Create/useFieldRules.tsx | 170 +++++++++--------- 3 files changed, 99 insertions(+), 83 deletions(-) diff --git a/apps/launch/components/MyStakingContracts/Create/index.spec.tsx b/apps/launch/components/MyStakingContracts/Create/index.spec.tsx index 020257bb..dceb794c 100644 --- a/apps/launch/components/MyStakingContracts/Create/index.spec.tsx +++ b/apps/launch/components/MyStakingContracts/Create/index.spec.tsx @@ -120,6 +120,12 @@ describe('', () => { await userEvent.type(rewardsPerSecondInput, '100'); expect(rewardsPerSecondInput).toHaveValue('100'); + const minStakingDepositInput = screen.getByLabelText('Minimum service staking deposit, OLAS'); + // clear first, because it has default value + await userEvent.clear(minStakingDepositInput); + await userEvent.type(minStakingDepositInput, '1000'); + expect(minStakingDepositInput).toHaveValue('1000'); + await clickCreateContractButton(); expect( screen.getByText('The rewards per second must be below the allowed limit'), diff --git a/apps/launch/components/MyStakingContracts/Create/index.tsx b/apps/launch/components/MyStakingContracts/Create/index.tsx index fbdb1632..be89c244 100644 --- a/apps/launch/components/MyStakingContracts/Create/index.tsx +++ b/apps/launch/components/MyStakingContracts/Create/index.tsx @@ -91,9 +91,11 @@ const TemplateInfoContent = ({ id }: { id: number }) => { * Create staking contract */ export const CreateStakingContract = () => { + const [form] = Form.useForm(); + const router = useRouter(); const dispatch = useAppDispatch(); - const rulesConfig = useFieldRules(); + const { rulesConfig, onValuesChange } = useFieldRules(form); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); @@ -210,6 +212,8 @@ export const CreateStakingContract = () => { {alertMessage} + form={form} + onValuesChange={onValuesChange} layout="vertical" onFinish={handleCreate} requiredMark={false} diff --git a/apps/launch/components/MyStakingContracts/Create/useFieldRules.tsx b/apps/launch/components/MyStakingContracts/Create/useFieldRules.tsx index fea8bfb0..62b11428 100644 --- a/apps/launch/components/MyStakingContracts/Create/useFieldRules.tsx +++ b/apps/launch/components/MyStakingContracts/Create/useFieldRules.tsx @@ -1,4 +1,4 @@ -import { Rule } from 'antd/es/form'; +import { FormInstance, Rule } from 'antd/es/form'; import { FORM_VALIDATION } from 'libs/util-functions/src'; @@ -21,96 +21,102 @@ const getGenericFieldRules = (label: string) => [ ]; type StakingDepositRules = { [K in keyof FormValues]: { rules: Rule[] | undefined } }; -export const useFieldRules = (): StakingDepositRules => { +export const useFieldRules = ( + form: FormInstance, +): { + onValuesChange: (changedValues: Record) => void; + rulesConfig: StakingDepositRules; +} => { const { data: numServicesLimit } = useNumServicesLimit(); const { data: minStakingDepositLimit } = useMinStakingDepositLimit(); const { data: timeForEmissionsLimit } = useTimeForEmissionsLimit(); const { data: apyLimit } = useApyLimit(); + const onValuesChange = (changedValues: Record) => { + // The rewardsPerSecond validation depends on minStakingDeposit value + // Manually trigger it's validation when minStakingDeposit changes + if ('minStakingDeposit' in changedValues) { + form.validateFields(['rewardsPerSecond']); + } + }; + return { - contractName: { rules: getGenericFieldRules(FieldConfig.contractName.name) }, - description: { rules: getGenericFieldRules(FieldConfig.description.name) }, - maxNumServices: { - rules: [ - ...getGenericFieldRules(FieldConfig.maxNumServices.name), - { - type: 'number', - min: 1, - max: numServicesLimit, - message: `Maximum number of staked agents must be at least 1 and at most ${numServicesLimit}`, - }, - ], - }, - rewardsPerSecond: { - rules: [ - ...getGenericFieldRules(FieldConfig.rewardsPerSecond.name), - { - // BE validation from https://github.com/valory-xyz/autonolas-registries/blob/main/contracts/staking/StakingVerifier - validator: async (_, value) => { - if (!minStakingDepositLimit) return Promise.resolve(); - if (!apyLimit) return Promise.resolve(); + onValuesChange, + rulesConfig: { + contractName: { rules: getGenericFieldRules(FieldConfig.contractName.name) }, + description: { rules: getGenericFieldRules(FieldConfig.description.name) }, + maxNumServices: { + rules: [ + ...getGenericFieldRules(FieldConfig.maxNumServices.name), + { + type: 'number', + min: 1, + max: numServicesLimit, + message: `Maximum number of staked agents must be at least 1 and at most ${numServicesLimit}`, + }, + ], + }, + rewardsPerSecond: { + rules: [ + ...getGenericFieldRules(FieldConfig.rewardsPerSecond.name), + { + // BE validation from https://github.com/valory-xyz/autonolas-registries/blob/main/contracts/staking/StakingVerifier + validator: async (_, value) => { + if (!minStakingDepositLimit) return Promise.resolve(); + if (!apyLimit) return Promise.resolve(); - const rewardsPerYear = value * ONE_YEAR; - const apy = (rewardsPerYear * 1e18) / 1000; + const minStakingDeposit = form.getFieldValue('minStakingDeposit'); + const rewardsPerYear = value * ONE_YEAR; + const apy = (rewardsPerYear * 1e18) / minStakingDeposit; - if (apy > apyLimit) { - return Promise.reject('The rewards per second must be below the allowed limit'); - } + if (apy > apyLimit) { + return Promise.reject('The rewards per second must be below the allowed limit'); + } + }, }, - }, - ], - }, - minStakingDeposit: { - rules: [ - ...getGenericFieldRules(FieldConfig.minStakingDeposit.name), - { - type: 'number', - min: 1, - max: minStakingDepositLimit, - message: `Minimum service staking deposit, OLAS must be at least 1 and at most ${minStakingDepositLimit}`, - }, - ], - }, - minNumStakingPeriods: { rules: getGenericFieldRules(FieldConfig.minNumStakingPeriods.name) }, - maxNumInactivityPeriods: { - rules: getGenericFieldRules(FieldConfig.maxNumInactivityPeriods.name), - }, - livenessPeriod: { - rules: [ - ...getGenericFieldRules(FieldConfig.livenessPeriod.name), - // TODO: any comments on this validation? - // { - // type: 'number', - // min: 86400, - // max: 86400 * 30, - // message: `Liveness period must be between 24 hours and 30 days`, - // }, - ], - }, - timeForEmissions: { - rules: [ - ...getGenericFieldRules(FieldConfig.timeForEmissions.name), - { - type: 'number', - min: 1, - max: timeForEmissionsLimit, - message: `Time for emissions must be between 1 and ${timeForEmissionsLimit} seconds`, - }, - ], - }, - numAgentInstances: { rules: getGenericFieldRules(FieldConfig.numAgentInstances.name) }, - agentIds: { - rules: [ - { ...FORM_VALIDATION.validateCommaSeparatedList }, - ], - }, - threshold: { rules: undefined }, - configHash: { rules: undefined }, - activityChecker: { - rules: [ - ...getGenericFieldRules(FieldConfig.activityChecker.name), - { ...FORM_VALIDATION.validateAddress }, - ], + ], + }, + minStakingDeposit: { + rules: [ + ...getGenericFieldRules(FieldConfig.minStakingDeposit.name), + { + type: 'number', + min: 1, + max: minStakingDepositLimit, + message: `Minimum service staking deposit, OLAS must be at least 1 and at most ${minStakingDepositLimit}`, + }, + ], + }, + minNumStakingPeriods: { rules: getGenericFieldRules(FieldConfig.minNumStakingPeriods.name) }, + maxNumInactivityPeriods: { + rules: getGenericFieldRules(FieldConfig.maxNumInactivityPeriods.name), + }, + livenessPeriod: { + rules: [...getGenericFieldRules(FieldConfig.livenessPeriod.name)], + }, + timeForEmissions: { + rules: [ + ...getGenericFieldRules(FieldConfig.timeForEmissions.name), + { + type: 'number', + min: 1, + max: timeForEmissionsLimit, + message: `Time for emissions must be between 1 and ${timeForEmissionsLimit} seconds`, + }, + ], + }, + numAgentInstances: { rules: getGenericFieldRules(FieldConfig.numAgentInstances.name) }, + agentIds: { + rules: [{ ...FORM_VALIDATION.validateCommaSeparatedList }], + }, + threshold: { rules: undefined }, + configHash: { rules: undefined }, + activityChecker: { + rules: [ + ...getGenericFieldRules(FieldConfig.activityChecker.name), + { ...FORM_VALIDATION.validateAddress }, + ], + }, }, }; };