Feat/1666: Added min requirements for raw proposal form. Tests failing (#1884)

* Feat/1666: Added min requirements for raw proposal form. Tests failing

* Feat/1666: Tests now passing
This commit is contained in:
Sam Keen 2022-10-31 16:02:04 +00:00 committed by GitHub
parent 03e39e8323
commit 1f8469a97a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 230 additions and 13 deletions

View File

@ -702,5 +702,7 @@
"FreeformProposal": "Freeform proposal", "FreeformProposal": "Freeform proposal",
"unknownReason": "unknown reason", "unknownReason": "unknown reason",
"votingEnded": "Voting has ended.", "votingEnded": "Voting has ended.",
"STATUS": "STATUS" "STATUS": "STATUS",
"ProposalMinimumAmounts": "Different proposal types can have different minimum token requirements. You must have the greater of the proposal minimum or spam protection minimum from the table below",
"SpamProtectionMin": "Spam protection minimum"
} }

View File

@ -13,6 +13,9 @@ interface ProposalFormMinRequirementsProps {
userAction: ProposalUserAction.CREATE | ProposalUserAction.VOTE; userAction: ProposalUserAction.CREATE | ProposalUserAction.VOTE;
} }
export const formatMinRequiredBalance = (balance: string) =>
new BigNumber(addDecimal(balance, 18));
// Returns the larger, formatted value of the two token amounts // Returns the larger, formatted value of the two token amounts
export const ProposalMinRequirements = ({ export const ProposalMinRequirements = ({
minProposalBalance, minProposalBalance,
@ -20,12 +23,10 @@ export const ProposalMinRequirements = ({
userAction, userAction,
}: ProposalFormMinRequirementsProps) => { }: ProposalFormMinRequirementsProps) => {
const { t } = useTranslation(); const { t } = useTranslation();
const minProposalBalanceFormatted = new BigNumber( const minProposalBalanceFormatted =
addDecimal(minProposalBalance, 18) formatMinRequiredBalance(minProposalBalance);
); const spamProtectionMinFormatted =
const spamProtectionMinFormatted = new BigNumber( formatMinRequiredBalance(spamProtectionMin);
addDecimal(spamProtectionMin, 18)
);
const larger = const larger =
minProposalBalanceFormatted > spamProtectionMinFormatted minProposalBalanceFormatted > spamProtectionMinFormatted

View File

@ -15,7 +15,7 @@ jest.mock('@vegaprotocol/environment', () => ({
}), }),
})); }));
const updateMarketNetworkParamsQueryMock: MockedResponse<NetworkParamsQuery> = { const newAssetNetworkParamsQueryMock: MockedResponse<NetworkParamsQuery> = {
request: { request: {
query: NETWORK_PARAMETERS_QUERY, query: NETWORK_PARAMETERS_QUERY,
}, },
@ -60,7 +60,7 @@ const updateMarketNetworkParamsQueryMock: MockedResponse<NetworkParamsQuery> = {
const renderComponent = () => const renderComponent = () =>
render( render(
<Router> <Router>
<MockedProvider mocks={[updateMarketNetworkParamsQueryMock]}> <MockedProvider mocks={[newAssetNetworkParamsQueryMock]}>
<AppStateProvider> <AppStateProvider>
<VegaWalletContext.Provider value={mockWalletContext}> <VegaWalletContext.Provider value={mockWalletContext}>
<ProposeNewAsset /> <ProposeNewAsset />

View File

@ -0,0 +1,104 @@
import { useTranslation } from 'react-i18next';
import { KeyValueTable, KeyValueTableRow } from '@vegaprotocol/ui-toolkit';
import { formatMinRequiredBalance } from '../../components/shared';
import type { ReactNode } from 'react';
export interface ProposalRawMinRequirementsProps {
assetMin: string;
updateAssetMin: string;
marketMin: string;
updateMarketMin: string;
updateNetParamMin: string;
freeformMin: string;
spamProtectionMin: string;
}
const Wrapper = ({ children }: { children: ReactNode }) => (
<div className="mb-4" data-testid="proposal-raw-min-requirements">
{children}
</div>
);
export const ProposalRawMinRequirements = ({
assetMin,
updateAssetMin,
marketMin,
updateMarketMin,
updateNetParamMin,
freeformMin,
spamProtectionMin,
}: ProposalRawMinRequirementsProps) => {
const { t } = useTranslation();
if (
assetMin <= spamProtectionMin &&
updateAssetMin <= spamProtectionMin &&
marketMin <= spamProtectionMin &&
updateMarketMin <= spamProtectionMin &&
updateNetParamMin <= spamProtectionMin &&
freeformMin <= spamProtectionMin
) {
return (
<Wrapper>
{t('MinProposalRequirements', {
value: Number(formatMinRequiredBalance(spamProtectionMin)),
})}
</Wrapper>
);
}
if (
assetMin === updateAssetMin &&
assetMin === marketMin &&
assetMin === updateMarketMin &&
assetMin === updateNetParamMin &&
assetMin === freeformMin
) {
return (
<Wrapper>
{t('MinProposalRequirements', {
value: Number(formatMinRequiredBalance(assetMin)),
})}
</Wrapper>
);
}
return (
<Wrapper>
<div className="mb-4">
{t(
'Different proposal types can have different minimum token requirements. You must have the greater of the proposal minimum or spam protection minimum from the table below'
)}
</div>
<KeyValueTable>
<KeyValueTableRow>
{t('NewAsset')}
{`${formatMinRequiredBalance(assetMin).toString()} VEGA`}
</KeyValueTableRow>
<KeyValueTableRow>
{t('UpdateAsset')}
{`${formatMinRequiredBalance(updateAssetMin).toString()} VEGA`}
</KeyValueTableRow>
<KeyValueTableRow>
{t('NewMarket')}
{`${formatMinRequiredBalance(marketMin).toString()} VEGA`}
</KeyValueTableRow>
<KeyValueTableRow>
{t('UpdateMarket')}
{`${formatMinRequiredBalance(updateMarketMin).toString()} VEGA`}
</KeyValueTableRow>
<KeyValueTableRow>
{t('NetworkParameter')}
{`${formatMinRequiredBalance(updateNetParamMin).toString()} VEGA`}
</KeyValueTableRow>
<KeyValueTableRow>
{t('Freeform')}
{`${formatMinRequiredBalance(freeformMin).toString()} VEGA`}
</KeyValueTableRow>
<KeyValueTableRow>
{t('SpamProtectionMin')}
{`${formatMinRequiredBalance(spamProtectionMin).toString()} VEGA`}
</KeyValueTableRow>
</KeyValueTable>
</Wrapper>
);
};

View File

@ -13,6 +13,58 @@ import {
import { ProposeRaw } from './propose-raw'; import { ProposeRaw } from './propose-raw';
import { ProposalEventDocument } from '@vegaprotocol/governance'; import { ProposalEventDocument } from '@vegaprotocol/governance';
import type { ProposalEventSubscription } from '@vegaprotocol/governance'; import type { ProposalEventSubscription } from '@vegaprotocol/governance';
import { NETWORK_PARAMETERS_QUERY } from '@vegaprotocol/react-helpers';
import type { NetworkParamsQuery } from '@vegaprotocol/web3';
const paramsDelay = 20;
const rawProposalNetworkParamsQueryMock: MockedResponse<NetworkParamsQuery> = {
request: {
query: NETWORK_PARAMETERS_QUERY,
},
result: {
data: {
networkParameters: [
{
__typename: 'NetworkParameter',
key: 'governance.proposal.asset.minProposerBalance',
value: '1',
},
{
__typename: 'NetworkParameter',
key: 'governance.proposal.updateAsset.minProposerBalance',
value: '1',
},
{
__typename: 'NetworkParameter',
key: 'governance.proposal.market.minProposerBalance',
value: '1',
},
{
__typename: 'NetworkParameter',
key: 'governance.proposal.updateMarket.minProposerBalance',
value: '1',
},
{
__typename: 'NetworkParameter',
key: 'governance.proposal.updateNetParam.minProposerBalance',
value: '1',
},
{
__typename: 'NetworkParameter',
key: 'governance.proposal.freeform.minProposerBalance',
value: '1',
},
{
__typename: 'NetworkParameter',
key: 'spam.protection.proposal.min.tokens',
value: '1000000000000000000',
},
],
},
},
delay: paramsDelay,
};
describe('Raw proposal form', () => { describe('Raw proposal form', () => {
const pubKey = '0x123'; const pubKey = '0x123';
@ -47,7 +99,9 @@ describe('Raw proposal form', () => {
const setup = (mockSendTx = jest.fn()) => { const setup = (mockSendTx = jest.fn()) => {
return render( return render(
<AppStateProvider> <AppStateProvider>
<MockedProvider mocks={[mockProposalEvent]}> <MockedProvider
mocks={[rawProposalNetworkParamsQueryMock, mockProposalEvent]}
>
<VegaWalletContext.Provider <VegaWalletContext.Provider
value={ value={
{ {
@ -74,6 +128,8 @@ describe('Raw proposal form', () => {
it('handles validation', async () => { it('handles validation', async () => {
const mockSendTx = jest.fn().mockReturnValue(Promise.resolve()); const mockSendTx = jest.fn().mockReturnValue(Promise.resolve());
setup(mockSendTx); setup(mockSendTx);
expect(await screen.findByTestId('proposal-submit')).toBeTruthy();
await act(async () => { await act(async () => {
fireEvent.click(screen.getByTestId('proposal-submit')); fireEvent.click(screen.getByTestId('proposal-submit'));
}); });
@ -113,6 +169,10 @@ describe('Raw proposal form', () => {
); );
setup(mockSendTx); setup(mockSendTx);
await act(async () => {
jest.advanceTimersByTime(paramsDelay);
});
const inputJSON = JSON.stringify({ const inputJSON = JSON.stringify({
rationale: { rationale: {
description: 'Update governance.proposal.freeform.minVoterBalance', description: 'Update governance.proposal.freeform.minVoterBalance',
@ -129,6 +189,7 @@ describe('Raw proposal form', () => {
enactmentTimestamp: Math.floor(getTime(addHours(new Date(), 3)) / 1000), enactmentTimestamp: Math.floor(getTime(addHours(new Date(), 3)) / 1000),
}, },
}); });
fireEvent.change(screen.getByTestId('proposal-data'), { fireEvent.change(screen.getByTestId('proposal-data'), {
target: { value: inputJSON }, target: { value: inputJSON },
}); });
@ -170,7 +231,14 @@ describe('Raw proposal form', () => {
); );
setup(mockSendTx); setup(mockSendTx);
await act(async () => {
jest.advanceTimersByTime(paramsDelay);
});
const inputJSON = '{}'; const inputJSON = '{}';
expect(await screen.findByTestId('proposal-data')).toBeTruthy();
fireEvent.change(screen.getByTestId('proposal-data'), { fireEvent.change(screen.getByTestId('proposal-data'), {
target: { value: inputJSON }, target: { value: inputJSON },
}); });

View File

@ -4,23 +4,43 @@ import { useEnvironment } from '@vegaprotocol/environment';
import { Heading } from '../../../../components/heading'; import { Heading } from '../../../../components/heading';
import { VegaWalletContainer } from '../../../../components/vega-wallet-container'; import { VegaWalletContainer } from '../../../../components/vega-wallet-container';
import { import {
AsyncRenderer,
FormGroup, FormGroup,
InputError, InputError,
Link, Link,
TextArea, TextArea,
} from '@vegaprotocol/ui-toolkit'; } from '@vegaprotocol/ui-toolkit';
import { validateJson } from '@vegaprotocol/react-helpers'; import {
NetworkParams,
useNetworkParams,
validateJson,
} from '@vegaprotocol/react-helpers';
import { useProposalSubmit } from '@vegaprotocol/governance'; import { useProposalSubmit } from '@vegaprotocol/governance';
import { import {
ProposalFormSubmit, ProposalFormSubmit,
ProposalFormTransactionDialog, ProposalFormTransactionDialog,
} from '../../components/propose'; } from '../../components/propose';
import { ProposalRawMinRequirements } from './proposal-raw-min-requirements';
export interface RawProposalFormFields { export interface RawProposalFormFields {
rawProposalData: string; rawProposalData: string;
} }
export const ProposeRaw = () => { export const ProposeRaw = () => {
const {
params,
loading: networkParamsLoading,
error: networkParamsError,
} = useNetworkParams([
NetworkParams.governance_proposal_asset_minProposerBalance,
NetworkParams.governance_proposal_updateAsset_minProposerBalance,
NetworkParams.governance_proposal_market_minProposerBalance,
NetworkParams.governance_proposal_updateMarket_minProposerBalance,
NetworkParams.governance_proposal_updateNetParam_minProposerBalance,
NetworkParams.governance_proposal_freeform_minProposerBalance,
NetworkParams.spam_protection_proposal_min_tokens,
]);
const { VEGA_EXPLORER_URL, VEGA_DOCS_URL } = useEnvironment(); const { VEGA_EXPLORER_URL, VEGA_DOCS_URL } = useEnvironment();
const { t } = useTranslation(); const { t } = useTranslation();
const { const {
@ -37,11 +57,33 @@ export const ProposeRaw = () => {
}; };
return ( return (
<> <AsyncRenderer
loading={networkParamsLoading}
error={networkParamsError}
data={params}
>
<Heading title={t('NewRawProposal')} /> <Heading title={t('NewRawProposal')} />
<VegaWalletContainer> <VegaWalletContainer>
{() => ( {() => (
<> <>
<ProposalRawMinRequirements
assetMin={params.governance_proposal_asset_minProposerBalance}
updateAssetMin={
params.governance_proposal_updateAsset_minProposerBalance
}
marketMin={params.governance_proposal_market_minProposerBalance}
updateMarketMin={
params.governance_proposal_updateMarket_minProposerBalance
}
updateNetParamMin={
params.governance_proposal_updateNetParam_minProposerBalance
}
freeformMin={
params.governance_proposal_freeform_minProposerBalance
}
spamProtectionMin={params.spam_protection_proposal_min_tokens}
/>
{VEGA_DOCS_URL && ( {VEGA_DOCS_URL && (
<p className="text-sm" data-testid="proposal-docs-link"> <p className="text-sm" data-testid="proposal-docs-link">
<span className="mr-1">{t('ProposalTermsText')}</span> <span className="mr-1">{t('ProposalTermsText')}</span>
@ -94,6 +136,6 @@ export const ProposeRaw = () => {
</> </>
)} )}
</VegaWalletContainer> </VegaWalletContainer>
</> </AsyncRenderer>
); );
}; };