fix(1837): account for proposal vote and enactment deadlines being uncoupled (#2005)
* Fix/1837: Remove 2 seconds from proposal vote deadline on submission to ensure the deadline is always slightly below the maximum the API accepts * fix(1837): Adjust for vote deadline and enactment deadline being decoupled in the API * fix(1837): Removed unnecessary dependencies * fix(1837): A couple of extra tests for get-enactment-timestamp * fix(1837): propose-update-asset.tsx tweaked to ensure max enactment button works properly
This commit is contained in:
parent
266f87be8f
commit
d3cb3896f4
@ -675,13 +675,14 @@
|
|||||||
"ProposalVoteTitle": "Vote deadline",
|
"ProposalVoteTitle": "Vote deadline",
|
||||||
"ProposalVoteAndEnactmentTitle": "Vote deadline and enactment",
|
"ProposalVoteAndEnactmentTitle": "Vote deadline and enactment",
|
||||||
"ProposalVoteDeadline": "Time till voting closes",
|
"ProposalVoteDeadline": "Time till voting closes",
|
||||||
"ProposalEnactmentDeadline": "Time till enactment (after vote close)",
|
"ProposalEnactmentDeadline": "Time till enactment (must be equal to or after vote close)",
|
||||||
"ProposalValidationDeadline": "Time till ERC-20 asset validation. Maximum value is affected by the vote deadline.",
|
"ProposalValidationDeadline": "Time till ERC-20 asset validation. Maximum value is affected by the vote deadline.",
|
||||||
"ThisWillSetVotingDeadlineTo": "This will set the voting deadline to",
|
"ThisWillSetVotingDeadlineTo": "This will set the voting deadline to",
|
||||||
"ThisWillSetEnactmentDeadlineTo": "This will set the enactment date to",
|
"ThisWillSetEnactmentDeadlineTo": "This will set the enactment date to",
|
||||||
"ThisWillSetValidationDeadlineTo": "This will set the validation deadline to",
|
"ThisWillSetValidationDeadlineTo": "This will set the validation deadline to",
|
||||||
"Hours": "hours",
|
"Hours": "hours",
|
||||||
"ThisWillAdd2MinutesToAllowTimeToConfirmInWallet": "Note: we add 2 minutes of extra time when you choose the minimum value. This gives you time to confirm the proposal in your wallet.",
|
"ThisWillAdd2MinutesToAllowTimeToConfirmInWallet": "Note: we add 2 minutes of extra time when you choose the minimum value. This gives you time to confirm the proposal in your wallet.",
|
||||||
|
"ProposalWillFailIfEnactmentIsEarlierThanVotingDeadline": "Proposal will fail if enactment is earlier than the voting deadline",
|
||||||
"SelectAMarketToChange": "Select a market to change",
|
"SelectAMarketToChange": "Select a market to change",
|
||||||
"MarketName": "Market name",
|
"MarketName": "Market name",
|
||||||
"MarketCode": "Market code",
|
"MarketCode": "Market code",
|
||||||
|
@ -20,7 +20,7 @@ afterEach(() => {
|
|||||||
const minVoteDeadline = '1h0m0s';
|
const minVoteDeadline = '1h0m0s';
|
||||||
const maxVoteDeadline = '5h0m0s';
|
const maxVoteDeadline = '5h0m0s';
|
||||||
const minEnactDeadline = '1h0m0s';
|
const minEnactDeadline = '1h0m0s';
|
||||||
const maxEnactDeadline = '4h0m0s';
|
const maxEnactDeadline = '5h0m0s';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Formats date according to locale.
|
* Formats date according to locale.
|
||||||
@ -118,7 +118,7 @@ describe('Proposal form vote, validation and enactment deadline', () => {
|
|||||||
const maxButton = screen.getByTestId('max-enactment');
|
const maxButton = screen.getByTestId('max-enactment');
|
||||||
const minButton = screen.getByTestId('min-enactment');
|
const minButton = screen.getByTestId('min-enactment');
|
||||||
fireEvent.click(maxButton);
|
fireEvent.click(maxButton);
|
||||||
expect(enactmentDeadlineInput).toHaveValue(4);
|
expect(enactmentDeadlineInput).toHaveValue(5);
|
||||||
fireEvent.click(minButton);
|
fireEvent.click(minButton);
|
||||||
expect(enactmentDeadlineInput).toHaveValue(1);
|
expect(enactmentDeadlineInput).toHaveValue(1);
|
||||||
});
|
});
|
||||||
@ -154,7 +154,24 @@ describe('Proposal form vote, validation and enactment deadline', () => {
|
|||||||
'2022-01-01T00:02:00.000Z'
|
'2022-01-01T00:02:00.000Z'
|
||||||
);
|
);
|
||||||
expect(screen.getByTestId('enactment-date')).toHaveTextContent(
|
expect(screen.getByTestId('enactment-date')).toHaveTextContent(
|
||||||
'2022-01-01T02:00:00.000Z'
|
'2022-01-01T01:02:00.000Z'
|
||||||
|
);
|
||||||
|
// When max values are used, the deadlines should have 2 seconds subtracted
|
||||||
|
// from them to account any delays
|
||||||
|
const voteDeadlineMaxButton = screen.getByTestId('max-vote');
|
||||||
|
const enactmentDeadlineMaxButton = screen.getByTestId('max-enactment');
|
||||||
|
const validationDeadlineMaxButton = screen.getByTestId('max-validation');
|
||||||
|
fireEvent.click(voteDeadlineMaxButton);
|
||||||
|
fireEvent.click(enactmentDeadlineMaxButton);
|
||||||
|
fireEvent.click(validationDeadlineMaxButton);
|
||||||
|
expect(screen.getByTestId('voting-date')).toHaveTextContent(
|
||||||
|
'2022-01-01T04:59:58.000Z'
|
||||||
|
);
|
||||||
|
expect(screen.getByTestId('validation-date')).toHaveTextContent(
|
||||||
|
'2022-01-01T04:59:58.000Z'
|
||||||
|
);
|
||||||
|
expect(screen.getByTestId('enactment-date')).toHaveTextContent(
|
||||||
|
'2022-01-01T04:59:58.000Z'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -171,19 +188,7 @@ describe('Proposal form vote, validation and enactment deadline', () => {
|
|||||||
'2022-01-01T00:02:30.000Z'
|
'2022-01-01T00:02:30.000Z'
|
||||||
);
|
);
|
||||||
expect(screen.getByTestId('enactment-date')).toHaveTextContent(
|
expect(screen.getByTestId('enactment-date')).toHaveTextContent(
|
||||||
'2022-01-01T02:00:30.000Z'
|
'2022-01-01T01:02:30.000Z'
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('update the vote deadline date and the enactment deadline date when the vote deadline is changed', () => {
|
|
||||||
renderComponent();
|
|
||||||
const voteDeadlineInput = screen.getByTestId('proposal-vote-deadline');
|
|
||||||
fireEvent.change(voteDeadlineInput, { target: { value: 2 } });
|
|
||||||
expect(screen.getByTestId('voting-date')).toHaveTextContent(
|
|
||||||
'2022-01-01T02:00:00.000Z'
|
|
||||||
);
|
|
||||||
expect(screen.getByTestId('enactment-date')).toHaveTextContent(
|
|
||||||
'2022-01-01T03:00:00.000Z'
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -198,7 +203,7 @@ describe('Proposal form vote, validation and enactment deadline', () => {
|
|||||||
fireEvent.click(voteDeadlineMaxButton);
|
fireEvent.click(voteDeadlineMaxButton);
|
||||||
fireEvent.click(validationDeadlineMaxButton);
|
fireEvent.click(validationDeadlineMaxButton);
|
||||||
expect(screen.getByTestId('validation-date')).toHaveTextContent(
|
expect(screen.getByTestId('validation-date')).toHaveTextContent(
|
||||||
'2022-01-01T05:00:00.000Z'
|
'2022-01-01T04:59:58.000Z'
|
||||||
);
|
);
|
||||||
expect(validationDeadlineInput).toHaveValue(5);
|
expect(validationDeadlineInput).toHaveValue(5);
|
||||||
fireEvent.click(voteDeadlineMinButton);
|
fireEvent.click(voteDeadlineMinButton);
|
||||||
@ -207,4 +212,19 @@ describe('Proposal form vote, validation and enactment deadline', () => {
|
|||||||
);
|
);
|
||||||
expect(validationDeadlineInput).toHaveValue(1);
|
expect(validationDeadlineInput).toHaveValue(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('displays error text if the vote deadline is set later than the enactment deadline', () => {
|
||||||
|
renderComponent();
|
||||||
|
const voteDeadlineInput = screen.getByTestId('proposal-vote-deadline');
|
||||||
|
const enactmentDeadlineInput = screen.getByTestId(
|
||||||
|
'proposal-enactment-deadline'
|
||||||
|
);
|
||||||
|
fireEvent.change(voteDeadlineInput, { target: { value: 5 } });
|
||||||
|
fireEvent.change(enactmentDeadlineInput, { target: { value: 2 } });
|
||||||
|
expect(
|
||||||
|
screen.getByTestId('enactment-before-voting-deadline')
|
||||||
|
).toHaveTextContent(
|
||||||
|
'Proposal will fail if enactment is earlier than the voting deadline'
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -7,10 +7,12 @@ import {
|
|||||||
InputError,
|
InputError,
|
||||||
} from '@vegaprotocol/ui-toolkit';
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
import { getDateTimeFormat } from '@vegaprotocol/react-helpers';
|
import { getDateTimeFormat } from '@vegaprotocol/react-helpers';
|
||||||
import { addHours, addMinutes } from 'date-fns';
|
import { addHours } from 'date-fns';
|
||||||
import {
|
import {
|
||||||
|
addTwoMinutes,
|
||||||
deadlineToSeconds,
|
deadlineToSeconds,
|
||||||
secondsToRoundedHours,
|
secondsToRoundedHours,
|
||||||
|
subtractTwoSeconds,
|
||||||
} from '@vegaprotocol/governance';
|
} from '@vegaprotocol/governance';
|
||||||
import { ProposalFormSubheader } from './proposal-form-subheader';
|
import { ProposalFormSubheader } from './proposal-form-subheader';
|
||||||
import type { UseFormRegisterReturn } from 'react-hook-form';
|
import type { UseFormRegisterReturn } from 'react-hook-form';
|
||||||
@ -218,6 +220,22 @@ const EnactmentForm = ({
|
|||||||
<span data-testid="enactment-date" className="pl-2">
|
<span data-testid="enactment-date" className="pl-2">
|
||||||
{getDateTimeFormat().format(deadlineDates.enactment)}
|
{getDateTimeFormat().format(deadlineDates.enactment)}
|
||||||
</span>
|
</span>
|
||||||
|
{deadlines.enactment === minEnactmentHours && (
|
||||||
|
<span
|
||||||
|
data-testid="enactment-2-mins-extra"
|
||||||
|
className="block mt-4 font-light"
|
||||||
|
>
|
||||||
|
{t('ThisWillAdd2MinutesToAllowTimeToConfirmInWallet')}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{deadlines.enactment && deadlines.enactment < deadlines.vote && (
|
||||||
|
<span
|
||||||
|
data-testid="enactment-before-voting-deadline"
|
||||||
|
className="block mt-4 text-vega-red-dark"
|
||||||
|
>
|
||||||
|
{t('ProposalWillFailIfEnactmentIsEarlierThanVotingDeadline')}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
@ -302,16 +320,13 @@ export function ProposalFormVoteAndEnactmentDeadline({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const [deadlineDates, setDeadlineDates] = useState<DeadlineDatesProps>({
|
const [deadlineDates, setDeadlineDates] = useState<DeadlineDatesProps>({
|
||||||
vote:
|
vote: addHours(addTwoMinutes(), deadlines.vote),
|
||||||
deadlines.vote === minVoteHours
|
|
||||||
? addHours(addMinutes(new Date(), 2), deadlines.vote)
|
|
||||||
: addHours(new Date(), deadlines.vote),
|
|
||||||
enactment: deadlines.enactment
|
enactment: deadlines.enactment
|
||||||
? addHours(new Date(), deadlines.vote + deadlines.enactment)
|
? addHours(addTwoMinutes(), deadlines.enactment)
|
||||||
: undefined,
|
: undefined,
|
||||||
validation:
|
validation:
|
||||||
deadlines.validation === 0
|
deadlines.validation === 0
|
||||||
? addHours(addMinutes(new Date(), 2), deadlines.validation)
|
? addHours(addTwoMinutes(), deadlines.validation)
|
||||||
: addHours(new Date(), deadlines.validation),
|
: addHours(new Date(), deadlines.validation),
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -319,21 +334,40 @@ export function ProposalFormVoteAndEnactmentDeadline({
|
|||||||
const interval = setInterval(() => {
|
const interval = setInterval(() => {
|
||||||
setDeadlineDates((prev) => ({
|
setDeadlineDates((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
vote:
|
vote: addHours(
|
||||||
deadlines.vote === minVoteHours
|
(deadlines.vote === minVoteHours && addTwoMinutes()) ||
|
||||||
? addHours(addMinutes(new Date(), 2), deadlines.vote)
|
(deadlines.vote === maxVoteHours && subtractTwoSeconds()) ||
|
||||||
: addHours(new Date(), deadlines.vote),
|
new Date(),
|
||||||
|
deadlines.vote
|
||||||
|
),
|
||||||
enactment: deadlines.enactment
|
enactment: deadlines.enactment
|
||||||
? addHours(new Date(), deadlines.vote + deadlines.enactment)
|
? addHours(
|
||||||
|
(deadlines.enactment === minEnactmentHours && addTwoMinutes()) ||
|
||||||
|
(deadlines.enactment === maxEnactmentHours &&
|
||||||
|
subtractTwoSeconds()) ||
|
||||||
|
new Date(),
|
||||||
|
deadlines.enactment
|
||||||
|
)
|
||||||
: undefined,
|
: undefined,
|
||||||
validation:
|
validation:
|
||||||
deadlines.validation === 0
|
deadlines.validation === 0
|
||||||
? addHours(addMinutes(new Date(), 2), deadlines.validation)
|
? addHours(addTwoMinutes(), deadlines.validation)
|
||||||
: addHours(new Date(), deadlines.validation),
|
: addHours(
|
||||||
|
(deadlines.validation === maxVoteHours &&
|
||||||
|
subtractTwoSeconds()) ||
|
||||||
|
new Date(),
|
||||||
|
deadlines.validation
|
||||||
|
),
|
||||||
}));
|
}));
|
||||||
}, 1000);
|
}, 1000);
|
||||||
return () => clearInterval(interval);
|
return () => clearInterval(interval);
|
||||||
}, [deadlines, minVoteHours]);
|
}, [
|
||||||
|
deadlines,
|
||||||
|
maxEnactmentHours,
|
||||||
|
maxVoteHours,
|
||||||
|
minEnactmentHours,
|
||||||
|
minVoteHours,
|
||||||
|
]);
|
||||||
|
|
||||||
const updateVoteDeadlineAndDate = (hours: number) => {
|
const updateVoteDeadlineAndDate = (hours: number) => {
|
||||||
// Validation, when needed, can only happen within the voting period. Therefore, if the
|
// Validation, when needed, can only happen within the voting period. Therefore, if the
|
||||||
@ -345,22 +379,24 @@ export function ProposalFormVoteAndEnactmentDeadline({
|
|||||||
validation: prev.validation && Math.min(prev.validation, hours),
|
validation: prev.validation && Math.min(prev.validation, hours),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// If the vote deadline is set to minimum, add 2 mins to the date as we do
|
// If the vote deadlines are set to minimum, add 2 mins to the date as we do
|
||||||
// this on submission to allow time to confirm in the wallet. Amending the
|
// this on submission to allow time to confirm in the wallet. Amending the
|
||||||
// vote deadline also changes the enactment date and potentially the validation
|
// vote deadline also changes the enactment date and potentially the validation
|
||||||
// date.
|
// date.
|
||||||
// The validation deadline date cannot be after the vote deadline date. Therefore,
|
// The validation deadline date cannot be after the vote deadline date. Therefore,
|
||||||
// if the vote deadline is changed, the validation deadline must potentially
|
// if the vote deadline is changed, the validation deadline must potentially
|
||||||
// be changed to be within the new vote deadline.
|
// be changed to be within the new vote deadline.
|
||||||
|
// Whilst it's not ideal, currently enactment deadlines are uncoupled from
|
||||||
|
// vote deadlines in the API. Therefore, the UI currently is too, so updating
|
||||||
|
// the vote deadline does not update the enactment deadline.
|
||||||
setDeadlineDates((prev) => ({
|
setDeadlineDates((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
vote:
|
vote: addHours(
|
||||||
hours === minVoteHours
|
(hours === minVoteHours && addTwoMinutes()) ||
|
||||||
? addHours(addMinutes(new Date(), 2), hours)
|
(hours === maxVoteHours && subtractTwoSeconds()) ||
|
||||||
: addHours(new Date(), hours),
|
new Date(),
|
||||||
enactment: deadlines.enactment
|
hours
|
||||||
? addHours(new Date(), hours + deadlines.enactment)
|
),
|
||||||
: undefined,
|
|
||||||
validation: addHours(new Date(), Math.min(hours, deadlines.validation)),
|
validation: addHours(new Date(), Math.min(hours, deadlines.validation)),
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
@ -373,7 +409,12 @@ export function ProposalFormVoteAndEnactmentDeadline({
|
|||||||
|
|
||||||
setDeadlineDates((prev) => ({
|
setDeadlineDates((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
enactment: addHours(deadlineDates.vote, hours),
|
enactment: addHours(
|
||||||
|
(hours === minEnactmentHours && addTwoMinutes()) ||
|
||||||
|
(hours === maxEnactmentHours && subtractTwoSeconds()) ||
|
||||||
|
new Date(),
|
||||||
|
hours
|
||||||
|
),
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -385,10 +426,12 @@ export function ProposalFormVoteAndEnactmentDeadline({
|
|||||||
|
|
||||||
setDeadlineDates((prev) => ({
|
setDeadlineDates((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
validation:
|
validation: addHours(
|
||||||
hours === 0
|
(hours === 0 && addTwoMinutes()) ||
|
||||||
? addHours(addMinutes(new Date(), 2), hours)
|
(hours === maxVoteHours && subtractTwoSeconds()) ||
|
||||||
: addHours(new Date(), hours),
|
new Date(),
|
||||||
|
hours
|
||||||
|
),
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -56,6 +56,12 @@ export const ProposeFreeform = () => {
|
|||||||
params.governance_proposal_freeform_minClose
|
params.governance_proposal_freeform_minClose
|
||||||
).toString();
|
).toString();
|
||||||
|
|
||||||
|
const isVoteDeadlineAtMaximum =
|
||||||
|
fields.proposalVoteDeadline ===
|
||||||
|
deadlineToRoundedHours(
|
||||||
|
params.governance_proposal_freeform_maxClose
|
||||||
|
).toString();
|
||||||
|
|
||||||
await submit({
|
await submit({
|
||||||
rationale: {
|
rationale: {
|
||||||
title: fields.proposalTitle,
|
title: fields.proposalTitle,
|
||||||
@ -65,7 +71,8 @@ export const ProposeFreeform = () => {
|
|||||||
newFreeform: {},
|
newFreeform: {},
|
||||||
closingTimestamp: getClosingTimestamp(
|
closingTimestamp: getClosingTimestamp(
|
||||||
fields.proposalVoteDeadline,
|
fields.proposalVoteDeadline,
|
||||||
isVoteDeadlineAtMinimum
|
isVoteDeadlineAtMinimum,
|
||||||
|
isVoteDeadlineAtMaximum
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -9,7 +9,7 @@ import {
|
|||||||
getClosingTimestamp,
|
getClosingTimestamp,
|
||||||
getEnactmentTimestamp,
|
getEnactmentTimestamp,
|
||||||
useProposalSubmit,
|
useProposalSubmit,
|
||||||
deadlineToRoundedHours,
|
doesValueEquateToParam,
|
||||||
} from '@vegaprotocol/governance';
|
} from '@vegaprotocol/governance';
|
||||||
import { useEnvironment } from '@vegaprotocol/environment';
|
import { useEnvironment } from '@vegaprotocol/environment';
|
||||||
import {
|
import {
|
||||||
@ -103,11 +103,22 @@ export const ProposeNetworkParameter = () => {
|
|||||||
.split('_')
|
.split('_')
|
||||||
.join('.');
|
.join('.');
|
||||||
|
|
||||||
const isVoteDeadlineAtMinimum =
|
const isVoteDeadlineAtMinimum = doesValueEquateToParam(
|
||||||
fields.proposalVoteDeadline ===
|
fields.proposalVoteDeadline,
|
||||||
deadlineToRoundedHours(
|
|
||||||
params.governance_proposal_updateNetParam_minClose
|
params.governance_proposal_updateNetParam_minClose
|
||||||
).toString();
|
);
|
||||||
|
const isVoteDeadlineAtMaximum = doesValueEquateToParam(
|
||||||
|
fields.proposalVoteDeadline,
|
||||||
|
params.governance_proposal_updateNetParam_maxClose
|
||||||
|
);
|
||||||
|
const isEnactmentDeadlineAtMinimum = doesValueEquateToParam(
|
||||||
|
fields.proposalEnactmentDeadline,
|
||||||
|
params.governance_proposal_updateNetParam_minEnact
|
||||||
|
);
|
||||||
|
const isEnactmentDeadlineAtMaximum = doesValueEquateToParam(
|
||||||
|
fields.proposalEnactmentDeadline,
|
||||||
|
params.governance_proposal_updateNetParam_maxEnact
|
||||||
|
);
|
||||||
|
|
||||||
await submit({
|
await submit({
|
||||||
rationale: {
|
rationale: {
|
||||||
@ -123,12 +134,13 @@ export const ProposeNetworkParameter = () => {
|
|||||||
},
|
},
|
||||||
closingTimestamp: getClosingTimestamp(
|
closingTimestamp: getClosingTimestamp(
|
||||||
fields.proposalVoteDeadline,
|
fields.proposalVoteDeadline,
|
||||||
isVoteDeadlineAtMinimum
|
isVoteDeadlineAtMinimum,
|
||||||
|
isVoteDeadlineAtMaximum
|
||||||
),
|
),
|
||||||
enactmentTimestamp: getEnactmentTimestamp(
|
enactmentTimestamp: getEnactmentTimestamp(
|
||||||
fields.proposalVoteDeadline,
|
|
||||||
fields.proposalEnactmentDeadline,
|
fields.proposalEnactmentDeadline,
|
||||||
isVoteDeadlineAtMinimum
|
isEnactmentDeadlineAtMinimum,
|
||||||
|
isEnactmentDeadlineAtMaximum
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -5,7 +5,7 @@ import {
|
|||||||
getEnactmentTimestamp,
|
getEnactmentTimestamp,
|
||||||
getValidationTimestamp,
|
getValidationTimestamp,
|
||||||
useProposalSubmit,
|
useProposalSubmit,
|
||||||
deadlineToRoundedHours,
|
doesValueEquateToParam,
|
||||||
} from '@vegaprotocol/governance';
|
} from '@vegaprotocol/governance';
|
||||||
import { useEnvironment } from '@vegaprotocol/environment';
|
import { useEnvironment } from '@vegaprotocol/environment';
|
||||||
import {
|
import {
|
||||||
@ -65,11 +65,26 @@ export const ProposeNewAsset = () => {
|
|||||||
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
|
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
|
||||||
|
|
||||||
const onSubmit = async (fields: NewAssetProposalFormFields) => {
|
const onSubmit = async (fields: NewAssetProposalFormFields) => {
|
||||||
const isVoteDeadlineAtMinimum =
|
const isVoteDeadlineAtMinimum = doesValueEquateToParam(
|
||||||
fields.proposalVoteDeadline ===
|
fields.proposalVoteDeadline,
|
||||||
deadlineToRoundedHours(
|
|
||||||
params.governance_proposal_asset_minClose
|
params.governance_proposal_asset_minClose
|
||||||
).toString();
|
);
|
||||||
|
const isVoteDeadlineAtMaximum = doesValueEquateToParam(
|
||||||
|
fields.proposalVoteDeadline,
|
||||||
|
params.governance_proposal_asset_maxClose
|
||||||
|
);
|
||||||
|
const isEnactmentDeadlineAtMinimum = doesValueEquateToParam(
|
||||||
|
fields.proposalEnactmentDeadline,
|
||||||
|
params.governance_proposal_asset_minEnact
|
||||||
|
);
|
||||||
|
const isEnactmentDeadlineAtMaximum = doesValueEquateToParam(
|
||||||
|
fields.proposalEnactmentDeadline,
|
||||||
|
params.governance_proposal_asset_maxEnact
|
||||||
|
);
|
||||||
|
const isValidationDeadlineAtMaximum = doesValueEquateToParam(
|
||||||
|
fields.proposalValidationDeadline,
|
||||||
|
params.governance_proposal_asset_maxClose
|
||||||
|
);
|
||||||
|
|
||||||
await submit({
|
await submit({
|
||||||
rationale: {
|
rationale: {
|
||||||
@ -82,15 +97,17 @@ export const ProposeNewAsset = () => {
|
|||||||
},
|
},
|
||||||
closingTimestamp: getClosingTimestamp(
|
closingTimestamp: getClosingTimestamp(
|
||||||
fields.proposalVoteDeadline,
|
fields.proposalVoteDeadline,
|
||||||
isVoteDeadlineAtMinimum
|
isVoteDeadlineAtMinimum,
|
||||||
|
isVoteDeadlineAtMaximum
|
||||||
),
|
),
|
||||||
enactmentTimestamp: getEnactmentTimestamp(
|
enactmentTimestamp: getEnactmentTimestamp(
|
||||||
fields.proposalVoteDeadline,
|
|
||||||
fields.proposalEnactmentDeadline,
|
fields.proposalEnactmentDeadline,
|
||||||
isVoteDeadlineAtMinimum
|
isEnactmentDeadlineAtMinimum,
|
||||||
|
isEnactmentDeadlineAtMaximum
|
||||||
),
|
),
|
||||||
validationTimestamp: getValidationTimestamp(
|
validationTimestamp: getValidationTimestamp(
|
||||||
fields.proposalValidationDeadline
|
fields.proposalValidationDeadline,
|
||||||
|
isValidationDeadlineAtMaximum
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -4,7 +4,7 @@ import {
|
|||||||
getClosingTimestamp,
|
getClosingTimestamp,
|
||||||
getEnactmentTimestamp,
|
getEnactmentTimestamp,
|
||||||
useProposalSubmit,
|
useProposalSubmit,
|
||||||
deadlineToRoundedHours,
|
doesValueEquateToParam,
|
||||||
} from '@vegaprotocol/governance';
|
} from '@vegaprotocol/governance';
|
||||||
import { useEnvironment } from '@vegaprotocol/environment';
|
import { useEnvironment } from '@vegaprotocol/environment';
|
||||||
import {
|
import {
|
||||||
@ -63,11 +63,22 @@ export const ProposeNewMarket = () => {
|
|||||||
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
|
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
|
||||||
|
|
||||||
const onSubmit = async (fields: NewMarketProposalFormFields) => {
|
const onSubmit = async (fields: NewMarketProposalFormFields) => {
|
||||||
const isVoteDeadlineAtMinimum =
|
const isVoteDeadlineAtMinimum = doesValueEquateToParam(
|
||||||
fields.proposalVoteDeadline ===
|
fields.proposalVoteDeadline,
|
||||||
deadlineToRoundedHours(
|
|
||||||
params.governance_proposal_market_minClose
|
params.governance_proposal_market_minClose
|
||||||
).toString();
|
);
|
||||||
|
const isVoteDeadlineAtMaximum = doesValueEquateToParam(
|
||||||
|
fields.proposalVoteDeadline,
|
||||||
|
params.governance_proposal_market_maxClose
|
||||||
|
);
|
||||||
|
const isEnactmentDeadlineAtMinimum = doesValueEquateToParam(
|
||||||
|
fields.proposalEnactmentDeadline,
|
||||||
|
params.governance_proposal_market_minEnact
|
||||||
|
);
|
||||||
|
const isEnactmentDeadlineAtMaximum = doesValueEquateToParam(
|
||||||
|
fields.proposalEnactmentDeadline,
|
||||||
|
params.governance_proposal_market_maxEnact
|
||||||
|
);
|
||||||
|
|
||||||
await submit({
|
await submit({
|
||||||
rationale: {
|
rationale: {
|
||||||
@ -80,12 +91,13 @@ export const ProposeNewMarket = () => {
|
|||||||
},
|
},
|
||||||
closingTimestamp: getClosingTimestamp(
|
closingTimestamp: getClosingTimestamp(
|
||||||
fields.proposalVoteDeadline,
|
fields.proposalVoteDeadline,
|
||||||
isVoteDeadlineAtMinimum
|
isVoteDeadlineAtMinimum,
|
||||||
|
isVoteDeadlineAtMaximum
|
||||||
),
|
),
|
||||||
enactmentTimestamp: getEnactmentTimestamp(
|
enactmentTimestamp: getEnactmentTimestamp(
|
||||||
fields.proposalVoteDeadline,
|
|
||||||
fields.proposalEnactmentDeadline,
|
fields.proposalEnactmentDeadline,
|
||||||
isVoteDeadlineAtMinimum
|
isEnactmentDeadlineAtMinimum,
|
||||||
|
isEnactmentDeadlineAtMaximum
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -4,7 +4,7 @@ import {
|
|||||||
getClosingTimestamp,
|
getClosingTimestamp,
|
||||||
getEnactmentTimestamp,
|
getEnactmentTimestamp,
|
||||||
useProposalSubmit,
|
useProposalSubmit,
|
||||||
deadlineToRoundedHours,
|
doesValueEquateToParam,
|
||||||
} from '@vegaprotocol/governance';
|
} from '@vegaprotocol/governance';
|
||||||
import { useEnvironment } from '@vegaprotocol/environment';
|
import { useEnvironment } from '@vegaprotocol/environment';
|
||||||
import {
|
import {
|
||||||
@ -63,11 +63,22 @@ export const ProposeUpdateAsset = () => {
|
|||||||
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
|
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
|
||||||
|
|
||||||
const onSubmit = async (fields: UpdateAssetProposalFormFields) => {
|
const onSubmit = async (fields: UpdateAssetProposalFormFields) => {
|
||||||
const isVoteDeadlineAtMinimum =
|
const isVoteDeadlineAtMinimum = doesValueEquateToParam(
|
||||||
fields.proposalVoteDeadline ===
|
fields.proposalVoteDeadline,
|
||||||
deadlineToRoundedHours(
|
|
||||||
params.governance_proposal_updateAsset_minClose
|
params.governance_proposal_updateAsset_minClose
|
||||||
).toString();
|
);
|
||||||
|
const isVoteDeadlineAtMaximum = doesValueEquateToParam(
|
||||||
|
fields.proposalVoteDeadline,
|
||||||
|
params.governance_proposal_updateAsset_maxClose
|
||||||
|
);
|
||||||
|
const isEnactmentDeadlineAtMinimum = doesValueEquateToParam(
|
||||||
|
fields.proposalEnactmentDeadline,
|
||||||
|
params.governance_proposal_updateAsset_minEnact
|
||||||
|
);
|
||||||
|
const isEnactmentDeadlineAtMaximum = doesValueEquateToParam(
|
||||||
|
fields.proposalEnactmentDeadline,
|
||||||
|
params.governance_proposal_updateAsset_maxEnact
|
||||||
|
);
|
||||||
|
|
||||||
await submit({
|
await submit({
|
||||||
rationale: {
|
rationale: {
|
||||||
@ -80,12 +91,13 @@ export const ProposeUpdateAsset = () => {
|
|||||||
},
|
},
|
||||||
closingTimestamp: getClosingTimestamp(
|
closingTimestamp: getClosingTimestamp(
|
||||||
fields.proposalVoteDeadline,
|
fields.proposalVoteDeadline,
|
||||||
isVoteDeadlineAtMinimum
|
isVoteDeadlineAtMinimum,
|
||||||
|
isVoteDeadlineAtMaximum
|
||||||
),
|
),
|
||||||
enactmentTimestamp: getEnactmentTimestamp(
|
enactmentTimestamp: getEnactmentTimestamp(
|
||||||
fields.proposalVoteDeadline,
|
|
||||||
fields.proposalEnactmentDeadline,
|
fields.proposalEnactmentDeadline,
|
||||||
isVoteDeadlineAtMinimum
|
isEnactmentDeadlineAtMinimum,
|
||||||
|
isEnactmentDeadlineAtMaximum
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -171,6 +183,7 @@ export const ProposeUpdateAsset = () => {
|
|||||||
voteErrorMessage={errors?.proposalVoteDeadline?.message}
|
voteErrorMessage={errors?.proposalVoteDeadline?.message}
|
||||||
voteMinClose={params.governance_proposal_updateAsset_minClose}
|
voteMinClose={params.governance_proposal_updateAsset_minClose}
|
||||||
voteMaxClose={params.governance_proposal_updateAsset_maxClose}
|
voteMaxClose={params.governance_proposal_updateAsset_maxClose}
|
||||||
|
onEnactMinMax={setValue}
|
||||||
enactmentRegister={register('proposalEnactmentDeadline', {
|
enactmentRegister={register('proposalEnactmentDeadline', {
|
||||||
required: t('Required'),
|
required: t('Required'),
|
||||||
})}
|
})}
|
||||||
|
@ -6,7 +6,7 @@ import {
|
|||||||
getClosingTimestamp,
|
getClosingTimestamp,
|
||||||
getEnactmentTimestamp,
|
getEnactmentTimestamp,
|
||||||
useProposalSubmit,
|
useProposalSubmit,
|
||||||
deadlineToRoundedHours,
|
doesValueEquateToParam,
|
||||||
} from '@vegaprotocol/governance';
|
} from '@vegaprotocol/governance';
|
||||||
import { useEnvironment } from '@vegaprotocol/environment';
|
import { useEnvironment } from '@vegaprotocol/environment';
|
||||||
import {
|
import {
|
||||||
@ -123,11 +123,22 @@ export const ProposeUpdateMarket = () => {
|
|||||||
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
|
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
|
||||||
|
|
||||||
const onSubmit = async (fields: UpdateMarketProposalFormFields) => {
|
const onSubmit = async (fields: UpdateMarketProposalFormFields) => {
|
||||||
const isVoteDeadlineAtMinimum =
|
const isVoteDeadlineAtMinimum = doesValueEquateToParam(
|
||||||
fields.proposalVoteDeadline ===
|
fields.proposalVoteDeadline,
|
||||||
deadlineToRoundedHours(
|
|
||||||
params.governance_proposal_updateMarket_minClose
|
params.governance_proposal_updateMarket_minClose
|
||||||
).toString();
|
);
|
||||||
|
const isVoteDeadlineAtMaximum = doesValueEquateToParam(
|
||||||
|
fields.proposalVoteDeadline,
|
||||||
|
params.governance_proposal_updateMarket_maxClose
|
||||||
|
);
|
||||||
|
const isEnactmentDeadlineAtMinimum = doesValueEquateToParam(
|
||||||
|
fields.proposalEnactmentDeadline,
|
||||||
|
params.governance_proposal_updateMarket_minEnact
|
||||||
|
);
|
||||||
|
const isEnactmentDeadlineAtMaximum = doesValueEquateToParam(
|
||||||
|
fields.proposalEnactmentDeadline,
|
||||||
|
params.governance_proposal_updateMarket_maxEnact
|
||||||
|
);
|
||||||
|
|
||||||
await submit({
|
await submit({
|
||||||
rationale: {
|
rationale: {
|
||||||
@ -143,12 +154,13 @@ export const ProposeUpdateMarket = () => {
|
|||||||
},
|
},
|
||||||
closingTimestamp: getClosingTimestamp(
|
closingTimestamp: getClosingTimestamp(
|
||||||
fields.proposalVoteDeadline,
|
fields.proposalVoteDeadline,
|
||||||
isVoteDeadlineAtMinimum
|
isVoteDeadlineAtMinimum,
|
||||||
|
isVoteDeadlineAtMaximum
|
||||||
),
|
),
|
||||||
enactmentTimestamp: getEnactmentTimestamp(
|
enactmentTimestamp: getEnactmentTimestamp(
|
||||||
fields.proposalVoteDeadline,
|
|
||||||
fields.proposalEnactmentDeadline,
|
fields.proposalEnactmentDeadline,
|
||||||
isVoteDeadlineAtMinimum
|
isEnactmentDeadlineAtMinimum,
|
||||||
|
isEnactmentDeadlineAtMaximum
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,9 @@
|
|||||||
import { deadlineToSeconds, secondsToRoundedHours } from './deadline-helpers';
|
import {
|
||||||
|
deadlineToSeconds,
|
||||||
|
secondsToRoundedHours,
|
||||||
|
addTwoMinutes,
|
||||||
|
subtractTwoSeconds,
|
||||||
|
} from './deadline-helpers';
|
||||||
|
|
||||||
describe('deadlineToSeconds', () => {
|
describe('deadlineToSeconds', () => {
|
||||||
it('should throw an error if the deadline does not match the format "XhXmXs"', () => {
|
it('should throw an error if the deadline does not match the format "XhXmXs"', () => {
|
||||||
@ -39,3 +44,37 @@ describe('secondsToRoundedHours', () => {
|
|||||||
expect(secondsToRoundedHours(9000)).toEqual(3);
|
expect(secondsToRoundedHours(9000)).toEqual(3);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('addTwoMinutes', () => {
|
||||||
|
it('should add two minutes to the current time', () => {
|
||||||
|
const now = new Date();
|
||||||
|
const twoMinutesLater = new Date(now.getTime() + 2 * 60 * 1000);
|
||||||
|
expect(addTwoMinutes(now)).toEqual(twoMinutesLater);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('will use the current time if no date is provided', () => {
|
||||||
|
const now = new Date();
|
||||||
|
const twoMinutesLater = new Date(now.getTime() + 2 * 60 * 1000);
|
||||||
|
expect(addTwoMinutes()).toEqual(twoMinutesLater);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add two minutes to a given time', () => {
|
||||||
|
const date = new Date(2020, 0, 1);
|
||||||
|
const twoMinutesLater = new Date(date.getTime() + 2 * 60 * 1000);
|
||||||
|
expect(addTwoMinutes(date)).toEqual(twoMinutesLater);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('subtractTwoSeconds', () => {
|
||||||
|
it('should subtract two seconds to the current time', () => {
|
||||||
|
const now = new Date();
|
||||||
|
const twoSecondsEarlier = new Date(now.getTime() - 2 * 1000);
|
||||||
|
expect(subtractTwoSeconds(now)).toEqual(twoSecondsEarlier);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should subtract two seconds from a given time', () => {
|
||||||
|
const date = new Date(2020, 0, 1);
|
||||||
|
const twoSecondsEarlier = new Date(date.getTime() - 2 * 1000);
|
||||||
|
expect(subtractTwoSeconds(date)).toEqual(twoSecondsEarlier);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
@ -1,10 +1,15 @@
|
|||||||
import { parse as ISO8601Parse, toSeconds } from 'iso8601-duration';
|
import { parse as ISO8601Parse, toSeconds } from 'iso8601-duration';
|
||||||
|
import { addMinutes, subSeconds } from 'date-fns';
|
||||||
|
|
||||||
|
const deadlineRegexChecker = (deadline: string) => {
|
||||||
|
// check that the deadline string matches the format "XhXmXs"
|
||||||
|
const regex = /^(\d+h)?(\d+m)?(\d+s)?$/;
|
||||||
|
return regex.test(deadline);
|
||||||
|
};
|
||||||
|
|
||||||
// Converts API deadlines ("XhXmXs") to seconds
|
// Converts API deadlines ("XhXmXs") to seconds
|
||||||
export const deadlineToSeconds = (deadline: string) => {
|
export const deadlineToSeconds = (deadline: string) => {
|
||||||
// check that the deadline string matches the format "XhXmXs"
|
if (!deadlineRegexChecker(deadline)) {
|
||||||
const regex = /^(\d+h)?(\d+m)?(\d+s)?$/;
|
|
||||||
if (!regex.test(deadline)) {
|
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Invalid deadline format, expected format "XhXmXs", got "${deadline}"`
|
`Invalid deadline format, expected format "XhXmXs", got "${deadline}"`
|
||||||
);
|
);
|
||||||
@ -20,3 +25,11 @@ export const secondsToRoundedHours = (seconds: number) => {
|
|||||||
|
|
||||||
export const deadlineToRoundedHours = (deadline: string) =>
|
export const deadlineToRoundedHours = (deadline: string) =>
|
||||||
secondsToRoundedHours(deadlineToSeconds(deadline));
|
secondsToRoundedHours(deadlineToSeconds(deadline));
|
||||||
|
|
||||||
|
export const doesValueEquateToParam = (value: string, param: string) =>
|
||||||
|
value === deadlineToRoundedHours(param).toString();
|
||||||
|
|
||||||
|
export const addTwoMinutes = (date?: Date) => addMinutes(date || new Date(), 2);
|
||||||
|
|
||||||
|
export const subtractTwoSeconds = (date?: Date) =>
|
||||||
|
subSeconds(date || new Date(), 2);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { getClosingTimestamp } from './get-closing-timestamp';
|
import { getClosingTimestamp } from './get-closing-timestamp';
|
||||||
import { addHours, addMinutes, getTime } from 'date-fns';
|
import { addHours, addMinutes, getTime, subSeconds } from 'date-fns';
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.useFakeTimers();
|
jest.useFakeTimers();
|
||||||
@ -14,6 +14,7 @@ describe('getClosingTimestamp', () => {
|
|||||||
it('should return the correct timestamp if the proposalVoteDeadline is set to minimum (when 2 mins are added)', () => {
|
it('should return the correct timestamp if the proposalVoteDeadline is set to minimum (when 2 mins are added)', () => {
|
||||||
const proposalVoteDeadline = '1';
|
const proposalVoteDeadline = '1';
|
||||||
const isMinimumDeadlineSelected = true;
|
const isMinimumDeadlineSelected = true;
|
||||||
|
const isMaximumDeadlineSelected = false;
|
||||||
const expected = Math.floor(
|
const expected = Math.floor(
|
||||||
getTime(
|
getTime(
|
||||||
addHours(addMinutes(new Date(), 2), Number(proposalVoteDeadline))
|
addHours(addMinutes(new Date(), 2), Number(proposalVoteDeadline))
|
||||||
@ -21,20 +22,40 @@ describe('getClosingTimestamp', () => {
|
|||||||
);
|
);
|
||||||
const actual = getClosingTimestamp(
|
const actual = getClosingTimestamp(
|
||||||
proposalVoteDeadline,
|
proposalVoteDeadline,
|
||||||
isMinimumDeadlineSelected
|
isMinimumDeadlineSelected,
|
||||||
|
isMaximumDeadlineSelected
|
||||||
);
|
);
|
||||||
expect(actual).toEqual(expected);
|
expect(actual).toEqual(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return the correct timestamp if the proposalVoteDeadline is not set to minimum (when no extra mins are added)', () => {
|
it('should return the correct timestamp if the proposalVoteDeadline is not set to minimum or maximum (no extra time added or subtracted)', () => {
|
||||||
const proposalVoteDeadline = '2';
|
const proposalVoteDeadline = '2';
|
||||||
const isMinimumDeadlineSelected = false;
|
const isMinimumDeadlineSelected = false;
|
||||||
|
const isMaximumDeadlineSelected = false;
|
||||||
const expected = Math.floor(
|
const expected = Math.floor(
|
||||||
getTime(addHours(new Date(), Number(proposalVoteDeadline))) / 1000
|
getTime(addHours(new Date(), Number(proposalVoteDeadline))) / 1000
|
||||||
);
|
);
|
||||||
const actual = getClosingTimestamp(
|
const actual = getClosingTimestamp(
|
||||||
proposalVoteDeadline,
|
proposalVoteDeadline,
|
||||||
isMinimumDeadlineSelected
|
isMinimumDeadlineSelected,
|
||||||
|
isMaximumDeadlineSelected
|
||||||
|
);
|
||||||
|
expect(actual).toEqual(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the correct timestamp if the proposalVoteDeadline is set to maximum (when 2 secs are subtracted)', () => {
|
||||||
|
const proposalVoteDeadline = '3';
|
||||||
|
const isMinimumDeadlineSelected = false;
|
||||||
|
const isMaximumDeadlineSelected = true;
|
||||||
|
const expected = Math.floor(
|
||||||
|
getTime(
|
||||||
|
addHours(subSeconds(new Date(), 2), Number(proposalVoteDeadline))
|
||||||
|
) / 1000
|
||||||
|
);
|
||||||
|
const actual = getClosingTimestamp(
|
||||||
|
proposalVoteDeadline,
|
||||||
|
isMinimumDeadlineSelected,
|
||||||
|
isMaximumDeadlineSelected
|
||||||
);
|
);
|
||||||
expect(actual).toEqual(expected);
|
expect(actual).toEqual(expected);
|
||||||
});
|
});
|
||||||
|
@ -1,17 +1,25 @@
|
|||||||
import { addHours, addMinutes, getTime } from 'date-fns';
|
import { addHours, getTime } from 'date-fns';
|
||||||
|
import { addTwoMinutes, subtractTwoSeconds } from './deadline-helpers';
|
||||||
|
|
||||||
// If proposaVoteDeadline is at its minimum, then we add
|
// If the vote deadline is at its minimum, then we add 2 extra minutes to the
|
||||||
// 2 extra minutes to the closing timestamp to ensure that there's time
|
// closing timestamp to ensure that there's time to confirm in the wallet.
|
||||||
// to confirm in the wallet.
|
|
||||||
|
// If it's at its maximum, remove a couple of seconds to ensure rounding errors
|
||||||
|
// and communication delays don't cause the deadline to be slightly
|
||||||
|
// later than the API can accept.
|
||||||
|
|
||||||
export const getClosingTimestamp = (
|
export const getClosingTimestamp = (
|
||||||
proposalVoteDeadline: string,
|
proposalVoteDeadline: string,
|
||||||
minimumDeadlineSelected: boolean
|
minimumDeadlineSelected: boolean,
|
||||||
|
maximumDeadlineSelected: boolean
|
||||||
) =>
|
) =>
|
||||||
Math.floor(
|
Math.floor(
|
||||||
getTime(
|
getTime(
|
||||||
minimumDeadlineSelected
|
addHours(
|
||||||
? addHours(addMinutes(new Date(), 2), Number(proposalVoteDeadline))
|
(minimumDeadlineSelected && addTwoMinutes()) ||
|
||||||
: addHours(new Date(), Number(proposalVoteDeadline))
|
(maximumDeadlineSelected && subtractTwoSeconds()) ||
|
||||||
|
new Date(),
|
||||||
|
Number(proposalVoteDeadline)
|
||||||
|
)
|
||||||
) / 1000
|
) / 1000
|
||||||
);
|
);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { getEnactmentTimestamp } from './get-enactment-timestamp';
|
import { getEnactmentTimestamp } from './get-enactment-timestamp';
|
||||||
import { addHours, getTime } from 'date-fns';
|
import { addHours, addMinutes, getTime, subSeconds } from 'date-fns';
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.useFakeTimers();
|
jest.useFakeTimers();
|
||||||
@ -12,21 +12,48 @@ afterEach(() => {
|
|||||||
|
|
||||||
describe('getEnactmentTimestamp', () => {
|
describe('getEnactmentTimestamp', () => {
|
||||||
it('should return the correct timestamp', () => {
|
it('should return the correct timestamp', () => {
|
||||||
const proposalVoteDeadline = '2';
|
|
||||||
const isMinimumVoteDeadlineSelected = false;
|
const isMinimumVoteDeadlineSelected = false;
|
||||||
|
const isMaximumVoteDeadlineSelected = false;
|
||||||
const enactmentDeadline = '1';
|
const enactmentDeadline = '1';
|
||||||
const expected = Math.floor(
|
const expected = Math.floor(
|
||||||
getTime(
|
getTime(addHours(new Date(), Number(enactmentDeadline))) / 1000
|
||||||
addHours(
|
|
||||||
new Date(),
|
|
||||||
Number(proposalVoteDeadline) + Number(enactmentDeadline)
|
|
||||||
)
|
|
||||||
) / 1000
|
|
||||||
);
|
);
|
||||||
const actual = getEnactmentTimestamp(
|
const actual = getEnactmentTimestamp(
|
||||||
proposalVoteDeadline,
|
|
||||||
enactmentDeadline,
|
enactmentDeadline,
|
||||||
isMinimumVoteDeadlineSelected
|
isMinimumVoteDeadlineSelected,
|
||||||
|
isMaximumVoteDeadlineSelected
|
||||||
|
);
|
||||||
|
expect(actual).toEqual(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the correct timestamp when minimum vote deadline is selected', () => {
|
||||||
|
const isMinimumVoteDeadlineSelected = true;
|
||||||
|
const isMaximumVoteDeadlineSelected = false;
|
||||||
|
const enactmentDeadline = '1';
|
||||||
|
const expected = Math.floor(
|
||||||
|
getTime(addMinutes(addHours(new Date(), Number(enactmentDeadline)), 2)) /
|
||||||
|
1000
|
||||||
|
);
|
||||||
|
const actual = getEnactmentTimestamp(
|
||||||
|
enactmentDeadline,
|
||||||
|
isMinimumVoteDeadlineSelected,
|
||||||
|
isMaximumVoteDeadlineSelected
|
||||||
|
);
|
||||||
|
expect(actual).toEqual(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the correct timestamp when maximum vote deadline is selected', () => {
|
||||||
|
const isMinimumVoteDeadlineSelected = false;
|
||||||
|
const isMaximumVoteDeadlineSelected = true;
|
||||||
|
const enactmentDeadline = '1';
|
||||||
|
const expected = Math.floor(
|
||||||
|
getTime(subSeconds(addHours(new Date(), Number(enactmentDeadline)), 2)) /
|
||||||
|
1000
|
||||||
|
);
|
||||||
|
const actual = getEnactmentTimestamp(
|
||||||
|
enactmentDeadline,
|
||||||
|
isMinimumVoteDeadlineSelected,
|
||||||
|
isMaximumVoteDeadlineSelected
|
||||||
);
|
);
|
||||||
expect(actual).toEqual(expected);
|
expect(actual).toEqual(expected);
|
||||||
});
|
});
|
||||||
|
@ -1,22 +1,24 @@
|
|||||||
import { addHours, fromUnixTime, getTime } from 'date-fns';
|
import { addHours, getTime } from 'date-fns';
|
||||||
import { getClosingTimestamp } from './get-closing-timestamp';
|
import { addTwoMinutes, subtractTwoSeconds } from './deadline-helpers';
|
||||||
|
|
||||||
|
// If the enactment deadline is at its minimum, then we add 2 extra minutes to the
|
||||||
|
// closing timestamp to ensure that there's time to confirm in the wallet.
|
||||||
|
|
||||||
|
// If it's at its maximum, remove a couple of seconds to ensure rounding errors
|
||||||
|
// and communication delays don't cause the deadline to be slightly
|
||||||
|
// later than the API can accept.
|
||||||
|
|
||||||
export const getEnactmentTimestamp = (
|
export const getEnactmentTimestamp = (
|
||||||
proposalVoteDeadline: string,
|
|
||||||
enactmentDeadline: string,
|
enactmentDeadline: string,
|
||||||
minimumVoteDeadlineSelected: boolean
|
minimumDeadlineSelected: boolean,
|
||||||
|
maximumDeadlineSelected: boolean
|
||||||
) =>
|
) =>
|
||||||
Math.floor(
|
Math.floor(
|
||||||
getTime(
|
getTime(
|
||||||
addHours(
|
addHours(
|
||||||
new Date(
|
(minimumDeadlineSelected && addTwoMinutes()) ||
|
||||||
fromUnixTime(
|
(maximumDeadlineSelected && subtractTwoSeconds()) ||
|
||||||
getClosingTimestamp(
|
new Date(),
|
||||||
proposalVoteDeadline,
|
|
||||||
minimumVoteDeadlineSelected
|
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
Number(enactmentDeadline)
|
Number(enactmentDeadline)
|
||||||
)
|
)
|
||||||
) / 1000
|
) / 1000
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { addHours, addMinutes, getTime } from 'date-fns';
|
import { addHours, addMinutes, getTime, subSeconds } from 'date-fns';
|
||||||
import { getValidationTimestamp } from './get-validation-timestamp';
|
import { getValidationTimestamp } from './get-validation-timestamp';
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@ -13,21 +13,44 @@ afterEach(() => {
|
|||||||
describe('getValidationTimestamp', () => {
|
describe('getValidationTimestamp', () => {
|
||||||
it('should return the correct timestamp if the proposalValidationDeadline is 0 (when 2 mins are added)', () => {
|
it('should return the correct timestamp if the proposalValidationDeadline is 0 (when 2 mins are added)', () => {
|
||||||
const proposalValidationDeadline = '0';
|
const proposalValidationDeadline = '0';
|
||||||
|
const isMaximumDeadlineSelected = false;
|
||||||
const expected = Math.floor(
|
const expected = Math.floor(
|
||||||
getTime(
|
getTime(
|
||||||
addHours(addMinutes(new Date(), 2), Number(proposalValidationDeadline))
|
addHours(addMinutes(new Date(), 2), Number(proposalValidationDeadline))
|
||||||
) / 1000
|
) / 1000
|
||||||
);
|
);
|
||||||
const actual = getValidationTimestamp(proposalValidationDeadline);
|
const actual = getValidationTimestamp(
|
||||||
|
proposalValidationDeadline,
|
||||||
|
isMaximumDeadlineSelected
|
||||||
|
);
|
||||||
expect(actual).toEqual(expected);
|
expect(actual).toEqual(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return the correct timestamp if the proposalValidationDeadline is 1 (when no extra mins are added)', () => {
|
it('should return the correct timestamp if the proposalValidationDeadline is neither maximum nor minimum (when no extra mins are added)', () => {
|
||||||
const proposalValidationDeadline = '1';
|
const proposalValidationDeadline = '1';
|
||||||
|
const isMaximumDeadlineSelected = false;
|
||||||
const expected = Math.floor(
|
const expected = Math.floor(
|
||||||
getTime(addHours(new Date(), Number(proposalValidationDeadline))) / 1000
|
getTime(addHours(new Date(), Number(proposalValidationDeadline))) / 1000
|
||||||
);
|
);
|
||||||
const actual = getValidationTimestamp(proposalValidationDeadline);
|
const actual = getValidationTimestamp(
|
||||||
|
proposalValidationDeadline,
|
||||||
|
isMaximumDeadlineSelected
|
||||||
|
);
|
||||||
|
expect(actual).toEqual(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the correct timestamp if the proposalValidationDeadline is maximum (when 2 secs are subtracted)', () => {
|
||||||
|
const proposalValidationDeadline = '2';
|
||||||
|
const isMaximumDeadlineSelected = true;
|
||||||
|
const expected = Math.floor(
|
||||||
|
getTime(
|
||||||
|
addHours(subSeconds(new Date(), 2), Number(proposalValidationDeadline))
|
||||||
|
) / 1000
|
||||||
|
);
|
||||||
|
const actual = getValidationTimestamp(
|
||||||
|
proposalValidationDeadline,
|
||||||
|
isMaximumDeadlineSelected
|
||||||
|
);
|
||||||
expect(actual).toEqual(expected);
|
expect(actual).toEqual(expected);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,17 +1,25 @@
|
|||||||
import { addHours, addMinutes, getTime } from 'date-fns';
|
import { addHours, getTime } from 'date-fns';
|
||||||
|
import { addTwoMinutes, subtractTwoSeconds } from './deadline-helpers';
|
||||||
|
|
||||||
// If proposalValidationDeadline is at its minimum of 0 hours, then we add
|
// If proposalValidationDeadline is at its minimum of 0 hours, then we add
|
||||||
// 2 extra minutes to the validation timestamp to ensure that there's time
|
// 2 extra minutes to the validation timestamp to ensure that there's time
|
||||||
// to confirm in the wallet.
|
// to confirm in the wallet.
|
||||||
|
|
||||||
export const getValidationTimestamp = (proposalValidationDeadline: string) =>
|
// If it's at its maximum, remove a couple of seconds to ensure rounding errors
|
||||||
|
// and communication delays don't cause the proposal deadline to be slightly
|
||||||
|
// later than the API can accept.
|
||||||
|
|
||||||
|
export const getValidationTimestamp = (
|
||||||
|
proposalValidationDeadline: string,
|
||||||
|
maximumDeadlineSelected: boolean
|
||||||
|
) =>
|
||||||
Math.floor(
|
Math.floor(
|
||||||
getTime(
|
getTime(
|
||||||
proposalValidationDeadline === '0'
|
addHours(
|
||||||
? addHours(
|
(proposalValidationDeadline === '0' && addTwoMinutes()) ||
|
||||||
addMinutes(new Date(), 2),
|
(maximumDeadlineSelected && subtractTwoSeconds()) ||
|
||||||
|
new Date(),
|
||||||
Number(proposalValidationDeadline)
|
Number(proposalValidationDeadline)
|
||||||
)
|
)
|
||||||
: addHours(new Date(), Number(proposalValidationDeadline))
|
|
||||||
) / 1000
|
) / 1000
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user