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:
parent
03e39e8323
commit
1f8469a97a
@ -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"
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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 />
|
||||||
|
@ -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>
|
||||||
|
);
|
||||||
|
};
|
@ -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 },
|
||||||
});
|
});
|
||||||
|
@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user