Feat/1512: equity like share vote (#1848)
* Feat/1512: Proposal type as enum, hoisted proposal type and min voting balance * Feat/1512: Setup and new LP tally for update market proposals * Feat/1512: Added LP data (if update market) to proposal-votes-table.tsx * Feat/1512: Fixing some broken tests and added unit tests for proposal-votes-table * Feat/1512: Tests for use-vote-information hook * Feat/1512: Tests for use-network-params hook * Feat/1512: Fixed some regenerated types * Feat/1512: Addressed comments from PR * Feat/1512: Condensed all useMemos in use-vote-information into a single one * Feat/1512: Small tweak to Thumbs element
This commit is contained in:
parent
ab64cf69be
commit
068381d620
@ -188,7 +188,8 @@
|
|||||||
"errorDetails": "Error details",
|
"errorDetails": "Error details",
|
||||||
"proposedNewValue": "Proposed new value:",
|
"proposedNewValue": "Proposed new value:",
|
||||||
"proposalChange": "Change <code>{{key}}</code> to <code>{{value}}</code>",
|
"proposalChange": "Change <code>{{key}}</code> to <code>{{value}}</code>",
|
||||||
"votes": "Votes",
|
"tokenVotes": "Token votes",
|
||||||
|
"liquidityVotes": "Liquidity votes",
|
||||||
"yourVote": "Your vote",
|
"yourVote": "Your vote",
|
||||||
"for": "For",
|
"for": "For",
|
||||||
"against": "Against",
|
"against": "Against",
|
||||||
@ -201,6 +202,7 @@
|
|||||||
"toVote": "to vote",
|
"toVote": "to vote",
|
||||||
"voteFor": "Vote for",
|
"voteFor": "Vote for",
|
||||||
"voteAgainst": "Vote against",
|
"voteAgainst": "Vote against",
|
||||||
|
"votingThresholdInfo": "If the token vote passes the participation threshold it will be the deciding vote. If not, the outcome will be determined by liquidity providers on this market.",
|
||||||
"noGovernanceTokens": "You need some VEGA tokens to participate in governance",
|
"noGovernanceTokens": "You need some VEGA tokens to participate in governance",
|
||||||
"youVoted": "You voted",
|
"youVoted": "You voted",
|
||||||
"changeVote": "Change vote",
|
"changeVote": "Change vote",
|
||||||
@ -208,6 +210,8 @@
|
|||||||
"votePending": "Casting vote",
|
"votePending": "Casting vote",
|
||||||
"voteError": "Something went wrong, and your vote was not seen by the network",
|
"voteError": "Something went wrong, and your vote was not seen by the network",
|
||||||
"back": "back",
|
"back": "back",
|
||||||
|
"byTokenVote": "by Token vote",
|
||||||
|
"byLiquidityVote": "by Liquidity vote",
|
||||||
"youDidNotVote": "Voting has ended. You did not vote",
|
"youDidNotVote": "Voting has ended. You did not vote",
|
||||||
"voteState_Yes": "For",
|
"voteState_Yes": "For",
|
||||||
"voteState_No": "Against",
|
"voteState_No": "Against",
|
||||||
@ -552,9 +556,12 @@
|
|||||||
"reference": "Reference",
|
"reference": "Reference",
|
||||||
"voteBreakdown": "Vote breakdown",
|
"voteBreakdown": "Vote breakdown",
|
||||||
"willPass": "Will pass",
|
"willPass": "Will pass",
|
||||||
"majorityMet": "Majority met",
|
"majorityMet": "Token majority met",
|
||||||
"participationMet": "Participation met",
|
"majorityLPMet": "Liquidity majority met",
|
||||||
|
"participationMet": "Token participation met",
|
||||||
|
"participationLPMet": "Liquidity participation met",
|
||||||
"tokenForProposal": "Tokens for proposal",
|
"tokenForProposal": "Tokens for proposal",
|
||||||
|
"tokenLPForProposal": "Liquidity shares for proposal",
|
||||||
"tokensAgainstProposal": "Tokens against proposal",
|
"tokensAgainstProposal": "Tokens against proposal",
|
||||||
"participationRequired": "Participation required",
|
"participationRequired": "Participation required",
|
||||||
"numberOfVotingParties": "Number of voting parties",
|
"numberOfVotingParties": "Number of voting parties",
|
||||||
|
@ -64,6 +64,7 @@ fragment ProposalFields on Proposal {
|
|||||||
yes {
|
yes {
|
||||||
totalTokens
|
totalTokens
|
||||||
totalNumber
|
totalNumber
|
||||||
|
totalEquityLikeShareWeight
|
||||||
votes {
|
votes {
|
||||||
value
|
value
|
||||||
party {
|
party {
|
||||||
@ -78,6 +79,7 @@ fragment ProposalFields on Proposal {
|
|||||||
no {
|
no {
|
||||||
totalTokens
|
totalTokens
|
||||||
totalNumber
|
totalNumber
|
||||||
|
totalEquityLikeShareWeight
|
||||||
votes {
|
votes {
|
||||||
value
|
value
|
||||||
party {
|
party {
|
||||||
|
@ -1,345 +0,0 @@
|
|||||||
/* tslint:disable */
|
|
||||||
/* eslint-disable */
|
|
||||||
// @generated
|
|
||||||
// This file was automatically generated and should not be edited.
|
|
||||||
|
|
||||||
import { ProposalState, ProposalRejectionReason, VoteValue } from "@vegaprotocol/types";
|
|
||||||
|
|
||||||
// ====================================================
|
|
||||||
// GraphQL fragment: ProposalFields
|
|
||||||
// ====================================================
|
|
||||||
|
|
||||||
export interface ProposalFields_rationale {
|
|
||||||
__typename: "ProposalRationale";
|
|
||||||
/**
|
|
||||||
* Title to be used to give a short description of the proposal in lists.
|
|
||||||
* This is to be between 0 and 100 unicode characters.
|
|
||||||
* This is mandatory for all proposals.
|
|
||||||
*/
|
|
||||||
title: string;
|
|
||||||
/**
|
|
||||||
* Description to show a short title / something in case the link goes offline.
|
|
||||||
* This is to be between 0 and 20k unicode characters.
|
|
||||||
* This is mandatory for all proposals.
|
|
||||||
*/
|
|
||||||
description: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ProposalFields_party {
|
|
||||||
__typename: "Party";
|
|
||||||
/**
|
|
||||||
* Party identifier
|
|
||||||
*/
|
|
||||||
id: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ProposalFields_terms_change_NewFreeform {
|
|
||||||
__typename: "NewFreeform";
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ProposalFields_terms_change_NewMarket_instrument_futureProduct_settlementAsset {
|
|
||||||
__typename: "Asset";
|
|
||||||
/**
|
|
||||||
* The symbol of the asset (e.g: GBP)
|
|
||||||
*/
|
|
||||||
symbol: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ProposalFields_terms_change_NewMarket_instrument_futureProduct {
|
|
||||||
__typename: "FutureProduct";
|
|
||||||
/**
|
|
||||||
* Product asset
|
|
||||||
*/
|
|
||||||
settlementAsset: ProposalFields_terms_change_NewMarket_instrument_futureProduct_settlementAsset;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ProposalFields_terms_change_NewMarket_instrument {
|
|
||||||
__typename: "InstrumentConfiguration";
|
|
||||||
/**
|
|
||||||
* Full and fairly descriptive name for the instrument
|
|
||||||
*/
|
|
||||||
name: string;
|
|
||||||
/**
|
|
||||||
* A short non necessarily unique code used to easily describe the instrument (e.g: FX:BTCUSD/DEC18)
|
|
||||||
*/
|
|
||||||
code: string;
|
|
||||||
/**
|
|
||||||
* Future product specification
|
|
||||||
*/
|
|
||||||
futureProduct: ProposalFields_terms_change_NewMarket_instrument_futureProduct | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ProposalFields_terms_change_NewMarket {
|
|
||||||
__typename: "NewMarket";
|
|
||||||
/**
|
|
||||||
* New market instrument configuration
|
|
||||||
*/
|
|
||||||
instrument: ProposalFields_terms_change_NewMarket_instrument;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ProposalFields_terms_change_UpdateMarket {
|
|
||||||
__typename: "UpdateMarket";
|
|
||||||
marketId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ProposalFields_terms_change_NewAsset_source_BuiltinAsset {
|
|
||||||
__typename: "BuiltinAsset";
|
|
||||||
/**
|
|
||||||
* Maximum amount that can be requested by a party through the built-in asset faucet at a time
|
|
||||||
*/
|
|
||||||
maxFaucetAmountMint: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ProposalFields_terms_change_NewAsset_source_ERC20 {
|
|
||||||
__typename: "ERC20";
|
|
||||||
/**
|
|
||||||
* The address of the ERC20 contract
|
|
||||||
*/
|
|
||||||
contractAddress: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ProposalFields_terms_change_NewAsset_source = ProposalFields_terms_change_NewAsset_source_BuiltinAsset | ProposalFields_terms_change_NewAsset_source_ERC20;
|
|
||||||
|
|
||||||
export interface ProposalFields_terms_change_NewAsset {
|
|
||||||
__typename: "NewAsset";
|
|
||||||
/**
|
|
||||||
* The full name of the asset (e.g: Great British Pound)
|
|
||||||
*/
|
|
||||||
name: string;
|
|
||||||
/**
|
|
||||||
* The symbol of the asset (e.g: GBP)
|
|
||||||
*/
|
|
||||||
symbol: string;
|
|
||||||
/**
|
|
||||||
* The source of the new asset
|
|
||||||
*/
|
|
||||||
source: ProposalFields_terms_change_NewAsset_source;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ProposalFields_terms_change_UpdateNetworkParameter_networkParameter {
|
|
||||||
__typename: "NetworkParameter";
|
|
||||||
/**
|
|
||||||
* The name of the network parameter
|
|
||||||
*/
|
|
||||||
key: string;
|
|
||||||
/**
|
|
||||||
* The value of the network parameter
|
|
||||||
*/
|
|
||||||
value: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ProposalFields_terms_change_UpdateNetworkParameter {
|
|
||||||
__typename: "UpdateNetworkParameter";
|
|
||||||
networkParameter: ProposalFields_terms_change_UpdateNetworkParameter_networkParameter;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ProposalFields_terms_change_UpdateAsset_source {
|
|
||||||
__typename: "UpdateERC20";
|
|
||||||
/**
|
|
||||||
* The lifetime limits deposit per address
|
|
||||||
* Note: this is a temporary measure for alpha mainnet
|
|
||||||
*/
|
|
||||||
lifetimeLimit: string;
|
|
||||||
/**
|
|
||||||
* The maximum allowed per withdrawal
|
|
||||||
* Note: this is a temporary measure for alpha mainnet
|
|
||||||
*/
|
|
||||||
withdrawThreshold: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ProposalFields_terms_change_UpdateAsset {
|
|
||||||
__typename: "UpdateAsset";
|
|
||||||
/**
|
|
||||||
* The minimum economically meaningful amount of this specific asset
|
|
||||||
*/
|
|
||||||
quantum: string;
|
|
||||||
/**
|
|
||||||
* The asset to update
|
|
||||||
*/
|
|
||||||
assetId: string;
|
|
||||||
/**
|
|
||||||
* The source of the updated asset
|
|
||||||
*/
|
|
||||||
source: ProposalFields_terms_change_UpdateAsset_source;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ProposalFields_terms_change = ProposalFields_terms_change_NewFreeform | ProposalFields_terms_change_NewMarket | ProposalFields_terms_change_UpdateMarket | ProposalFields_terms_change_NewAsset | ProposalFields_terms_change_UpdateNetworkParameter | ProposalFields_terms_change_UpdateAsset;
|
|
||||||
|
|
||||||
export interface ProposalFields_terms {
|
|
||||||
__typename: "ProposalTerms";
|
|
||||||
/**
|
|
||||||
* RFC3339Nano time and date when voting closes for this proposal.
|
|
||||||
* Constrained by "minClose" and "maxClose" network parameters.
|
|
||||||
*/
|
|
||||||
closingDatetime: string;
|
|
||||||
/**
|
|
||||||
* RFC3339Nano time and date when this proposal is executed (if passed). Note that it has to be after closing date time.
|
|
||||||
* Constrained by "minEnactInSeconds" and "maxEnactInSeconds" network parameters.
|
|
||||||
* Note: Optional as free form proposals do not require it.
|
|
||||||
*/
|
|
||||||
enactmentDatetime: string | null;
|
|
||||||
/**
|
|
||||||
* Actual change being introduced by the proposal - action the proposal triggers if passed and enacted.
|
|
||||||
*/
|
|
||||||
change: ProposalFields_terms_change;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ProposalFields_votes_yes_votes_party_stakingSummary {
|
|
||||||
__typename: "StakingSummary";
|
|
||||||
/**
|
|
||||||
* The stake currently available for the party
|
|
||||||
*/
|
|
||||||
currentStakeAvailable: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ProposalFields_votes_yes_votes_party {
|
|
||||||
__typename: "Party";
|
|
||||||
/**
|
|
||||||
* Party identifier
|
|
||||||
*/
|
|
||||||
id: string;
|
|
||||||
/**
|
|
||||||
* The staking information for this Party
|
|
||||||
*/
|
|
||||||
stakingSummary: ProposalFields_votes_yes_votes_party_stakingSummary;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ProposalFields_votes_yes_votes {
|
|
||||||
__typename: "Vote";
|
|
||||||
/**
|
|
||||||
* The vote value cast
|
|
||||||
*/
|
|
||||||
value: VoteValue;
|
|
||||||
/**
|
|
||||||
* The party casting the vote
|
|
||||||
*/
|
|
||||||
party: ProposalFields_votes_yes_votes_party;
|
|
||||||
/**
|
|
||||||
* RFC3339Nano time and date when the vote reached Vega network
|
|
||||||
*/
|
|
||||||
datetime: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ProposalFields_votes_yes {
|
|
||||||
__typename: "ProposalVoteSide";
|
|
||||||
/**
|
|
||||||
* Total number of governance tokens from the votes cast for this side
|
|
||||||
*/
|
|
||||||
totalTokens: string;
|
|
||||||
/**
|
|
||||||
* Total number of votes cast for this side
|
|
||||||
*/
|
|
||||||
totalNumber: string;
|
|
||||||
/**
|
|
||||||
* All votes cast for this side
|
|
||||||
*/
|
|
||||||
votes: ProposalFields_votes_yes_votes[] | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ProposalFields_votes_no_votes_party_stakingSummary {
|
|
||||||
__typename: "StakingSummary";
|
|
||||||
/**
|
|
||||||
* The stake currently available for the party
|
|
||||||
*/
|
|
||||||
currentStakeAvailable: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ProposalFields_votes_no_votes_party {
|
|
||||||
__typename: "Party";
|
|
||||||
/**
|
|
||||||
* Party identifier
|
|
||||||
*/
|
|
||||||
id: string;
|
|
||||||
/**
|
|
||||||
* The staking information for this Party
|
|
||||||
*/
|
|
||||||
stakingSummary: ProposalFields_votes_no_votes_party_stakingSummary;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ProposalFields_votes_no_votes {
|
|
||||||
__typename: "Vote";
|
|
||||||
/**
|
|
||||||
* The vote value cast
|
|
||||||
*/
|
|
||||||
value: VoteValue;
|
|
||||||
/**
|
|
||||||
* The party casting the vote
|
|
||||||
*/
|
|
||||||
party: ProposalFields_votes_no_votes_party;
|
|
||||||
/**
|
|
||||||
* RFC3339Nano time and date when the vote reached Vega network
|
|
||||||
*/
|
|
||||||
datetime: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ProposalFields_votes_no {
|
|
||||||
__typename: "ProposalVoteSide";
|
|
||||||
/**
|
|
||||||
* Total number of governance tokens from the votes cast for this side
|
|
||||||
*/
|
|
||||||
totalTokens: string;
|
|
||||||
/**
|
|
||||||
* Total number of votes cast for this side
|
|
||||||
*/
|
|
||||||
totalNumber: string;
|
|
||||||
/**
|
|
||||||
* All votes cast for this side
|
|
||||||
*/
|
|
||||||
votes: ProposalFields_votes_no_votes[] | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ProposalFields_votes {
|
|
||||||
__typename: "ProposalVotes";
|
|
||||||
/**
|
|
||||||
* Yes votes cast for this proposal
|
|
||||||
*/
|
|
||||||
yes: ProposalFields_votes_yes;
|
|
||||||
/**
|
|
||||||
* No votes cast for this proposal
|
|
||||||
*/
|
|
||||||
no: ProposalFields_votes_no;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ProposalFields {
|
|
||||||
__typename: "Proposal";
|
|
||||||
/**
|
|
||||||
* Proposal ID that is filled by Vega once proposal reaches the network
|
|
||||||
*/
|
|
||||||
id: string | null;
|
|
||||||
/**
|
|
||||||
* Rationale behind the proposal
|
|
||||||
*/
|
|
||||||
rationale: ProposalFields_rationale;
|
|
||||||
/**
|
|
||||||
* A UUID reference to aid tracking proposals on Vega
|
|
||||||
*/
|
|
||||||
reference: string;
|
|
||||||
/**
|
|
||||||
* State of the proposal
|
|
||||||
*/
|
|
||||||
state: ProposalState;
|
|
||||||
/**
|
|
||||||
* RFC3339Nano time and date when the proposal reached Vega network
|
|
||||||
*/
|
|
||||||
datetime: string;
|
|
||||||
/**
|
|
||||||
* Why the proposal was rejected by the core
|
|
||||||
*/
|
|
||||||
rejectionReason: ProposalRejectionReason | null;
|
|
||||||
/**
|
|
||||||
* Party that prepared the proposal
|
|
||||||
*/
|
|
||||||
party: ProposalFields_party;
|
|
||||||
/**
|
|
||||||
* Error details of the rejectionReason
|
|
||||||
*/
|
|
||||||
errorDetails: string | null;
|
|
||||||
/**
|
|
||||||
* Terms of the proposal
|
|
||||||
*/
|
|
||||||
terms: ProposalFields_terms;
|
|
||||||
/**
|
|
||||||
* Votes cast for this proposal
|
|
||||||
*/
|
|
||||||
votes: ProposalFields_votes;
|
|
||||||
}
|
|
@ -3,19 +3,19 @@ import { Schema as Types } from '@vegaprotocol/types';
|
|||||||
import { gql } from '@apollo/client';
|
import { gql } from '@apollo/client';
|
||||||
import * as Apollo from '@apollo/client';
|
import * as Apollo from '@apollo/client';
|
||||||
const defaultOptions = {} as const;
|
const defaultOptions = {} as const;
|
||||||
export type ProposalFieldsFragment = { __typename?: 'Proposal', id?: string | null, reference: string, state: Types.ProposalState, datetime: string, rejectionReason?: Types.ProposalRejectionReason | null, errorDetails?: string | null, party: { __typename?: 'Party', id: string }, terms: { __typename?: 'ProposalTerms', closingDatetime: string, enactmentDatetime?: string | null, change: { __typename: 'NewAsset', name: string, symbol: string, source: { __typename: 'BuiltinAsset', maxFaucetAmountMint: string } | { __typename: 'ERC20', contractAddress: string } } | { __typename?: 'NewFreeform' } | { __typename?: 'NewMarket', decimalPlaces: number, metadata?: Array<string> | null, instrument: { __typename?: 'InstrumentConfiguration', name: string, code: string, futureProduct?: { __typename?: 'FutureProduct', settlementAsset: { __typename?: 'Asset', symbol: string } } | null } } | { __typename?: 'UpdateAsset', quantum: string, source: { __typename?: 'UpdateERC20', lifetimeLimit: string, withdrawThreshold: string } } | { __typename?: 'UpdateMarket', marketId: string } | { __typename?: 'UpdateNetworkParameter', networkParameter: { __typename?: 'NetworkParameter', key: string, value: string } } }, votes: { __typename?: 'ProposalVotes', yes: { __typename?: 'ProposalVoteSide', totalTokens: string, totalNumber: string, votes?: Array<{ __typename?: 'Vote', value: Types.VoteValue, datetime: string, party: { __typename?: 'Party', id: string, stake: { __typename?: 'PartyStake', currentStakeAvailable: string } } }> | null }, no: { __typename?: 'ProposalVoteSide', totalTokens: string, totalNumber: string, votes?: Array<{ __typename?: 'Vote', value: Types.VoteValue, datetime: string, party: { __typename?: 'Party', id: string, stake: { __typename?: 'PartyStake', currentStakeAvailable: string } } }> | null } } };
|
export type ProposalFieldsFragment = { __typename?: 'Proposal', id?: string | null, reference: string, state: Types.ProposalState, datetime: string, rejectionReason?: Types.ProposalRejectionReason | null, errorDetails?: string | null, party: { __typename?: 'Party', id: string }, terms: { __typename?: 'ProposalTerms', closingDatetime: string, enactmentDatetime?: string | null, change: { __typename: 'NewAsset', name: string, symbol: string, source: { __typename: 'BuiltinAsset', maxFaucetAmountMint: string } | { __typename: 'ERC20', contractAddress: string } } | { __typename?: 'NewFreeform' } | { __typename?: 'NewMarket', decimalPlaces: number, metadata?: Array<string> | null, instrument: { __typename?: 'InstrumentConfiguration', name: string, code: string, futureProduct?: { __typename?: 'FutureProduct', settlementAsset: { __typename?: 'Asset', symbol: string } } | null } } | { __typename?: 'UpdateAsset', quantum: string, source: { __typename?: 'UpdateERC20', lifetimeLimit: string, withdrawThreshold: string } } | { __typename?: 'UpdateMarket', marketId: string } | { __typename?: 'UpdateNetworkParameter', networkParameter: { __typename?: 'NetworkParameter', key: string, value: string } } }, votes: { __typename?: 'ProposalVotes', yes: { __typename?: 'ProposalVoteSide', totalTokens: string, totalNumber: string, totalEquityLikeShareWeight: string, votes?: Array<{ __typename?: 'Vote', value: Types.VoteValue, datetime: string, party: { __typename?: 'Party', id: string, stake: { __typename?: 'PartyStake', currentStakeAvailable: string } } }> | null }, no: { __typename?: 'ProposalVoteSide', totalTokens: string, totalNumber: string, totalEquityLikeShareWeight: string, votes?: Array<{ __typename?: 'Vote', value: Types.VoteValue, datetime: string, party: { __typename?: 'Party', id: string, stake: { __typename?: 'PartyStake', currentStakeAvailable: string } } }> | null } } };
|
||||||
|
|
||||||
export type ProposalQueryVariables = Types.Exact<{
|
export type ProposalQueryVariables = Types.Exact<{
|
||||||
proposalId: Types.Scalars['ID'];
|
proposalId: Types.Scalars['ID'];
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type ProposalQuery = { __typename?: 'Query', proposal?: { __typename?: 'Proposal', id?: string | null, reference: string, state: Types.ProposalState, datetime: string, rejectionReason?: Types.ProposalRejectionReason | null, errorDetails?: string | null, party: { __typename?: 'Party', id: string }, terms: { __typename?: 'ProposalTerms', closingDatetime: string, enactmentDatetime?: string | null, change: { __typename: 'NewAsset', name: string, symbol: string, source: { __typename: 'BuiltinAsset', maxFaucetAmountMint: string } | { __typename: 'ERC20', contractAddress: string } } | { __typename?: 'NewFreeform' } | { __typename?: 'NewMarket', decimalPlaces: number, metadata?: Array<string> | null, instrument: { __typename?: 'InstrumentConfiguration', name: string, code: string, futureProduct?: { __typename?: 'FutureProduct', settlementAsset: { __typename?: 'Asset', symbol: string } } | null } } | { __typename?: 'UpdateAsset', quantum: string, source: { __typename?: 'UpdateERC20', lifetimeLimit: string, withdrawThreshold: string } } | { __typename?: 'UpdateMarket', marketId: string } | { __typename?: 'UpdateNetworkParameter', networkParameter: { __typename?: 'NetworkParameter', key: string, value: string } } }, votes: { __typename?: 'ProposalVotes', yes: { __typename?: 'ProposalVoteSide', totalTokens: string, totalNumber: string, votes?: Array<{ __typename?: 'Vote', value: Types.VoteValue, datetime: string, party: { __typename?: 'Party', id: string, stake: { __typename?: 'PartyStake', currentStakeAvailable: string } } }> | null }, no: { __typename?: 'ProposalVoteSide', totalTokens: string, totalNumber: string, votes?: Array<{ __typename?: 'Vote', value: Types.VoteValue, datetime: string, party: { __typename?: 'Party', id: string, stake: { __typename?: 'PartyStake', currentStakeAvailable: string } } }> | null } } } | null };
|
export type ProposalQuery = { __typename?: 'Query', proposal?: { __typename?: 'Proposal', id?: string | null, reference: string, state: Types.ProposalState, datetime: string, rejectionReason?: Types.ProposalRejectionReason | null, errorDetails?: string | null, party: { __typename?: 'Party', id: string }, terms: { __typename?: 'ProposalTerms', closingDatetime: string, enactmentDatetime?: string | null, change: { __typename: 'NewAsset', name: string, symbol: string, source: { __typename: 'BuiltinAsset', maxFaucetAmountMint: string } | { __typename: 'ERC20', contractAddress: string } } | { __typename?: 'NewFreeform' } | { __typename?: 'NewMarket', decimalPlaces: number, metadata?: Array<string> | null, instrument: { __typename?: 'InstrumentConfiguration', name: string, code: string, futureProduct?: { __typename?: 'FutureProduct', settlementAsset: { __typename?: 'Asset', symbol: string } } | null } } | { __typename?: 'UpdateAsset', quantum: string, source: { __typename?: 'UpdateERC20', lifetimeLimit: string, withdrawThreshold: string } } | { __typename?: 'UpdateMarket', marketId: string } | { __typename?: 'UpdateNetworkParameter', networkParameter: { __typename?: 'NetworkParameter', key: string, value: string } } }, votes: { __typename?: 'ProposalVotes', yes: { __typename?: 'ProposalVoteSide', totalTokens: string, totalNumber: string, totalEquityLikeShareWeight: string, votes?: Array<{ __typename?: 'Vote', value: Types.VoteValue, datetime: string, party: { __typename?: 'Party', id: string, stake: { __typename?: 'PartyStake', currentStakeAvailable: string } } }> | null }, no: { __typename?: 'ProposalVoteSide', totalTokens: string, totalNumber: string, totalEquityLikeShareWeight: string, votes?: Array<{ __typename?: 'Vote', value: Types.VoteValue, datetime: string, party: { __typename?: 'Party', id: string, stake: { __typename?: 'PartyStake', currentStakeAvailable: string } } }> | null } } } | null };
|
||||||
|
|
||||||
export type ProposalsQueryVariables = Types.Exact<{ [key: string]: never; }>;
|
export type ProposalsQueryVariables = Types.Exact<{ [key: string]: never; }>;
|
||||||
|
|
||||||
|
|
||||||
export type ProposalsQuery = { __typename?: 'Query', proposals?: Array<{ __typename?: 'Proposal', id?: string | null, reference: string, state: Types.ProposalState, datetime: string, rejectionReason?: Types.ProposalRejectionReason | null, errorDetails?: string | null, party: { __typename?: 'Party', id: string }, terms: { __typename?: 'ProposalTerms', closingDatetime: string, enactmentDatetime?: string | null, change: { __typename: 'NewAsset', name: string, symbol: string, source: { __typename: 'BuiltinAsset', maxFaucetAmountMint: string } | { __typename: 'ERC20', contractAddress: string } } | { __typename?: 'NewFreeform' } | { __typename?: 'NewMarket', decimalPlaces: number, metadata?: Array<string> | null, instrument: { __typename?: 'InstrumentConfiguration', name: string, code: string, futureProduct?: { __typename?: 'FutureProduct', settlementAsset: { __typename?: 'Asset', symbol: string } } | null } } | { __typename?: 'UpdateAsset', quantum: string, source: { __typename?: 'UpdateERC20', lifetimeLimit: string, withdrawThreshold: string } } | { __typename?: 'UpdateMarket', marketId: string } | { __typename?: 'UpdateNetworkParameter', networkParameter: { __typename?: 'NetworkParameter', key: string, value: string } } }, votes: { __typename?: 'ProposalVotes', yes: { __typename?: 'ProposalVoteSide', totalTokens: string, totalNumber: string, votes?: Array<{ __typename?: 'Vote', value: Types.VoteValue, datetime: string, party: { __typename?: 'Party', id: string, stake: { __typename?: 'PartyStake', currentStakeAvailable: string } } }> | null }, no: { __typename?: 'ProposalVoteSide', totalTokens: string, totalNumber: string, votes?: Array<{ __typename?: 'Vote', value: Types.VoteValue, datetime: string, party: { __typename?: 'Party', id: string, stake: { __typename?: 'PartyStake', currentStakeAvailable: string } } }> | null } } }> | null };
|
export type ProposalsQuery = { __typename?: 'Query', proposals?: Array<{ __typename?: 'Proposal', id?: string | null, reference: string, state: Types.ProposalState, datetime: string, rejectionReason?: Types.ProposalRejectionReason | null, errorDetails?: string | null, party: { __typename?: 'Party', id: string }, terms: { __typename?: 'ProposalTerms', closingDatetime: string, enactmentDatetime?: string | null, change: { __typename: 'NewAsset', name: string, symbol: string, source: { __typename: 'BuiltinAsset', maxFaucetAmountMint: string } | { __typename: 'ERC20', contractAddress: string } } | { __typename?: 'NewFreeform' } | { __typename?: 'NewMarket', decimalPlaces: number, metadata?: Array<string> | null, instrument: { __typename?: 'InstrumentConfiguration', name: string, code: string, futureProduct?: { __typename?: 'FutureProduct', settlementAsset: { __typename?: 'Asset', symbol: string } } | null } } | { __typename?: 'UpdateAsset', quantum: string, source: { __typename?: 'UpdateERC20', lifetimeLimit: string, withdrawThreshold: string } } | { __typename?: 'UpdateMarket', marketId: string } | { __typename?: 'UpdateNetworkParameter', networkParameter: { __typename?: 'NetworkParameter', key: string, value: string } } }, votes: { __typename?: 'ProposalVotes', yes: { __typename?: 'ProposalVoteSide', totalTokens: string, totalNumber: string, totalEquityLikeShareWeight: string, votes?: Array<{ __typename?: 'Vote', value: Types.VoteValue, datetime: string, party: { __typename?: 'Party', id: string, stake: { __typename?: 'PartyStake', currentStakeAvailable: string } } }> | null }, no: { __typename?: 'ProposalVoteSide', totalTokens: string, totalNumber: string, totalEquityLikeShareWeight: string, votes?: Array<{ __typename?: 'Vote', value: Types.VoteValue, datetime: string, party: { __typename?: 'Party', id: string, stake: { __typename?: 'PartyStake', currentStakeAvailable: string } } }> | null } } }> | null };
|
||||||
|
|
||||||
export const ProposalFieldsFragmentDoc = gql`
|
export const ProposalFieldsFragmentDoc = gql`
|
||||||
fragment ProposalFields on Proposal {
|
fragment ProposalFields on Proposal {
|
||||||
@ -84,6 +84,7 @@ export const ProposalFieldsFragmentDoc = gql`
|
|||||||
yes {
|
yes {
|
||||||
totalTokens
|
totalTokens
|
||||||
totalNumber
|
totalNumber
|
||||||
|
totalEquityLikeShareWeight
|
||||||
votes {
|
votes {
|
||||||
value
|
value
|
||||||
party {
|
party {
|
||||||
@ -98,6 +99,7 @@ export const ProposalFieldsFragmentDoc = gql`
|
|||||||
no {
|
no {
|
||||||
totalTokens
|
totalTokens
|
||||||
totalNumber
|
totalNumber
|
||||||
|
totalEquityLikeShareWeight
|
||||||
votes {
|
votes {
|
||||||
value
|
value
|
||||||
party {
|
party {
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { ProposalState } from '@vegaprotocol/types';
|
import { ProposalState } from '@vegaprotocol/types';
|
||||||
import type { ProposalFields } from '../../__generated__/ProposalFields';
|
import type { Proposal_proposal } from '../../proposal/__generated__/Proposal';
|
||||||
|
|
||||||
export const CurrentProposalState = ({
|
export const CurrentProposalState = ({
|
||||||
proposal,
|
proposal,
|
||||||
}: {
|
}: {
|
||||||
proposal: ProposalFields;
|
proposal: Proposal_proposal;
|
||||||
}) => {
|
}) => {
|
||||||
const { state } = proposal;
|
const { state } = proposal;
|
||||||
let className = 'text-white';
|
let className = 'text-white';
|
||||||
|
@ -6,8 +6,8 @@ import { ProposalRejectionReason, ProposalState } from '@vegaprotocol/types';
|
|||||||
import type { NetworkParamsQuery } from '@vegaprotocol/web3';
|
import type { NetworkParamsQuery } from '@vegaprotocol/web3';
|
||||||
import { AppStateProvider } from '../../../../contexts/app-state/app-state-provider';
|
import { AppStateProvider } from '../../../../contexts/app-state/app-state-provider';
|
||||||
import { generateProposal } from '../../test-helpers/generate-proposals';
|
import { generateProposal } from '../../test-helpers/generate-proposals';
|
||||||
import type { ProposalFields } from '../../__generated__/ProposalFields';
|
|
||||||
import { CurrentProposalStatus } from './current-proposal-status';
|
import { CurrentProposalStatus } from './current-proposal-status';
|
||||||
|
import type { Proposal_proposal } from '../../proposal/__generated__/Proposal';
|
||||||
|
|
||||||
const networkParamsQueryMock: MockedResponse<NetworkParamsQuery> = {
|
const networkParamsQueryMock: MockedResponse<NetworkParamsQuery> = {
|
||||||
request: {
|
request: {
|
||||||
@ -31,7 +31,7 @@ const networkParamsQueryMock: MockedResponse<NetworkParamsQuery> = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderComponent = ({ proposal }: { proposal: ProposalFields }) => {
|
const renderComponent = ({ proposal }: { proposal: Proposal_proposal }) => {
|
||||||
render(
|
render(
|
||||||
<AppStateProvider>
|
<AppStateProvider>
|
||||||
<MockedProvider mocks={[networkParamsQueryMock]}>
|
<MockedProvider mocks={[networkParamsQueryMock]}>
|
||||||
@ -52,7 +52,7 @@ afterEach(() => {
|
|||||||
|
|
||||||
it('Proposal open - renders will fail state if the proposal will fail', async () => {
|
it('Proposal open - renders will fail state if the proposal will fail', async () => {
|
||||||
const proposal = generateProposal();
|
const proposal = generateProposal();
|
||||||
const failedProposal: ProposalFields = {
|
const failedProposal: Proposal_proposal = {
|
||||||
...proposal,
|
...proposal,
|
||||||
votes: {
|
votes: {
|
||||||
__typename: 'ProposalVotes',
|
__typename: 'ProposalVotes',
|
||||||
@ -61,12 +61,14 @@ it('Proposal open - renders will fail state if the proposal will fail', async ()
|
|||||||
totalNumber: '0',
|
totalNumber: '0',
|
||||||
totalTokens: '0',
|
totalTokens: '0',
|
||||||
votes: null,
|
votes: null,
|
||||||
|
totalEquityLikeShareWeight: '0',
|
||||||
},
|
},
|
||||||
no: {
|
no: {
|
||||||
__typename: 'ProposalVoteSide',
|
__typename: 'ProposalVoteSide',
|
||||||
totalNumber: '0',
|
totalNumber: '0',
|
||||||
totalTokens: '0',
|
totalTokens: '0',
|
||||||
votes: null,
|
votes: null,
|
||||||
|
totalEquityLikeShareWeight: '0',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -119,7 +121,7 @@ it('Proposal passed - renders vote passed and time since vote closed', async ()
|
|||||||
|
|
||||||
it('Proposal waiting for node vote - will pass - renders if the vote will pass and status', async () => {
|
it('Proposal waiting for node vote - will pass - renders if the vote will pass and status', async () => {
|
||||||
const proposal = generateProposal();
|
const proposal = generateProposal();
|
||||||
const failedProposal: ProposalFields = {
|
const failedProposal: Proposal_proposal = {
|
||||||
...proposal,
|
...proposal,
|
||||||
state: ProposalState.STATE_WAITING_FOR_NODE_VOTE,
|
state: ProposalState.STATE_WAITING_FOR_NODE_VOTE,
|
||||||
votes: {
|
votes: {
|
||||||
@ -129,12 +131,14 @@ it('Proposal waiting for node vote - will pass - renders if the vote will pass
|
|||||||
totalNumber: '0',
|
totalNumber: '0',
|
||||||
totalTokens: '0',
|
totalTokens: '0',
|
||||||
votes: null,
|
votes: null,
|
||||||
|
totalEquityLikeShareWeight: '0',
|
||||||
},
|
},
|
||||||
no: {
|
no: {
|
||||||
__typename: 'ProposalVoteSide',
|
__typename: 'ProposalVoteSide',
|
||||||
totalNumber: '0',
|
totalNumber: '0',
|
||||||
totalTokens: '0',
|
totalTokens: '0',
|
||||||
votes: null,
|
votes: null,
|
||||||
|
totalEquityLikeShareWeight: '0',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -245,12 +249,14 @@ it('Proposal failed - renders participation not met if participation is not met'
|
|||||||
totalNumber: '0',
|
totalNumber: '0',
|
||||||
totalTokens: '0',
|
totalTokens: '0',
|
||||||
votes: null,
|
votes: null,
|
||||||
|
totalEquityLikeShareWeight: '0',
|
||||||
},
|
},
|
||||||
no: {
|
no: {
|
||||||
__typename: 'ProposalVoteSide',
|
__typename: 'ProposalVoteSide',
|
||||||
totalNumber: '0',
|
totalNumber: '0',
|
||||||
totalTokens: '0',
|
totalTokens: '0',
|
||||||
votes: null,
|
votes: null,
|
||||||
|
totalEquityLikeShareWeight: '0',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -280,12 +286,14 @@ it('Proposal failed - renders majority not met if majority is not met', async ()
|
|||||||
totalNumber: '0',
|
totalNumber: '0',
|
||||||
totalTokens: '0',
|
totalTokens: '0',
|
||||||
votes: null,
|
votes: null,
|
||||||
|
totalEquityLikeShareWeight: '0',
|
||||||
},
|
},
|
||||||
no: {
|
no: {
|
||||||
__typename: 'ProposalVoteSide',
|
__typename: 'ProposalVoteSide',
|
||||||
totalNumber: '1',
|
totalNumber: '1',
|
||||||
totalTokens: '25242474195500835440000',
|
totalTokens: '25242474195500835440000',
|
||||||
votes: null,
|
votes: null,
|
||||||
|
totalEquityLikeShareWeight: '0',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -4,7 +4,7 @@ import { useTranslation } from 'react-i18next';
|
|||||||
|
|
||||||
import { ProposalState } from '@vegaprotocol/types';
|
import { ProposalState } from '@vegaprotocol/types';
|
||||||
import { useVoteInformation } from '../../hooks';
|
import { useVoteInformation } from '../../hooks';
|
||||||
import type { ProposalFields } from '../../__generated__/ProposalFields';
|
import type { Proposal_proposal } from '../../proposal/__generated__/Proposal';
|
||||||
|
|
||||||
export const StatusPass = ({ children }: { children: ReactNode }) => (
|
export const StatusPass = ({ children }: { children: ReactNode }) => (
|
||||||
<span className="text-vega-green">{children}</span>
|
<span className="text-vega-green">{children}</span>
|
||||||
@ -42,11 +42,12 @@ const WillPass = ({
|
|||||||
export const CurrentProposalStatus = ({
|
export const CurrentProposalStatus = ({
|
||||||
proposal,
|
proposal,
|
||||||
}: {
|
}: {
|
||||||
proposal: ProposalFields;
|
proposal: Proposal_proposal;
|
||||||
}) => {
|
}) => {
|
||||||
const { willPass, majorityMet, participationMet } = useVoteInformation({
|
const { willPassByTokenVote, majorityMet, participationMet } =
|
||||||
proposal,
|
useVoteInformation({
|
||||||
});
|
proposal,
|
||||||
|
});
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const daysClosedAgo = formatDistanceToNow(
|
const daysClosedAgo = formatDistanceToNow(
|
||||||
@ -61,7 +62,9 @@ export const CurrentProposalStatus = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (proposal.state === ProposalState.STATE_OPEN) {
|
if (proposal.state === ProposalState.STATE_OPEN) {
|
||||||
return <WillPass willPass={willPass}>{t('currentlySetTo')}</WillPass>;
|
return (
|
||||||
|
<WillPass willPass={willPassByTokenVote}>{t('currentlySetTo')}</WillPass>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@ -108,7 +111,12 @@ export const CurrentProposalStatus = ({
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<span>{t('votePassed')}</span>
|
<span>{t('votePassed')}</span>
|
||||||
<StatusPass> {proposal.state}</StatusPass>
|
<StatusPass>
|
||||||
|
|
||||||
|
{proposal.state === ProposalState.STATE_ENACTED
|
||||||
|
? t('Enacted')
|
||||||
|
: t('Passed')}
|
||||||
|
</StatusPass>
|
||||||
<span>
|
<span>
|
||||||
|
|
||||||
{proposal.state === ProposalState.STATE_ENACTED
|
{proposal.state === ProposalState.STATE_ENACTED
|
||||||
@ -121,7 +129,7 @@ export const CurrentProposalStatus = ({
|
|||||||
|
|
||||||
if (proposal.state === ProposalState.STATE_WAITING_FOR_NODE_VOTE) {
|
if (proposal.state === ProposalState.STATE_WAITING_FOR_NODE_VOTE) {
|
||||||
return (
|
return (
|
||||||
<WillPass willPass={willPass}>
|
<WillPass willPass={willPassByTokenVote}>
|
||||||
<span>{t('WaitingForNodeVote')}</span>{' '}
|
<span>{t('WaitingForNodeVote')}</span>{' '}
|
||||||
<span>{t('currentlySetTo')}</span>
|
<span>{t('currentlySetTo')}</span>
|
||||||
</WillPass>
|
</WillPass>
|
||||||
|
@ -4,10 +4,10 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import { KeyValueTable, KeyValueTableRow } from '@vegaprotocol/ui-toolkit';
|
import { KeyValueTable, KeyValueTableRow } from '@vegaprotocol/ui-toolkit';
|
||||||
import { DATE_FORMAT_DETAILED } from '../../../../lib/date-formats';
|
import { DATE_FORMAT_DETAILED } from '../../../../lib/date-formats';
|
||||||
import { CurrentProposalState } from '../current-proposal-state';
|
import { CurrentProposalState } from '../current-proposal-state';
|
||||||
import type { ProposalFields } from '../../__generated__/ProposalFields';
|
import type { Proposal_proposal } from '../../proposal/__generated__/Proposal';
|
||||||
|
|
||||||
interface ProposalChangeTableProps {
|
interface ProposalChangeTableProps {
|
||||||
proposal: ProposalFields;
|
proposal: Proposal_proposal;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ProposalChangeTable = ({ proposal }: ProposalChangeTableProps) => {
|
export const ProposalChangeTable = ({ proposal }: ProposalChangeTableProps) => {
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { render, screen } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react';
|
||||||
import { generateProposal } from '../../test-helpers/generate-proposals';
|
import { generateProposal } from '../../test-helpers/generate-proposals';
|
||||||
import { ProposalHeader } from './proposal-header';
|
import { ProposalHeader } from './proposal-header';
|
||||||
import type { ProposalFields } from '../../__generated__/ProposalFields';
|
import type { Proposal_proposal } from '../../proposal/__generated__/Proposal';
|
||||||
|
|
||||||
const renderComponent = (proposal: ProposalFields) => (
|
const renderComponent = (proposal: Proposal_proposal) => (
|
||||||
<ProposalHeader proposal={proposal} />
|
<ProposalHeader proposal={proposal} />
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -2,9 +2,13 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import { Lozenge } from '@vegaprotocol/ui-toolkit';
|
import { Lozenge } from '@vegaprotocol/ui-toolkit';
|
||||||
import type { ReactNode } from 'react';
|
import type { ReactNode } from 'react';
|
||||||
import { shorten } from '@vegaprotocol/react-helpers';
|
import { shorten } from '@vegaprotocol/react-helpers';
|
||||||
import type { ProposalFields } from '../../__generated__/ProposalFields';
|
import type { Proposal_proposal } from '../../proposal/__generated__/Proposal';
|
||||||
|
|
||||||
export const ProposalHeader = ({ proposal }: { proposal: ProposalFields }) => {
|
export const ProposalHeader = ({
|
||||||
|
proposal,
|
||||||
|
}: {
|
||||||
|
proposal: Proposal_proposal;
|
||||||
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { change } = proposal.terms;
|
const { change } = proposal.terms;
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
|
import { SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
|
||||||
import type { ProposalFields_terms } from '../../__generated__/ProposalFields';
|
import type { Proposal_proposal_terms } from '../../proposal/__generated__/Proposal';
|
||||||
|
|
||||||
export const ProposalTermsJson = ({
|
export const ProposalTermsJson = ({
|
||||||
terms,
|
terms,
|
||||||
}: {
|
}: {
|
||||||
terms: ProposalFields_terms;
|
terms: Proposal_proposal_terms;
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
return (
|
return (
|
||||||
|
@ -0,0 +1,115 @@
|
|||||||
|
import { render, screen } from '@testing-library/react';
|
||||||
|
import { MockedProvider } from '@apollo/client/testing';
|
||||||
|
import { AppStateProvider } from '../../../../contexts/app-state/app-state-provider';
|
||||||
|
import { ProposalVotesTable } from './proposal-votes-table';
|
||||||
|
import { ProposalType } from '../proposal/proposal';
|
||||||
|
import {
|
||||||
|
generateNoVotes,
|
||||||
|
generateProposal,
|
||||||
|
generateYesVotes,
|
||||||
|
} from '../../test-helpers/generate-proposals';
|
||||||
|
|
||||||
|
const defaultProposal = generateProposal();
|
||||||
|
const defaultProposalType = ProposalType.PROPOSAL_NETWORK_PARAMETER;
|
||||||
|
const updateMarketProposal = generateProposal({
|
||||||
|
terms: {
|
||||||
|
change: {
|
||||||
|
__typename: 'UpdateMarket',
|
||||||
|
marketId: '12345',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
votes: {
|
||||||
|
__typename: 'ProposalVotes',
|
||||||
|
yes: generateYesVotes(10),
|
||||||
|
no: generateNoVotes(0),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const updateMarketProposalType = ProposalType.PROPOSAL_UPDATE_MARKET;
|
||||||
|
|
||||||
|
const renderComponent = (
|
||||||
|
proposal = defaultProposal,
|
||||||
|
proposalType = defaultProposalType
|
||||||
|
) =>
|
||||||
|
render(
|
||||||
|
<MockedProvider>
|
||||||
|
<AppStateProvider>
|
||||||
|
<ProposalVotesTable proposal={proposal} proposalType={proposalType} />
|
||||||
|
</AppStateProvider>
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
|
|
||||||
|
describe('Proposal Votes Table', () => {
|
||||||
|
it('should render successfully', () => {
|
||||||
|
const { baseElement } = renderComponent();
|
||||||
|
expect(baseElement).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show vote breakdown fields, excluding custom update market fields', () => {
|
||||||
|
renderComponent();
|
||||||
|
expect(screen.getByText('Will pass')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('Token majority met')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('Token participation met')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('Tokens for proposal')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('Total Supply')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('Tokens against proposal')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('Participation required')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('Majority Required')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('Number of voting parties')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('Total yes tokens')).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
screen.getByText('Total tokens voted percentage')
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('Number of votes for')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('Number of votes against')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('Yes percentage')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('No percentage')).toBeInTheDocument();
|
||||||
|
expect(screen.queryByText('Liquidity majority met')).toBeNull();
|
||||||
|
expect(screen.queryByText('Liquidity participation met')).toBeNull();
|
||||||
|
expect(screen.queryByText('Liquidity shares for proposal')).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('displays different breakdown fields for update market proposal', () => {
|
||||||
|
renderComponent(updateMarketProposal, updateMarketProposalType);
|
||||||
|
expect(screen.getByText('Liquidity majority met')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('Liquidity participation met')).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
screen.getByText('Liquidity shares for proposal')
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(screen.queryByText('Number of voting parties')).toBeNull();
|
||||||
|
expect(screen.queryByText('Total yes tokens')).toBeNull();
|
||||||
|
expect(screen.queryByText('Total tokens voted percentage')).toBeNull();
|
||||||
|
expect(screen.queryByText('Number of votes for')).toBeNull();
|
||||||
|
expect(screen.queryByText('Number of votes against')).toBeNull();
|
||||||
|
expect(screen.queryByText('Yes percentage')).toBeNull();
|
||||||
|
expect(screen.queryByText('No percentage')).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('displays if an update market proposal will pass by token vote', () => {
|
||||||
|
renderComponent(updateMarketProposal, updateMarketProposalType);
|
||||||
|
expect(screen.getByText('👍 by Token vote')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('displays if an update market proposal will pass by LP vote', () => {
|
||||||
|
renderComponent(
|
||||||
|
generateProposal({
|
||||||
|
terms: {
|
||||||
|
change: {
|
||||||
|
__typename: 'UpdateMarket',
|
||||||
|
marketId: '12345',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
votes: {
|
||||||
|
__typename: 'ProposalVotes',
|
||||||
|
yes: {
|
||||||
|
...generateYesVotes(0, 1, '10'),
|
||||||
|
},
|
||||||
|
no: {
|
||||||
|
...generateNoVotes(0, 1, '0'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
updateMarketProposalType
|
||||||
|
);
|
||||||
|
expect(screen.getByText('👍 by Liquidity vote')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
@ -1,40 +1,58 @@
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import {
|
||||||
import { KeyValueTable, KeyValueTableRow } from '@vegaprotocol/ui-toolkit';
|
KeyValueTable,
|
||||||
|
KeyValueTableRow,
|
||||||
|
Thumbs,
|
||||||
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
import {
|
import {
|
||||||
formatNumber,
|
formatNumber,
|
||||||
formatNumberPercentage,
|
formatNumberPercentage,
|
||||||
} from '@vegaprotocol/react-helpers';
|
} from '@vegaprotocol/react-helpers';
|
||||||
import { useVoteInformation } from '../../hooks';
|
import { useVoteInformation } from '../../hooks';
|
||||||
import { useAppState } from '../../../../contexts/app-state/app-state-context';
|
import { useAppState } from '../../../../contexts/app-state/app-state-context';
|
||||||
import type { ProposalFields } from '../../__generated__/ProposalFields';
|
import type { Proposal_proposal } from '../../proposal/__generated__/Proposal';
|
||||||
|
import { ProposalType } from '../proposal/proposal';
|
||||||
|
|
||||||
interface ProposalVotesTableProps {
|
interface ProposalVotesTableProps {
|
||||||
proposal: ProposalFields;
|
proposal: Proposal_proposal;
|
||||||
|
proposalType: ProposalType | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ProposalVotesTable = ({ proposal }: ProposalVotesTableProps) => {
|
export const ProposalVotesTable = ({
|
||||||
|
proposal,
|
||||||
|
proposalType,
|
||||||
|
}: ProposalVotesTableProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const {
|
const {
|
||||||
appState: { totalSupply },
|
appState: { totalSupply },
|
||||||
} = useAppState();
|
} = useAppState();
|
||||||
const {
|
const {
|
||||||
willPass,
|
willPassByTokenVote,
|
||||||
|
willPassByLPVote,
|
||||||
totalTokensPercentage,
|
totalTokensPercentage,
|
||||||
participationMet,
|
participationMet,
|
||||||
|
participationLPMet,
|
||||||
totalTokensVoted,
|
totalTokensVoted,
|
||||||
noPercentage,
|
noPercentage,
|
||||||
yesPercentage,
|
yesPercentage,
|
||||||
noTokens,
|
noTokens,
|
||||||
yesTokens,
|
yesTokens,
|
||||||
|
yesEquityLikeShareWeight,
|
||||||
yesVotes,
|
yesVotes,
|
||||||
noVotes,
|
noVotes,
|
||||||
totalVotes,
|
totalVotes,
|
||||||
requiredMajorityPercentage,
|
requiredMajorityPercentage,
|
||||||
requiredParticipation,
|
requiredParticipation,
|
||||||
majorityMet,
|
majorityMet,
|
||||||
|
majorityLPMet,
|
||||||
} = useVoteInformation({ proposal });
|
} = useVoteInformation({ proposal });
|
||||||
|
|
||||||
|
const isUpdateMarket = proposalType === ProposalType.PROPOSAL_UPDATE_MARKET;
|
||||||
|
const updateMarketWillPass = willPassByTokenVote || willPassByLPVote;
|
||||||
|
const updateMarketVotePassMethod = willPassByTokenVote
|
||||||
|
? t('byTokenVote')
|
||||||
|
: t('byLiquidityVote');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<KeyValueTable
|
<KeyValueTable
|
||||||
title={t('voteBreakdown')}
|
title={t('voteBreakdown')}
|
||||||
@ -44,20 +62,48 @@ export const ProposalVotesTable = ({ proposal }: ProposalVotesTableProps) => {
|
|||||||
>
|
>
|
||||||
<KeyValueTableRow>
|
<KeyValueTableRow>
|
||||||
{t('willPass')}
|
{t('willPass')}
|
||||||
{willPass ? '👍' : '👎'}
|
{isUpdateMarket ? (
|
||||||
|
updateMarketWillPass ? (
|
||||||
|
<Thumbs up={true} text={updateMarketVotePassMethod} />
|
||||||
|
) : (
|
||||||
|
<Thumbs up={false} />
|
||||||
|
)
|
||||||
|
) : willPassByTokenVote ? (
|
||||||
|
<Thumbs up={true} />
|
||||||
|
) : (
|
||||||
|
<Thumbs up={false} />
|
||||||
|
)}
|
||||||
</KeyValueTableRow>
|
</KeyValueTableRow>
|
||||||
<KeyValueTableRow>
|
<KeyValueTableRow>
|
||||||
{t('majorityMet')}
|
{t('majorityMet')}
|
||||||
{majorityMet ? '👍' : '👎'}
|
{majorityMet ? <Thumbs up={true} /> : <Thumbs up={false} />}
|
||||||
</KeyValueTableRow>
|
</KeyValueTableRow>
|
||||||
|
{isUpdateMarket && (
|
||||||
|
<KeyValueTableRow>
|
||||||
|
{t('majorityLPMet')}
|
||||||
|
{majorityLPMet ? <Thumbs up={true} /> : <Thumbs up={false} />}
|
||||||
|
</KeyValueTableRow>
|
||||||
|
)}
|
||||||
<KeyValueTableRow>
|
<KeyValueTableRow>
|
||||||
{t('participationMet')}
|
{t('participationMet')}
|
||||||
{participationMet ? '👍' : '👎'}
|
{participationMet ? <Thumbs up={true} /> : <Thumbs up={false} />}
|
||||||
</KeyValueTableRow>
|
</KeyValueTableRow>
|
||||||
|
{isUpdateMarket && (
|
||||||
|
<KeyValueTableRow>
|
||||||
|
{t('participationLPMet')}
|
||||||
|
{participationLPMet ? <Thumbs up={true} /> : <Thumbs up={false} />}
|
||||||
|
</KeyValueTableRow>
|
||||||
|
)}
|
||||||
<KeyValueTableRow>
|
<KeyValueTableRow>
|
||||||
{t('tokenForProposal')}
|
{t('tokenForProposal')}
|
||||||
{formatNumber(yesTokens, 2)}
|
{formatNumber(yesTokens, 2)}
|
||||||
</KeyValueTableRow>
|
</KeyValueTableRow>
|
||||||
|
{isUpdateMarket && (
|
||||||
|
<KeyValueTableRow>
|
||||||
|
{t('tokenLPForProposal')}
|
||||||
|
{formatNumber(yesEquityLikeShareWeight, 2)}
|
||||||
|
</KeyValueTableRow>
|
||||||
|
)}
|
||||||
<KeyValueTableRow>
|
<KeyValueTableRow>
|
||||||
{t('totalSupply')}
|
{t('totalSupply')}
|
||||||
{formatNumber(totalSupply, 2)}
|
{formatNumber(totalSupply, 2)}
|
||||||
@ -74,34 +120,38 @@ export const ProposalVotesTable = ({ proposal }: ProposalVotesTableProps) => {
|
|||||||
{t('majorityRequired')}
|
{t('majorityRequired')}
|
||||||
{formatNumberPercentage(requiredMajorityPercentage)}
|
{formatNumberPercentage(requiredMajorityPercentage)}
|
||||||
</KeyValueTableRow>
|
</KeyValueTableRow>
|
||||||
<KeyValueTableRow>
|
{!isUpdateMarket && (
|
||||||
{t('numberOfVotingParties')}
|
<>
|
||||||
{formatNumber(totalVotes, 0)}
|
<KeyValueTableRow>
|
||||||
</KeyValueTableRow>
|
{t('numberOfVotingParties')}
|
||||||
<KeyValueTableRow>
|
{formatNumber(totalVotes, 0)}
|
||||||
{t('totalTokensVotes')}
|
</KeyValueTableRow>
|
||||||
{formatNumber(totalTokensVoted, 2)}
|
<KeyValueTableRow>
|
||||||
</KeyValueTableRow>
|
{t('totalTokensVotes')}
|
||||||
<KeyValueTableRow>
|
{formatNumber(totalTokensVoted, 2)}
|
||||||
{t('totalTokenVotedPercentage')}
|
</KeyValueTableRow>
|
||||||
{formatNumberPercentage(totalTokensPercentage, 2)}
|
<KeyValueTableRow>
|
||||||
</KeyValueTableRow>
|
{t('totalTokenVotedPercentage')}
|
||||||
<KeyValueTableRow>
|
{formatNumberPercentage(totalTokensPercentage, 2)}
|
||||||
{t('numberOfForVotes')}
|
</KeyValueTableRow>
|
||||||
{formatNumber(yesVotes, 0)}
|
<KeyValueTableRow>
|
||||||
</KeyValueTableRow>
|
{t('numberOfForVotes')}
|
||||||
<KeyValueTableRow>
|
{formatNumber(yesVotes, 0)}
|
||||||
{t('numberOfAgainstVotes')}
|
</KeyValueTableRow>
|
||||||
{formatNumber(noVotes, 0)}
|
<KeyValueTableRow>
|
||||||
</KeyValueTableRow>
|
{t('numberOfAgainstVotes')}
|
||||||
<KeyValueTableRow>
|
{formatNumber(noVotes, 0)}
|
||||||
{t('yesPercentage')}
|
</KeyValueTableRow>
|
||||||
{formatNumberPercentage(yesPercentage, 2)}
|
<KeyValueTableRow>
|
||||||
</KeyValueTableRow>
|
{t('yesPercentage')}
|
||||||
<KeyValueTableRow>
|
{formatNumberPercentage(yesPercentage, 2)}
|
||||||
{t('noPercentage')}
|
</KeyValueTableRow>
|
||||||
{formatNumberPercentage(noPercentage, 2)}
|
<KeyValueTableRow>
|
||||||
</KeyValueTableRow>
|
{t('noPercentage')}
|
||||||
|
{formatNumberPercentage(noPercentage, 2)}
|
||||||
|
</KeyValueTableRow>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</KeyValueTable>
|
</KeyValueTable>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -3,6 +3,22 @@ import { generateProposal } from '../../test-helpers/generate-proposals';
|
|||||||
import { Proposal } from './proposal';
|
import { Proposal } from './proposal';
|
||||||
import type { Proposal_proposal } from '../../proposal/__generated__/Proposal';
|
import type { Proposal_proposal } from '../../proposal/__generated__/Proposal';
|
||||||
|
|
||||||
|
jest.mock('@vegaprotocol/react-helpers', () => ({
|
||||||
|
...jest.requireActual('@vegaprotocol/react-helpers'),
|
||||||
|
useNetworkParams: jest.fn(() => ({
|
||||||
|
params: {
|
||||||
|
governance_proposal_asset_minVoterBalance: '1',
|
||||||
|
governance_proposal_freeform_minVoterBalance: '0',
|
||||||
|
governance_proposal_market_minVoterBalance: '1',
|
||||||
|
governance_proposal_updateAsset_minVoterBalance: '0',
|
||||||
|
governance_proposal_updateMarket_minVoterBalance: '1',
|
||||||
|
governance_proposal_updateNetParam_minVoterBalance: '1',
|
||||||
|
spam_protection_voting_min_tokens: '1000000000000000000',
|
||||||
|
},
|
||||||
|
loading: false,
|
||||||
|
error: null,
|
||||||
|
})),
|
||||||
|
}));
|
||||||
jest.mock('../proposal-detail-header/proposal-header', () => ({
|
jest.mock('../proposal-detail-header/proposal-header', () => ({
|
||||||
ProposalHeader: () => <div data-testid="proposal-header"></div>,
|
ProposalHeader: () => <div data-testid="proposal-header"></div>,
|
||||||
}));
|
}));
|
||||||
@ -19,16 +35,16 @@ jest.mock('../vote-details', () => ({
|
|||||||
VoteDetails: () => <div data-testid="proposal-vote-details"></div>,
|
VoteDetails: () => <div data-testid="proposal-vote-details"></div>,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('Renders with data-testid', () => {
|
it('Renders with data-testid', async () => {
|
||||||
const proposal = generateProposal();
|
const proposal = generateProposal();
|
||||||
render(<Proposal proposal={proposal as Proposal_proposal} />);
|
render(<Proposal proposal={proposal as Proposal_proposal} />);
|
||||||
expect(screen.getByTestId('proposal')).toBeInTheDocument();
|
expect(await screen.findByTestId('proposal')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders each section', () => {
|
it('renders each section', async () => {
|
||||||
const proposal = generateProposal();
|
const proposal = generateProposal();
|
||||||
render(<Proposal proposal={proposal as Proposal_proposal} />);
|
render(<Proposal proposal={proposal as Proposal_proposal} />);
|
||||||
expect(screen.getByTestId('proposal-header')).toBeInTheDocument();
|
expect(await screen.findByTestId('proposal-header')).toBeInTheDocument();
|
||||||
expect(screen.getByTestId('proposal-change-table')).toBeInTheDocument();
|
expect(screen.getByTestId('proposal-change-table')).toBeInTheDocument();
|
||||||
expect(screen.getByTestId('proposal-terms-json')).toBeInTheDocument();
|
expect(screen.getByTestId('proposal-terms-json')).toBeInTheDocument();
|
||||||
expect(screen.getByTestId('proposal-votes-table')).toBeInTheDocument();
|
expect(screen.getByTestId('proposal-votes-table')).toBeInTheDocument();
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import { NetworkParams, useNetworkParams } from '@vegaprotocol/react-helpers';
|
||||||
|
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||||
import { ProposalHeader } from '../proposal-detail-header/proposal-header';
|
import { ProposalHeader } from '../proposal-detail-header/proposal-header';
|
||||||
import type { Proposal_proposal } from '../../proposal/__generated__/Proposal';
|
import type { Proposal_proposal } from '../../proposal/__generated__/Proposal';
|
||||||
import { ProposalChangeTable } from '../proposal-change-table';
|
import { ProposalChangeTable } from '../proposal-change-table';
|
||||||
@ -5,28 +7,89 @@ import { ProposalTermsJson } from '../proposal-terms-json';
|
|||||||
import { ProposalVotesTable } from '../proposal-votes-table';
|
import { ProposalVotesTable } from '../proposal-votes-table';
|
||||||
import { VoteDetails } from '../vote-details';
|
import { VoteDetails } from '../vote-details';
|
||||||
|
|
||||||
|
export enum ProposalType {
|
||||||
|
PROPOSAL_NEW_MARKET = 'PROPOSAL_NEW_MARKET',
|
||||||
|
PROPOSAL_UPDATE_MARKET = 'PROPOSAL_UPDATE_MARKET',
|
||||||
|
PROPOSAL_NEW_ASSET = 'PROPOSAL_NEW_ASSET',
|
||||||
|
PROPOSAL_UPDATE_ASSET = 'PROPOSAL_UPDATE_ASSET',
|
||||||
|
PROPOSAL_NETWORK_PARAMETER = 'PROPOSAL_NETWORK_PARAMETER',
|
||||||
|
PROPOSAL_FREEFORM = 'PROPOSAL_FREEFORM',
|
||||||
|
}
|
||||||
|
|
||||||
interface ProposalProps {
|
interface ProposalProps {
|
||||||
proposal: Proposal_proposal;
|
proposal: Proposal_proposal;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Proposal = ({ proposal }: ProposalProps) => {
|
export const Proposal = ({ proposal }: ProposalProps) => {
|
||||||
|
const { params, loading, error } = useNetworkParams([
|
||||||
|
NetworkParams.governance_proposal_market_minVoterBalance,
|
||||||
|
NetworkParams.governance_proposal_updateMarket_minVoterBalance,
|
||||||
|
NetworkParams.governance_proposal_asset_minVoterBalance,
|
||||||
|
NetworkParams.governance_proposal_updateAsset_minVoterBalance,
|
||||||
|
NetworkParams.governance_proposal_updateNetParam_minVoterBalance,
|
||||||
|
NetworkParams.governance_proposal_freeform_minVoterBalance,
|
||||||
|
NetworkParams.spam_protection_voting_min_tokens,
|
||||||
|
]);
|
||||||
|
|
||||||
if (!proposal) {
|
if (!proposal) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let minVoterBalance = null;
|
||||||
|
let proposalType = null;
|
||||||
|
|
||||||
|
if (params) {
|
||||||
|
switch (proposal.terms.change.__typename) {
|
||||||
|
case 'NewMarket':
|
||||||
|
minVoterBalance = params.governance_proposal_market_minVoterBalance;
|
||||||
|
proposalType = ProposalType.PROPOSAL_NEW_MARKET;
|
||||||
|
break;
|
||||||
|
case 'UpdateMarket':
|
||||||
|
minVoterBalance =
|
||||||
|
params.governance_proposal_updateMarket_minVoterBalance;
|
||||||
|
proposalType = ProposalType.PROPOSAL_UPDATE_MARKET;
|
||||||
|
break;
|
||||||
|
case 'NewAsset':
|
||||||
|
minVoterBalance = params.governance_proposal_asset_minVoterBalance;
|
||||||
|
proposalType = ProposalType.PROPOSAL_NEW_ASSET;
|
||||||
|
break;
|
||||||
|
case 'UpdateAsset':
|
||||||
|
minVoterBalance =
|
||||||
|
params.governance_proposal_updateAsset_minVoterBalance;
|
||||||
|
proposalType = ProposalType.PROPOSAL_UPDATE_ASSET;
|
||||||
|
break;
|
||||||
|
case 'UpdateNetworkParameter':
|
||||||
|
minVoterBalance =
|
||||||
|
params.governance_proposal_updateNetParam_minVoterBalance;
|
||||||
|
proposalType = ProposalType.PROPOSAL_NETWORK_PARAMETER;
|
||||||
|
break;
|
||||||
|
case 'NewFreeform':
|
||||||
|
minVoterBalance = params.governance_proposal_freeform_minVoterBalance;
|
||||||
|
proposalType = ProposalType.PROPOSAL_FREEFORM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section data-testid="proposal">
|
<AsyncRenderer data={params} loading={loading} error={error}>
|
||||||
<ProposalHeader proposal={proposal} />
|
<section data-testid="proposal">
|
||||||
<div className="mb-8">
|
<ProposalHeader proposal={proposal} />
|
||||||
<ProposalChangeTable proposal={proposal} />
|
<div className="mb-8">
|
||||||
</div>
|
<ProposalChangeTable proposal={proposal} />
|
||||||
<div className="mb-8">
|
</div>
|
||||||
<VoteDetails proposal={proposal} />
|
<div className="mb-8">
|
||||||
</div>
|
<VoteDetails
|
||||||
<div className="mb-8">
|
proposal={proposal}
|
||||||
<ProposalVotesTable proposal={proposal} />
|
proposalType={proposalType}
|
||||||
</div>
|
minVoterBalance={minVoterBalance}
|
||||||
<ProposalTermsJson terms={proposal.terms} />
|
spamProtectionMinTokens={params?.spam_protection_voting_min_tokens}
|
||||||
</section>
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="mb-8">
|
||||||
|
<ProposalVotesTable proposal={proposal} proposalType={proposalType} />
|
||||||
|
</div>
|
||||||
|
<ProposalTermsJson terms={proposal.terms} />
|
||||||
|
</section>
|
||||||
|
</AsyncRenderer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -26,10 +26,10 @@ import {
|
|||||||
lastWeek,
|
lastWeek,
|
||||||
nextWeek,
|
nextWeek,
|
||||||
} from '../../test-helpers/mocks';
|
} from '../../test-helpers/mocks';
|
||||||
import type { Proposals_proposalsConnection_edges_node as ProposalNode } from '../../proposals/__generated__/Proposals';
|
import type { Proposal_proposal } from '../../proposal/__generated__/Proposal';
|
||||||
|
|
||||||
const renderComponent = (
|
const renderComponent = (
|
||||||
proposal: ProposalNode,
|
proposal: Proposal_proposal,
|
||||||
mock = networkParamsQueryMock
|
mock = networkParamsQueryMock
|
||||||
) =>
|
) =>
|
||||||
render(
|
render(
|
||||||
|
@ -15,7 +15,7 @@ import {
|
|||||||
ProposalState,
|
ProposalState,
|
||||||
} from '@vegaprotocol/types';
|
} from '@vegaprotocol/types';
|
||||||
import Routes from '../../../routes';
|
import Routes from '../../../routes';
|
||||||
import type { ProposalFields } from '../../__generated__/ProposalFields';
|
import type { Proposal_proposal } from '../../proposal/__generated__/Proposal';
|
||||||
|
|
||||||
const MajorityNotReached = () => {
|
const MajorityNotReached = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -37,12 +37,13 @@ const ParticipationNotReached = () => {
|
|||||||
export const ProposalsListItemDetails = ({
|
export const ProposalsListItemDetails = ({
|
||||||
proposal,
|
proposal,
|
||||||
}: {
|
}: {
|
||||||
proposal: ProposalFields;
|
proposal: Proposal_proposal;
|
||||||
}) => {
|
}) => {
|
||||||
const { state } = proposal;
|
const { state } = proposal;
|
||||||
const { willPass, majorityMet, participationMet } = useVoteInformation({
|
const { willPassByTokenVote, majorityMet, participationMet } =
|
||||||
proposal,
|
useVoteInformation({
|
||||||
});
|
proposal,
|
||||||
|
});
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { voteState } = useUserVote(
|
const { voteState } = useUserVote(
|
||||||
proposal.id,
|
proposal.id,
|
||||||
@ -133,7 +134,7 @@ export const ProposalsListItemDetails = ({
|
|||||||
voteStatus =
|
voteStatus =
|
||||||
(!participationMet && <ParticipationNotReached />) ||
|
(!participationMet && <ParticipationNotReached />) ||
|
||||||
(!majorityMet && <MajorityNotReached />) ||
|
(!majorityMet && <MajorityNotReached />) ||
|
||||||
(willPass ? (
|
(willPassByTokenVote ? (
|
||||||
<>
|
<>
|
||||||
{t('Set to')} <StatusPass>{t('pass')}</StatusPass>
|
{t('Set to')} <StatusPass>{t('pass')}</StatusPass>
|
||||||
</>
|
</>
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import type { ProposalFields } from '../../__generated__/ProposalFields';
|
|
||||||
import { ProposalHeader } from '../proposal-detail-header/proposal-header';
|
import { ProposalHeader } from '../proposal-detail-header/proposal-header';
|
||||||
import { ProposalsListItemDetails } from './proposals-list-item-details';
|
import { ProposalsListItemDetails } from './proposals-list-item-details';
|
||||||
|
import type { Proposal_proposal } from '../../proposal/__generated__/Proposal';
|
||||||
|
|
||||||
interface ProposalsListItemProps {
|
interface ProposalsListItemProps {
|
||||||
proposal: ProposalFields;
|
proposal: Proposal_proposal;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ProposalsListItem = ({ proposal }: ProposalsListItemProps) => {
|
export const ProposalsListItem = ({ proposal }: ProposalsListItemProps) => {
|
||||||
|
@ -14,7 +14,7 @@ import {
|
|||||||
lastMonth,
|
lastMonth,
|
||||||
nextMonth,
|
nextMonth,
|
||||||
} from '../../test-helpers/mocks';
|
} from '../../test-helpers/mocks';
|
||||||
import type { ProposalFields } from '../../__generated__/ProposalFields';
|
import type { Proposal_proposal } from '../../proposal/__generated__/Proposal';
|
||||||
|
|
||||||
const openProposalClosesNextMonth = generateProposal({
|
const openProposalClosesNextMonth = generateProposal({
|
||||||
id: 'proposal1',
|
id: 'proposal1',
|
||||||
@ -58,7 +58,7 @@ const failedProposalClosedLastMonth = generateProposal({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const renderComponent = (proposals: ProposalFields[]) => (
|
const renderComponent = (proposals: Proposal_proposal[]) => (
|
||||||
<Router>
|
<Router>
|
||||||
<MockedProvider mocks={[networkParamsQueryMock]}>
|
<MockedProvider mocks={[networkParamsQueryMock]}>
|
||||||
<AppStateProvider>
|
<AppStateProvider>
|
||||||
|
@ -7,17 +7,17 @@ import { ProposalsListFilter } from '../proposals-list-filter';
|
|||||||
import Routes from '../../../routes';
|
import Routes from '../../../routes';
|
||||||
import { Button } from '@vegaprotocol/ui-toolkit';
|
import { Button } from '@vegaprotocol/ui-toolkit';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import type { ProposalFields } from '../../__generated__/ProposalFields';
|
import type { Proposal_proposal } from '../../proposal/__generated__/Proposal';
|
||||||
import { Links } from '../../../../config';
|
import { Links } from '../../../../config';
|
||||||
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||||
|
|
||||||
interface ProposalsListProps {
|
interface ProposalsListProps {
|
||||||
proposals: ProposalFields[];
|
proposals: Proposal_proposal[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SortedProposalsProps {
|
interface SortedProposalsProps {
|
||||||
open: ProposalFields[];
|
open: Proposal_proposal[];
|
||||||
closed: ProposalFields[];
|
closed: Proposal_proposal[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ProposalsList = ({ proposals }: ProposalsListProps) => {
|
export const ProposalsList = ({ proposals }: ProposalsListProps) => {
|
||||||
@ -39,7 +39,7 @@ export const ProposalsList = ({ proposals }: ProposalsListProps) => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const filterPredicate = (p: ProposalFields) =>
|
const filterPredicate = (p: Proposal_proposal) =>
|
||||||
p.id?.includes(filterString) ||
|
p.id?.includes(filterString) ||
|
||||||
p.party?.id?.toString().includes(filterString);
|
p.party?.id?.toString().includes(filterString);
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ import {
|
|||||||
nextWeek,
|
nextWeek,
|
||||||
lastMonth,
|
lastMonth,
|
||||||
} from '../../test-helpers/mocks';
|
} from '../../test-helpers/mocks';
|
||||||
import type { ProposalFields } from '../../__generated__/ProposalFields';
|
import type { Proposal_proposal } from '../../proposal/__generated__/Proposal';
|
||||||
|
|
||||||
const rejectedProposalClosesNextWeek = generateProposal({
|
const rejectedProposalClosesNextWeek = generateProposal({
|
||||||
id: 'rejected1',
|
id: 'rejected1',
|
||||||
@ -35,7 +35,7 @@ const rejectedProposalClosedLastMonth = generateProposal({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const renderComponent = (proposals: ProposalFields[]) => (
|
const renderComponent = (proposals: Proposal_proposal[]) => (
|
||||||
<Router>
|
<Router>
|
||||||
<MockedProvider mocks={[networkParamsQueryMock]}>
|
<MockedProvider mocks={[networkParamsQueryMock]}>
|
||||||
<AppStateProvider>
|
<AppStateProvider>
|
||||||
|
@ -3,17 +3,17 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import { Heading } from '../../../../components/heading';
|
import { Heading } from '../../../../components/heading';
|
||||||
import { ProposalsListItem } from '../proposals-list-item';
|
import { ProposalsListItem } from '../proposals-list-item';
|
||||||
import { ProposalsListFilter } from '../proposals-list-filter';
|
import { ProposalsListFilter } from '../proposals-list-filter';
|
||||||
import type { Proposals_proposalsConnection_edges_node } from '../../proposals/__generated__/Proposals';
|
import type { Proposal_proposal } from '../../proposal/__generated__/Proposal';
|
||||||
|
|
||||||
interface ProposalsListProps {
|
interface ProposalsListProps {
|
||||||
proposals: Proposals_proposalsConnection_edges_node[];
|
proposals: Proposal_proposal[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const RejectedProposalsList = ({ proposals }: ProposalsListProps) => {
|
export const RejectedProposalsList = ({ proposals }: ProposalsListProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [filterString, setFilterString] = useState('');
|
const [filterString, setFilterString] = useState('');
|
||||||
|
|
||||||
const filterPredicate = (p: Proposals_proposalsConnection_edges_node) =>
|
const filterPredicate = (p: Proposal_proposal) =>
|
||||||
p.id?.includes(filterString) ||
|
p.id?.includes(filterString) ||
|
||||||
p.party?.id?.toString().includes(filterString);
|
p.party?.id?.toString().includes(filterString);
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { render } from '@testing-library/react';
|
import { render } from '@testing-library/react';
|
||||||
import { ProposalMinRequirements } from './proposal-min-requirements';
|
import { ProposalMinRequirements } from './proposal-min-requirements';
|
||||||
import { ProposalUserAction } from '@vegaprotocol/types';
|
import { ProposalUserAction } from '../../components/shared';
|
||||||
|
|
||||||
describe('ProposalFormMinRequirements', () => {
|
describe('ProposalFormMinRequirements', () => {
|
||||||
it('should render successfully with spam protection value, if larger', () => {
|
it('should render successfully with spam protection value, if larger', () => {
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import { addDecimal } from '@vegaprotocol/react-helpers';
|
import { addDecimal } from '@vegaprotocol/react-helpers';
|
||||||
import { ProposalUserAction } from '@vegaprotocol/types';
|
|
||||||
|
export enum ProposalUserAction {
|
||||||
|
CREATE = 'CREATE',
|
||||||
|
VOTE = 'VOTE',
|
||||||
|
}
|
||||||
|
|
||||||
interface ProposalFormMinRequirementsProps {
|
interface ProposalFormMinRequirementsProps {
|
||||||
minProposalBalance: string;
|
minProposalBalance: string;
|
||||||
|
@ -15,11 +15,8 @@ import type {
|
|||||||
} from './__generated__/VoteButtonsQuery';
|
} from './__generated__/VoteButtonsQuery';
|
||||||
import { VoteState } from './use-user-vote';
|
import { VoteState } from './use-user-vote';
|
||||||
import { useVegaWallet, useVegaWalletDialogStore } from '@vegaprotocol/wallet';
|
import { useVegaWallet, useVegaWalletDialogStore } from '@vegaprotocol/wallet';
|
||||||
import {
|
import { ProposalState, VoteValue } from '@vegaprotocol/types';
|
||||||
ProposalState,
|
import { ProposalUserAction } from '../shared';
|
||||||
ProposalUserAction,
|
|
||||||
VoteValue,
|
|
||||||
} from '@vegaprotocol/types';
|
|
||||||
import { AsyncRenderer, Button, ButtonLink } from '@vegaprotocol/ui-toolkit';
|
import { AsyncRenderer, Button, ButtonLink } from '@vegaprotocol/ui-toolkit';
|
||||||
import { ProposalMinRequirements } from '../shared';
|
import { ProposalMinRequirements } from '../shared';
|
||||||
import { addDecimal } from '@vegaprotocol/react-helpers';
|
import { addDecimal } from '@vegaprotocol/react-helpers';
|
||||||
|
@ -1,72 +1,43 @@
|
|||||||
import { formatDistanceToNow } from 'date-fns';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { formatNumber } from '../../../../lib/format-number';
|
import { formatNumber } from '../../../../lib/format-number';
|
||||||
import { ConnectToVega } from '../../../../components/connect-to-vega/connect-to-vega';
|
import { ConnectToVega } from '../../../../components/connect-to-vega';
|
||||||
import { useVoteInformation } from '../../hooks';
|
import { useVoteInformation } from '../../hooks';
|
||||||
import { CurrentProposalStatus } from '../current-proposal-status';
|
|
||||||
import { useUserVote } from './use-user-vote';
|
import { useUserVote } from './use-user-vote';
|
||||||
import { VoteButtonsContainer } from './vote-buttons';
|
import { VoteButtonsContainer } from './vote-buttons';
|
||||||
import { VoteProgress } from './vote-progress';
|
import { VoteProgress } from './vote-progress';
|
||||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||||
import { ProposalState } from '@vegaprotocol/types';
|
import { ProposalType } from '../proposal/proposal';
|
||||||
import type { Proposal_proposal } from '../../proposal/__generated__/Proposal';
|
import type { Proposal_proposal } from '../../proposal/__generated__/Proposal';
|
||||||
import { NetworkParams, useNetworkParams } from '@vegaprotocol/react-helpers';
|
|
||||||
|
|
||||||
interface VoteDetailsProps {
|
interface VoteDetailsProps {
|
||||||
proposal: Proposal_proposal;
|
proposal: Proposal_proposal;
|
||||||
|
minVoterBalance: string | null;
|
||||||
|
spamProtectionMinTokens: string | null;
|
||||||
|
proposalType: ProposalType | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const VoteDetails = ({ proposal }: VoteDetailsProps) => {
|
export const VoteDetails = ({
|
||||||
|
proposal,
|
||||||
|
minVoterBalance,
|
||||||
|
spamProtectionMinTokens,
|
||||||
|
proposalType,
|
||||||
|
}: VoteDetailsProps) => {
|
||||||
const { pubKey } = useVegaWallet();
|
const { pubKey } = useVegaWallet();
|
||||||
const {
|
const {
|
||||||
totalTokensPercentage,
|
totalTokensPercentage,
|
||||||
participationMet,
|
participationMet,
|
||||||
totalTokensVoted,
|
totalTokensVoted,
|
||||||
noPercentage,
|
noPercentage,
|
||||||
|
noLPPercentage,
|
||||||
yesPercentage,
|
yesPercentage,
|
||||||
|
yesLPPercentage,
|
||||||
yesTokens,
|
yesTokens,
|
||||||
noTokens,
|
noTokens,
|
||||||
requiredMajorityPercentage,
|
requiredMajorityPercentage,
|
||||||
|
requiredMajorityLPPercentage,
|
||||||
requiredParticipation,
|
requiredParticipation,
|
||||||
} = useVoteInformation({ proposal });
|
} = useVoteInformation({ proposal });
|
||||||
|
|
||||||
let minVoterBalance = null;
|
|
||||||
const { params } = useNetworkParams([
|
|
||||||
NetworkParams.governance_proposal_market_minVoterBalance,
|
|
||||||
NetworkParams.governance_proposal_updateMarket_minVoterBalance,
|
|
||||||
NetworkParams.governance_proposal_asset_minVoterBalance,
|
|
||||||
NetworkParams.governance_proposal_updateAsset_minVoterBalance,
|
|
||||||
NetworkParams.governance_proposal_updateNetParam_minVoterBalance,
|
|
||||||
NetworkParams.governance_proposal_freeform_minVoterBalance,
|
|
||||||
NetworkParams.spam_protection_voting_min_tokens,
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (params) {
|
|
||||||
switch (proposal.terms.change.__typename) {
|
|
||||||
case 'NewMarket':
|
|
||||||
minVoterBalance = params.governance_proposal_market_minVoterBalance;
|
|
||||||
break;
|
|
||||||
case 'UpdateMarket':
|
|
||||||
minVoterBalance =
|
|
||||||
params.governance_proposal_updateMarket_minVoterBalance;
|
|
||||||
break;
|
|
||||||
case 'NewAsset':
|
|
||||||
minVoterBalance = params.governance_proposal_asset_minVoterBalance;
|
|
||||||
break;
|
|
||||||
case 'UpdateAsset':
|
|
||||||
minVoterBalance =
|
|
||||||
params.governance_proposal_updateAsset_minVoterBalance;
|
|
||||||
break;
|
|
||||||
case 'UpdateNetworkParameter':
|
|
||||||
minVoterBalance =
|
|
||||||
params.governance_proposal_updateNetParam_minVoterBalance;
|
|
||||||
break;
|
|
||||||
case 'NewFreeform':
|
|
||||||
minVoterBalance = params.governance_proposal_freeform_minVoterBalance;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { voteState, voteDatetime, castVote } = useUserVote(
|
const { voteState, voteDatetime, castVote } = useUserVote(
|
||||||
proposal.id,
|
proposal.id,
|
||||||
@ -75,98 +46,136 @@ export const VoteDetails = ({ proposal }: VoteDetailsProps) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const defaultDecimals = 2;
|
const defaultDecimals = 2;
|
||||||
const daysLeft = t('daysLeft', {
|
|
||||||
daysLeft: formatDistanceToNow(new Date(proposal.terms.closingDatetime)),
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section>
|
<>
|
||||||
<h3 className="text-xl mb-2">{t('votes')}</h3>
|
{proposalType === ProposalType.PROPOSAL_UPDATE_MARKET && (
|
||||||
<p>
|
<section>
|
||||||
<span>
|
<h3 className="text-xl mb-2">{t('liquidityVotes')}</h3>
|
||||||
<CurrentProposalStatus proposal={proposal} />
|
<table className="w-full mb-8">
|
||||||
</span>
|
<thead>
|
||||||
{'. '}
|
<tr>
|
||||||
{proposal.state === ProposalState.STATE_OPEN ? daysLeft : null}
|
<th className="text-vega-green w-[18%] text-left">
|
||||||
</p>
|
{t('for')}
|
||||||
<table className="w-full">
|
</th>
|
||||||
<thead>
|
<th>
|
||||||
<tr>
|
<VoteProgress
|
||||||
<th className="text-vega-green w-[18%] text-left">{t('for')}</th>
|
threshold={requiredMajorityLPPercentage}
|
||||||
<th>
|
progress={yesLPPercentage}
|
||||||
<VoteProgress
|
/>
|
||||||
threshold={requiredMajorityPercentage}
|
</th>
|
||||||
progress={yesPercentage}
|
<th className="text-danger w-[18%] text-right">
|
||||||
/>
|
{t('against')}
|
||||||
</th>
|
</th>
|
||||||
<th className="text-danger w-[18%] text-right">{t('against')}</th>
|
</tr>
|
||||||
</tr>
|
</thead>
|
||||||
</thead>
|
<tbody>
|
||||||
<tbody>
|
<tr>
|
||||||
<tr>
|
<td
|
||||||
<td
|
className="text-left"
|
||||||
className="text-left"
|
data-testid="vote-progress-indicator-percentage-for"
|
||||||
data-testid="vote-progress-indicator-percentage-for"
|
>
|
||||||
>
|
{yesLPPercentage.toFixed(defaultDecimals)}%
|
||||||
{yesPercentage.toFixed(defaultDecimals)}%
|
</td>
|
||||||
</td>
|
<td className="text-center text-white">
|
||||||
<td className="text-center text-white">
|
{t('majorityRequired')}{' '}
|
||||||
{t('majorityRequired')}{' '}
|
{requiredMajorityLPPercentage.toFixed(defaultDecimals)}%
|
||||||
{requiredMajorityPercentage.toFixed(defaultDecimals)}%
|
</td>
|
||||||
</td>
|
<td
|
||||||
<td
|
className="text-right"
|
||||||
className="text-right"
|
data-testid="vote-progress-indicator-percentage-against"
|
||||||
data-testid="vote-progress-indicator-percentage-against"
|
>
|
||||||
>
|
{noLPPercentage.toFixed(defaultDecimals)}%
|
||||||
{noPercentage.toFixed(defaultDecimals)}%
|
</td>
|
||||||
</td>
|
</tr>
|
||||||
</tr>
|
</tbody>
|
||||||
<tr>
|
</table>
|
||||||
<td data-testid="vote-progress-indicator-tokens-for">
|
</section>
|
||||||
{' '}
|
|
||||||
{formatNumber(yesTokens, defaultDecimals)}{' '}
|
|
||||||
</td>
|
|
||||||
<td></td>
|
|
||||||
<td
|
|
||||||
data-testid="vote-progress-indicator-tokens-against"
|
|
||||||
className="text-right"
|
|
||||||
>
|
|
||||||
{formatNumber(noTokens, defaultDecimals)}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<p>
|
|
||||||
{t('participation')}
|
|
||||||
{': '}
|
|
||||||
{participationMet ? (
|
|
||||||
<span className="text-vega-green mx-4">{t('met')}</span>
|
|
||||||
) : (
|
|
||||||
<span className="text-danger mx-4">{t('notMet')}</span>
|
|
||||||
)}{' '}
|
|
||||||
{formatNumber(totalTokensVoted, defaultDecimals)}{' '}
|
|
||||||
{formatNumber(totalTokensPercentage, defaultDecimals)}%
|
|
||||||
<span className="ml-4">
|
|
||||||
({formatNumber(requiredParticipation, defaultDecimals)}%{' '}
|
|
||||||
{t('governanceRequired')})
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
{pubKey ? (
|
|
||||||
<>
|
|
||||||
<h3 className="text-xl mb-2">{t('yourVote')}</h3>
|
|
||||||
<VoteButtonsContainer
|
|
||||||
voteState={voteState}
|
|
||||||
castVote={castVote}
|
|
||||||
voteDatetime={voteDatetime}
|
|
||||||
proposalState={proposal.state}
|
|
||||||
minVoterBalance={minVoterBalance}
|
|
||||||
spamProtectionMinTokens={params.spam_protection_voting_min_tokens}
|
|
||||||
className="flex"
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<ConnectToVega />
|
|
||||||
)}
|
)}
|
||||||
</section>
|
<section>
|
||||||
|
<h3 className="text-xl mb-2">{t('tokenVotes')}</h3>
|
||||||
|
<table className="w-full mb-4">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th className="text-vega-green w-[18%] text-left">{t('for')}</th>
|
||||||
|
<th>
|
||||||
|
<VoteProgress
|
||||||
|
threshold={requiredMajorityPercentage}
|
||||||
|
progress={yesPercentage}
|
||||||
|
/>
|
||||||
|
</th>
|
||||||
|
<th className="text-danger w-[18%] text-right">{t('against')}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
className="text-left"
|
||||||
|
data-testid="vote-progress-indicator-percentage-for"
|
||||||
|
>
|
||||||
|
{yesPercentage.toFixed(defaultDecimals)}%
|
||||||
|
</td>
|
||||||
|
<td className="text-center text-white">
|
||||||
|
{t('majorityRequired')}{' '}
|
||||||
|
{requiredMajorityPercentage.toFixed(defaultDecimals)}%
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
className="text-right"
|
||||||
|
data-testid="vote-progress-indicator-percentage-against"
|
||||||
|
>
|
||||||
|
{noPercentage.toFixed(defaultDecimals)}%
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td data-testid="vote-progress-indicator-tokens-for">
|
||||||
|
{' '}
|
||||||
|
{formatNumber(yesTokens, defaultDecimals)}{' '}
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
<td
|
||||||
|
data-testid="vote-progress-indicator-tokens-against"
|
||||||
|
className="text-right"
|
||||||
|
>
|
||||||
|
{formatNumber(noTokens, defaultDecimals)}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<p className="mb-6">
|
||||||
|
{t('participation')}
|
||||||
|
{': '}
|
||||||
|
{participationMet ? (
|
||||||
|
<span className="text-vega-green mx-4">{t('met')}</span>
|
||||||
|
) : (
|
||||||
|
<span className="text-danger mx-4">{t('notMet')}</span>
|
||||||
|
)}{' '}
|
||||||
|
{formatNumber(totalTokensVoted, defaultDecimals)}{' '}
|
||||||
|
{formatNumber(totalTokensPercentage, defaultDecimals)}%
|
||||||
|
<span className="ml-4">
|
||||||
|
({formatNumber(requiredParticipation, defaultDecimals)}%{' '}
|
||||||
|
{t('governanceRequired')})
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
{proposalType === ProposalType.PROPOSAL_UPDATE_MARKET && (
|
||||||
|
<p>{t('votingThresholdInfo')}</p>
|
||||||
|
)}
|
||||||
|
{pubKey ? (
|
||||||
|
<>
|
||||||
|
<h3 className="text-xl mb-2">{t('yourVote')}</h3>
|
||||||
|
<VoteButtonsContainer
|
||||||
|
voteState={voteState}
|
||||||
|
castVote={castVote}
|
||||||
|
voteDatetime={voteDatetime}
|
||||||
|
proposalState={proposal.state}
|
||||||
|
minVoterBalance={minVoterBalance}
|
||||||
|
spamProtectionMinTokens={spamProtectionMinTokens}
|
||||||
|
className="flex"
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<ConnectToVega />
|
||||||
|
)}
|
||||||
|
</section>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1 +1,2 @@
|
|||||||
export { useVoteInformation } from './use-vote-information';
|
export { useVoteInformation } from './use-vote-information';
|
||||||
|
export { useProposalNetworkParams } from './use-proposal-network-params';
|
||||||
|
@ -0,0 +1,146 @@
|
|||||||
|
import { renderHook } from '@testing-library/react';
|
||||||
|
import { BigNumber } from '../../../lib/bignumber';
|
||||||
|
import { useProposalNetworkParams } from './use-proposal-network-params';
|
||||||
|
import { generateProposal } from '../test-helpers/generate-proposals';
|
||||||
|
|
||||||
|
jest.mock('@vegaprotocol/react-helpers', () => ({
|
||||||
|
...jest.requireActual('@vegaprotocol/react-helpers'),
|
||||||
|
useNetworkParams: jest.fn(() => ({
|
||||||
|
params: {
|
||||||
|
governance_proposal_updateMarket_requiredMajority: '0.1',
|
||||||
|
governance_proposal_updateMarket_requiredParticipation: '0.15',
|
||||||
|
governance_proposal_updateMarket_requiredMajorityLP: '0.2',
|
||||||
|
governance_proposal_updateMarket_requiredParticipationLP: '0.25',
|
||||||
|
governance_proposal_market_requiredMajority: '0.3',
|
||||||
|
governance_proposal_market_requiredParticipation: '0.35',
|
||||||
|
governance_proposal_asset_requiredMajority: '0.4',
|
||||||
|
governance_proposal_asset_requiredParticipation: '0.45',
|
||||||
|
governance_proposal_updateAsset_requiredMajority: '0.5',
|
||||||
|
governance_proposal_updateAsset_requiredParticipation: '0.55',
|
||||||
|
governance_proposal_updateNetParam_requiredMajority: '0.6',
|
||||||
|
governance_proposal_updateNetParam_requiredParticipation: '0.65',
|
||||||
|
governance_proposal_freeform_requiredMajority: '0.7',
|
||||||
|
governance_proposal_freeform_requiredParticipation: '0.75',
|
||||||
|
},
|
||||||
|
loading: false,
|
||||||
|
error: null,
|
||||||
|
})),
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('use-proposal-network-params', () => {
|
||||||
|
it('returns the correct params for an update market proposal', () => {
|
||||||
|
const proposal = generateProposal({
|
||||||
|
terms: {
|
||||||
|
change: {
|
||||||
|
__typename: 'UpdateMarket',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
result: { current },
|
||||||
|
} = renderHook(() => useProposalNetworkParams({ proposal }));
|
||||||
|
|
||||||
|
expect(current).toEqual({
|
||||||
|
requiredMajority: '0.1',
|
||||||
|
requiredMajorityLP: '0.2',
|
||||||
|
requiredParticipation: new BigNumber(0.15),
|
||||||
|
requiredParticipationLP: new BigNumber(0.25),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns the correct params for a market proposal', () => {
|
||||||
|
const proposal = generateProposal({
|
||||||
|
terms: {
|
||||||
|
change: {
|
||||||
|
__typename: 'NewMarket',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
result: { current },
|
||||||
|
} = renderHook(() => useProposalNetworkParams({ proposal }));
|
||||||
|
|
||||||
|
expect(current).toEqual({
|
||||||
|
requiredMajority: '0.3',
|
||||||
|
requiredParticipation: new BigNumber(0.35),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns the correct params for an asset proposal', () => {
|
||||||
|
const proposal = generateProposal({
|
||||||
|
terms: {
|
||||||
|
change: {
|
||||||
|
__typename: 'NewAsset',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
result: { current },
|
||||||
|
} = renderHook(() => useProposalNetworkParams({ proposal }));
|
||||||
|
|
||||||
|
expect(current).toEqual({
|
||||||
|
requiredMajority: '0.4',
|
||||||
|
requiredParticipation: new BigNumber(0.45),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns the correct params for an update asset proposal', () => {
|
||||||
|
const proposal = generateProposal({
|
||||||
|
terms: {
|
||||||
|
change: {
|
||||||
|
__typename: 'UpdateAsset',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
result: { current },
|
||||||
|
} = renderHook(() => useProposalNetworkParams({ proposal }));
|
||||||
|
|
||||||
|
expect(current).toEqual({
|
||||||
|
requiredMajority: '0.5',
|
||||||
|
requiredParticipation: new BigNumber(0.55),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns the correct params for a network params proposal', () => {
|
||||||
|
const proposal = generateProposal({
|
||||||
|
terms: {
|
||||||
|
change: {
|
||||||
|
__typename: 'UpdateNetworkParameter',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
result: { current },
|
||||||
|
} = renderHook(() => useProposalNetworkParams({ proposal }));
|
||||||
|
|
||||||
|
expect(current).toEqual({
|
||||||
|
requiredMajority: '0.6',
|
||||||
|
requiredParticipation: new BigNumber(0.65),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns the correct params for a freeform proposal', () => {
|
||||||
|
const proposal = generateProposal({
|
||||||
|
terms: {
|
||||||
|
change: {
|
||||||
|
__typename: 'NewFreeform',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
result: { current },
|
||||||
|
} = renderHook(() => useProposalNetworkParams({ proposal }));
|
||||||
|
|
||||||
|
expect(current).toEqual({
|
||||||
|
requiredMajority: '0.7',
|
||||||
|
requiredParticipation: new BigNumber(0.75),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,90 @@
|
|||||||
|
import { NetworkParams, useNetworkParams } from '@vegaprotocol/react-helpers';
|
||||||
|
import { BigNumber } from '../../../lib/bignumber';
|
||||||
|
import type { Proposal_proposal } from '../proposal/__generated__/Proposal';
|
||||||
|
|
||||||
|
export const useProposalNetworkParams = ({
|
||||||
|
proposal,
|
||||||
|
}: {
|
||||||
|
proposal: Proposal_proposal;
|
||||||
|
}) => {
|
||||||
|
const { params } = useNetworkParams([
|
||||||
|
NetworkParams.governance_proposal_updateMarket_requiredMajority,
|
||||||
|
NetworkParams.governance_proposal_updateMarket_requiredMajorityLP,
|
||||||
|
NetworkParams.governance_proposal_updateMarket_requiredParticipation,
|
||||||
|
NetworkParams.governance_proposal_updateMarket_requiredParticipationLP,
|
||||||
|
NetworkParams.governance_proposal_market_requiredMajority,
|
||||||
|
NetworkParams.governance_proposal_market_requiredParticipation,
|
||||||
|
NetworkParams.governance_proposal_updateAsset_requiredMajority,
|
||||||
|
NetworkParams.governance_proposal_updateAsset_requiredParticipation,
|
||||||
|
NetworkParams.governance_proposal_asset_requiredMajority,
|
||||||
|
NetworkParams.governance_proposal_asset_requiredParticipation,
|
||||||
|
NetworkParams.governance_proposal_updateNetParam_requiredMajority,
|
||||||
|
NetworkParams.governance_proposal_updateNetParam_requiredParticipation,
|
||||||
|
NetworkParams.governance_proposal_freeform_requiredMajority,
|
||||||
|
NetworkParams.governance_proposal_freeform_requiredParticipation,
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!params) {
|
||||||
|
return {
|
||||||
|
requiredMajority: new BigNumber(1),
|
||||||
|
requiredMajorityLP: new BigNumber(0),
|
||||||
|
requiredParticipation: new BigNumber(1),
|
||||||
|
requiredParticipationLP: new BigNumber(0),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (proposal.terms.change.__typename) {
|
||||||
|
case 'UpdateMarket':
|
||||||
|
return {
|
||||||
|
requiredMajority:
|
||||||
|
params.governance_proposal_updateMarket_requiredMajority,
|
||||||
|
requiredMajorityLP:
|
||||||
|
params.governance_proposal_updateMarket_requiredMajorityLP,
|
||||||
|
requiredParticipation: new BigNumber(
|
||||||
|
params.governance_proposal_updateMarket_requiredParticipation
|
||||||
|
),
|
||||||
|
requiredParticipationLP: new BigNumber(
|
||||||
|
params.governance_proposal_updateMarket_requiredParticipationLP
|
||||||
|
),
|
||||||
|
};
|
||||||
|
case 'UpdateNetworkParameter':
|
||||||
|
return {
|
||||||
|
requiredMajority:
|
||||||
|
params.governance_proposal_updateNetParam_requiredMajority,
|
||||||
|
requiredParticipation: new BigNumber(
|
||||||
|
params.governance_proposal_updateNetParam_requiredParticipation
|
||||||
|
),
|
||||||
|
};
|
||||||
|
case 'NewAsset':
|
||||||
|
return {
|
||||||
|
requiredMajority: params.governance_proposal_asset_requiredMajority,
|
||||||
|
requiredParticipation: new BigNumber(
|
||||||
|
params.governance_proposal_asset_requiredParticipation
|
||||||
|
),
|
||||||
|
};
|
||||||
|
case 'UpdateAsset':
|
||||||
|
return {
|
||||||
|
requiredMajority:
|
||||||
|
params.governance_proposal_updateAsset_requiredMajority,
|
||||||
|
requiredParticipation: new BigNumber(
|
||||||
|
params.governance_proposal_updateAsset_requiredParticipation
|
||||||
|
),
|
||||||
|
};
|
||||||
|
case 'NewMarket':
|
||||||
|
return {
|
||||||
|
requiredMajority: params.governance_proposal_market_requiredMajority,
|
||||||
|
requiredParticipation: new BigNumber(
|
||||||
|
params.governance_proposal_market_requiredParticipation
|
||||||
|
),
|
||||||
|
};
|
||||||
|
case 'NewFreeform':
|
||||||
|
return {
|
||||||
|
requiredMajority: params.governance_proposal_freeform_requiredMajority,
|
||||||
|
requiredParticipation: new BigNumber(
|
||||||
|
params.governance_proposal_freeform_requiredParticipation
|
||||||
|
),
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
throw new Error('Unknown proposal type');
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,279 @@
|
|||||||
|
import { renderHook } from '@testing-library/react';
|
||||||
|
import { BigNumber } from '../../../lib/bignumber';
|
||||||
|
import { useVoteInformation } from './use-vote-information';
|
||||||
|
import {
|
||||||
|
generateProposal,
|
||||||
|
generateYesVotes,
|
||||||
|
generateNoVotes,
|
||||||
|
} from '../test-helpers/generate-proposals';
|
||||||
|
import type { AppState } from '../../../contexts/app-state/app-state-context';
|
||||||
|
|
||||||
|
const mockTotalSupply = new BigNumber(100);
|
||||||
|
|
||||||
|
const mockAppState: AppState = {
|
||||||
|
totalAssociated: new BigNumber('50063005'),
|
||||||
|
decimals: 18,
|
||||||
|
totalSupply: mockTotalSupply,
|
||||||
|
balanceFormatted: new BigNumber(0),
|
||||||
|
walletBalance: new BigNumber(0),
|
||||||
|
lien: new BigNumber(0),
|
||||||
|
allowance: new BigNumber(0),
|
||||||
|
tranches: null,
|
||||||
|
vegaWalletOverlay: false,
|
||||||
|
vegaWalletManageOverlay: false,
|
||||||
|
ethConnectOverlay: false,
|
||||||
|
walletAssociatedBalance: null,
|
||||||
|
vestingAssociatedBalance: null,
|
||||||
|
trancheBalances: [],
|
||||||
|
totalLockedBalance: new BigNumber(0),
|
||||||
|
totalVestedBalance: new BigNumber(0),
|
||||||
|
trancheError: null,
|
||||||
|
drawerOpen: false,
|
||||||
|
associationBreakdown: {
|
||||||
|
vestingAssociations: {},
|
||||||
|
stakingAssociations: {},
|
||||||
|
},
|
||||||
|
transactionOverlay: false,
|
||||||
|
bannerMessage: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
jest.mock('../../../contexts/app-state/app-state-context', () => ({
|
||||||
|
useAppState: () => ({
|
||||||
|
appState: mockAppState,
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
|
jest.mock('@vegaprotocol/react-helpers', () => ({
|
||||||
|
...jest.requireActual('@vegaprotocol/react-helpers'),
|
||||||
|
useNetworkParams: jest.fn(() => ({
|
||||||
|
params: {
|
||||||
|
governance_proposal_updateMarket_requiredMajority: '0.5',
|
||||||
|
governance_proposal_updateMarket_requiredMajorityLP: '0.5',
|
||||||
|
governance_proposal_updateMarket_requiredParticipation: '0.5',
|
||||||
|
governance_proposal_updateMarket_requiredParticipationLP: '0.5',
|
||||||
|
governance_proposal_market_requiredMajority: '0.5',
|
||||||
|
governance_proposal_market_requiredParticipation: '0.5',
|
||||||
|
governance_proposal_asset_requiredMajority: '0.5',
|
||||||
|
governance_proposal_asset_requiredParticipation: '0.5',
|
||||||
|
governance_proposal_updateAsset_requiredMajority: '0.5',
|
||||||
|
governance_proposal_updateAsset_requiredParticipation: '0.5',
|
||||||
|
governance_proposal_updateNetParam_requiredMajority: '0.5',
|
||||||
|
governance_proposal_updateNetParam_requiredParticipation: '0.5',
|
||||||
|
governance_proposal_freeform_requiredMajority: '0.5',
|
||||||
|
governance_proposal_freeform_requiredParticipation: '0.5',
|
||||||
|
},
|
||||||
|
loading: false,
|
||||||
|
error: null,
|
||||||
|
})),
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('use-vote-information', () => {
|
||||||
|
it('returns all required vote information', () => {
|
||||||
|
const yesVotes = 40;
|
||||||
|
const noVotes = 60;
|
||||||
|
const yesEquityLikeShareWeight = '30';
|
||||||
|
const noEquityLikeShareWeight = '70';
|
||||||
|
// Note - giving a fixedTokenValue of 1 means a ratio of 1:1 votes to tokens, making sums easier :)
|
||||||
|
const fixedTokenValue = 1;
|
||||||
|
|
||||||
|
const proposal = generateProposal({
|
||||||
|
terms: {
|
||||||
|
change: {
|
||||||
|
__typename: 'UpdateMarket',
|
||||||
|
marketId: '12345',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
votes: {
|
||||||
|
__typename: 'ProposalVotes',
|
||||||
|
yes: generateYesVotes(
|
||||||
|
yesVotes,
|
||||||
|
fixedTokenValue,
|
||||||
|
yesEquityLikeShareWeight
|
||||||
|
),
|
||||||
|
no: generateNoVotes(noVotes, fixedTokenValue, noEquityLikeShareWeight),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
result: { current },
|
||||||
|
} = renderHook(() => useVoteInformation({ proposal }));
|
||||||
|
|
||||||
|
expect(current.requiredMajorityPercentage).toEqual(new BigNumber(50));
|
||||||
|
expect(current.requiredMajorityLPPercentage).toEqual(new BigNumber(50));
|
||||||
|
expect(current.noTokens).toEqual(new BigNumber(60));
|
||||||
|
expect(current.noVotes).toEqual(new BigNumber(60));
|
||||||
|
expect(current.noEquityLikeShareWeight).toEqual(new BigNumber(70));
|
||||||
|
expect(current.yesTokens).toEqual(new BigNumber(40));
|
||||||
|
expect(current.yesVotes).toEqual(new BigNumber(40));
|
||||||
|
expect(current.yesEquityLikeShareWeight).toEqual(new BigNumber(30));
|
||||||
|
expect(current.totalTokensVoted).toEqual(new BigNumber(100));
|
||||||
|
expect(current.totalVotes).toEqual(new BigNumber(100));
|
||||||
|
expect(current.totalEquityLikeShareWeight).toEqual(new BigNumber(100));
|
||||||
|
expect(current.yesPercentage).toEqual(new BigNumber(40));
|
||||||
|
expect(current.yesLPPercentage).toEqual(new BigNumber(30));
|
||||||
|
expect(current.noPercentage).toEqual(new BigNumber(60));
|
||||||
|
expect(current.noLPPercentage).toEqual(new BigNumber(70));
|
||||||
|
expect(current.requiredParticipation).toEqual(new BigNumber(50));
|
||||||
|
expect(current.participationMet).toEqual(true);
|
||||||
|
expect(current.requiredParticipationLP).toEqual(new BigNumber(50));
|
||||||
|
expect(current.participationLPMet).toEqual(true);
|
||||||
|
expect(current.majorityMet).toEqual(false);
|
||||||
|
expect(current.majorityLPMet).toEqual(false);
|
||||||
|
expect(current.totalTokensPercentage).toEqual(new BigNumber(100));
|
||||||
|
expect(current.totalLPTokensPercentage).toEqual(new BigNumber(100));
|
||||||
|
expect(current.willPassByTokenVote).toEqual(false);
|
||||||
|
expect(current.willPassByLPVote).toEqual(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('correctly returns majority, participation and will-pass status for a proposal with no votes', () => {
|
||||||
|
const yesVotes = 0;
|
||||||
|
const noVotes = 0;
|
||||||
|
const fixedTokenValue = 1;
|
||||||
|
|
||||||
|
const proposal = generateProposal({
|
||||||
|
votes: {
|
||||||
|
__typename: 'ProposalVotes',
|
||||||
|
yes: generateYesVotes(yesVotes, fixedTokenValue),
|
||||||
|
no: generateNoVotes(noVotes, fixedTokenValue),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
result: { current },
|
||||||
|
} = renderHook(() => useVoteInformation({ proposal }));
|
||||||
|
|
||||||
|
expect(current.participationMet).toEqual(false);
|
||||||
|
expect(current.majorityMet).toEqual(false);
|
||||||
|
expect(current.willPassByTokenVote).toEqual(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('correctly shows lack of participation for a failing proposal lacking votes', () => {
|
||||||
|
const yesVotes = 20;
|
||||||
|
const noVotes = 10;
|
||||||
|
const fixedTokenValue = 1;
|
||||||
|
|
||||||
|
const proposal = generateProposal({
|
||||||
|
votes: {
|
||||||
|
__typename: 'ProposalVotes',
|
||||||
|
yes: generateYesVotes(yesVotes, fixedTokenValue),
|
||||||
|
no: generateNoVotes(noVotes, fixedTokenValue),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
result: { current },
|
||||||
|
} = renderHook(() => useVoteInformation({ proposal }));
|
||||||
|
|
||||||
|
expect(current.participationMet).toEqual(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('correctly shows participation but lack of majority for a failing proposal with enough votes but not enough majority', () => {
|
||||||
|
const yesVotes = 20;
|
||||||
|
const noVotes = 70;
|
||||||
|
const fixedTokenValue = 1;
|
||||||
|
|
||||||
|
const proposal = generateProposal({
|
||||||
|
votes: {
|
||||||
|
__typename: 'ProposalVotes',
|
||||||
|
yes: generateYesVotes(yesVotes, fixedTokenValue),
|
||||||
|
no: generateNoVotes(noVotes, fixedTokenValue),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
result: { current },
|
||||||
|
} = renderHook(() => useVoteInformation({ proposal }));
|
||||||
|
|
||||||
|
expect(current.participationMet).toEqual(true);
|
||||||
|
expect(current.majorityMet).toEqual(false);
|
||||||
|
expect(current.willPassByTokenVote).toEqual(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('correctly shows participation, majority and will-pass data for successful proposal', () => {
|
||||||
|
const yesVotes = 70;
|
||||||
|
const noVotes = 20;
|
||||||
|
const fixedTokenValue = 1;
|
||||||
|
|
||||||
|
const proposal = generateProposal({
|
||||||
|
votes: {
|
||||||
|
__typename: 'ProposalVotes',
|
||||||
|
yes: generateYesVotes(yesVotes, fixedTokenValue),
|
||||||
|
no: generateNoVotes(noVotes, fixedTokenValue),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
result: { current },
|
||||||
|
} = renderHook(() => useVoteInformation({ proposal }));
|
||||||
|
|
||||||
|
expect(current.participationMet).toEqual(true);
|
||||||
|
expect(current.majorityMet).toEqual(true);
|
||||||
|
expect(current.willPassByTokenVote).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('correctly shows whether an update market proposal will pass by token or LP vote - both failing', () => {
|
||||||
|
const yesVotes = 20;
|
||||||
|
const noVotes = 70;
|
||||||
|
const yesEquityLikeShareWeight = '30';
|
||||||
|
const noEquityLikeShareWeight = '60';
|
||||||
|
const fixedTokenValue = 1;
|
||||||
|
|
||||||
|
const proposal = generateProposal({
|
||||||
|
terms: {
|
||||||
|
change: {
|
||||||
|
__typename: 'UpdateMarket',
|
||||||
|
marketId: '12345',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
votes: {
|
||||||
|
__typename: 'ProposalVotes',
|
||||||
|
yes: generateYesVotes(
|
||||||
|
yesVotes,
|
||||||
|
fixedTokenValue,
|
||||||
|
yesEquityLikeShareWeight
|
||||||
|
),
|
||||||
|
no: generateNoVotes(noVotes, fixedTokenValue, noEquityLikeShareWeight),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
result: { current },
|
||||||
|
} = renderHook(() => useVoteInformation({ proposal }));
|
||||||
|
|
||||||
|
expect(current.willPassByTokenVote).toEqual(false);
|
||||||
|
expect(current.willPassByLPVote).toEqual(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('correctly shows whether an update market proposal failing token but passing LP voting', () => {
|
||||||
|
const yesVotes = 0;
|
||||||
|
const noVotes = 70;
|
||||||
|
const yesEquityLikeShareWeight = '80';
|
||||||
|
const noEquityLikeShareWeight = '20';
|
||||||
|
const fixedTokenValue = 1;
|
||||||
|
|
||||||
|
const proposal = generateProposal({
|
||||||
|
terms: {
|
||||||
|
change: {
|
||||||
|
__typename: 'UpdateMarket',
|
||||||
|
marketId: '12345',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
votes: {
|
||||||
|
__typename: 'ProposalVotes',
|
||||||
|
yes: generateYesVotes(
|
||||||
|
yesVotes,
|
||||||
|
fixedTokenValue,
|
||||||
|
yesEquityLikeShareWeight
|
||||||
|
),
|
||||||
|
no: generateNoVotes(noVotes, fixedTokenValue, noEquityLikeShareWeight),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
result: { current },
|
||||||
|
} = renderHook(() => useVoteInformation({ proposal }));
|
||||||
|
|
||||||
|
expect(current.willPassByTokenVote).toEqual(false);
|
||||||
|
expect(current.willPassByLPVote).toEqual(true);
|
||||||
|
});
|
||||||
|
});
|
@ -1,162 +1,198 @@
|
|||||||
import { useNetworkParams, NetworkParams } from '@vegaprotocol/react-helpers';
|
import { useMemo } from 'react';
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
import { useAppState } from '../../../contexts/app-state/app-state-context';
|
import { useAppState } from '../../../contexts/app-state/app-state-context';
|
||||||
import { BigNumber } from '../../../lib/bignumber';
|
import { BigNumber } from '../../../lib/bignumber';
|
||||||
import type { ProposalFields } from '../__generated__/ProposalFields';
|
import { useProposalNetworkParams } from './use-proposal-network-params';
|
||||||
|
import type { Proposal_proposal } from '../proposal/__generated__/Proposal';
|
||||||
const useProposalNetworkParams = ({
|
|
||||||
proposal,
|
|
||||||
}: {
|
|
||||||
proposal: ProposalFields;
|
|
||||||
}) => {
|
|
||||||
const { params } = useNetworkParams([
|
|
||||||
NetworkParams.governance_proposal_updateMarket_requiredMajority,
|
|
||||||
NetworkParams.governance_proposal_updateMarket_requiredParticipation,
|
|
||||||
NetworkParams.governance_proposal_market_requiredMajority,
|
|
||||||
NetworkParams.governance_proposal_market_requiredParticipation,
|
|
||||||
NetworkParams.governance_proposal_asset_requiredMajority,
|
|
||||||
NetworkParams.governance_proposal_asset_requiredParticipation,
|
|
||||||
NetworkParams.governance_proposal_updateNetParam_requiredMajority,
|
|
||||||
NetworkParams.governance_proposal_updateNetParam_requiredParticipation,
|
|
||||||
NetworkParams.governance_proposal_freeform_requiredMajority,
|
|
||||||
NetworkParams.governance_proposal_freeform_requiredParticipation,
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (!params) {
|
|
||||||
return {
|
|
||||||
requiredMajority: new BigNumber(1),
|
|
||||||
requiredParticipation: new BigNumber(1),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (proposal.terms.change.__typename) {
|
|
||||||
case 'UpdateMarket':
|
|
||||||
return {
|
|
||||||
requiredMajority:
|
|
||||||
params.governance_proposal_updateMarket_requiredMajority,
|
|
||||||
requiredParticipation: new BigNumber(
|
|
||||||
params.governance_proposal_updateMarket_requiredParticipation
|
|
||||||
),
|
|
||||||
};
|
|
||||||
case 'UpdateNetworkParameter':
|
|
||||||
return {
|
|
||||||
requiredMajority:
|
|
||||||
params.governance_proposal_updateNetParam_requiredMajority,
|
|
||||||
requiredParticipation: new BigNumber(
|
|
||||||
params.governance_proposal_updateNetParam_requiredParticipation
|
|
||||||
),
|
|
||||||
};
|
|
||||||
case 'NewAsset':
|
|
||||||
return {
|
|
||||||
requiredMajority: params.governance_proposal_asset_requiredMajority,
|
|
||||||
requiredParticipation: new BigNumber(
|
|
||||||
params.governance_proposal_asset_requiredParticipation
|
|
||||||
),
|
|
||||||
};
|
|
||||||
case 'NewMarket':
|
|
||||||
return {
|
|
||||||
requiredMajority: params.governance_proposal_market_requiredMajority,
|
|
||||||
requiredParticipation: new BigNumber(
|
|
||||||
params.governance_proposal_market_requiredParticipation
|
|
||||||
),
|
|
||||||
};
|
|
||||||
case 'NewFreeform':
|
|
||||||
return {
|
|
||||||
requiredMajority: params.governance_proposal_freeform_requiredMajority,
|
|
||||||
requiredParticipation: new BigNumber(
|
|
||||||
params.governance_proposal_freeform_requiredParticipation
|
|
||||||
),
|
|
||||||
};
|
|
||||||
default:
|
|
||||||
throw new Error('Unknown proposal type');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useVoteInformation = ({
|
export const useVoteInformation = ({
|
||||||
proposal,
|
proposal,
|
||||||
}: {
|
}: {
|
||||||
proposal: ProposalFields;
|
proposal: Proposal_proposal;
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const {
|
||||||
appState: { totalSupply },
|
appState: { totalSupply },
|
||||||
} = useAppState();
|
} = useAppState();
|
||||||
|
|
||||||
const { requiredMajority, requiredParticipation } = useProposalNetworkParams({
|
const {
|
||||||
|
requiredMajority,
|
||||||
|
requiredParticipation,
|
||||||
|
requiredMajorityLP,
|
||||||
|
requiredParticipationLP,
|
||||||
|
} = useProposalNetworkParams({
|
||||||
proposal,
|
proposal,
|
||||||
});
|
});
|
||||||
|
|
||||||
const requiredMajorityPercentage = React.useMemo(
|
const {
|
||||||
() =>
|
requiredMajorityPercentage,
|
||||||
requiredMajority
|
requiredMajorityLPPercentage,
|
||||||
? new BigNumber(requiredMajority).times(100)
|
noTokens,
|
||||||
: new BigNumber(100),
|
noEquityLikeShareWeight,
|
||||||
[requiredMajority]
|
yesTokens,
|
||||||
);
|
yesEquityLikeShareWeight,
|
||||||
|
totalTokensVoted,
|
||||||
|
totalEquityLikeShareWeight,
|
||||||
|
yesPercentage,
|
||||||
|
yesLPPercentage,
|
||||||
|
noPercentage,
|
||||||
|
noLPPercentage,
|
||||||
|
participationMet,
|
||||||
|
participationLPMet,
|
||||||
|
majorityMet,
|
||||||
|
majorityLPMet,
|
||||||
|
totalTokensPercentage,
|
||||||
|
totalLPTokensPercentage,
|
||||||
|
willPassByTokenVote,
|
||||||
|
willPassByLPVote,
|
||||||
|
} = useMemo(() => {
|
||||||
|
const requiredMajorityPercentage = requiredMajority
|
||||||
|
? new BigNumber(requiredMajority).times(100)
|
||||||
|
: new BigNumber(100);
|
||||||
|
|
||||||
const noTokens = React.useMemo(() => {
|
const requiredMajorityLPPercentage = requiredMajorityLP
|
||||||
return new BigNumber(proposal.votes.no.totalTokens);
|
? new BigNumber(requiredMajorityLP).times(100)
|
||||||
}, [proposal.votes.no.totalTokens]);
|
: new BigNumber(100);
|
||||||
|
|
||||||
const yesTokens = React.useMemo(() => {
|
const noTokens = new BigNumber(proposal.votes.no.totalTokens);
|
||||||
return new BigNumber(proposal.votes.yes.totalTokens);
|
|
||||||
}, [proposal.votes.yes.totalTokens]);
|
|
||||||
|
|
||||||
const totalTokensVoted = React.useMemo(
|
const noEquityLikeShareWeight = !proposal.votes.no
|
||||||
() => yesTokens.plus(noTokens),
|
.totalEquityLikeShareWeight
|
||||||
[yesTokens, noTokens]
|
? new BigNumber(0)
|
||||||
);
|
: new BigNumber(proposal.votes.no.totalEquityLikeShareWeight);
|
||||||
const yesPercentage = React.useMemo(
|
|
||||||
() =>
|
|
||||||
totalTokensVoted.isZero()
|
|
||||||
? new BigNumber(0)
|
|
||||||
: yesTokens.multipliedBy(100).dividedBy(totalTokensVoted),
|
|
||||||
[totalTokensVoted, yesTokens]
|
|
||||||
);
|
|
||||||
const noPercentage = React.useMemo(
|
|
||||||
() =>
|
|
||||||
totalTokensVoted.isZero()
|
|
||||||
? new BigNumber(0)
|
|
||||||
: noTokens.multipliedBy(100).dividedBy(totalTokensVoted),
|
|
||||||
[noTokens, totalTokensVoted]
|
|
||||||
);
|
|
||||||
const participationMet = React.useMemo(() => {
|
|
||||||
const tokensNeeded = totalSupply.multipliedBy(requiredParticipation);
|
|
||||||
return totalTokensVoted.isGreaterThan(tokensNeeded);
|
|
||||||
}, [requiredParticipation, totalTokensVoted, totalSupply]);
|
|
||||||
|
|
||||||
const majorityMet = React.useMemo(() => {
|
const yesTokens = new BigNumber(proposal.votes.yes.totalTokens);
|
||||||
return yesPercentage.isGreaterThanOrEqualTo(requiredMajorityPercentage);
|
|
||||||
}, [yesPercentage, requiredMajorityPercentage]);
|
|
||||||
|
|
||||||
const totalTokensPercentage = React.useMemo(() => {
|
const yesEquityLikeShareWeight = !proposal.votes.yes
|
||||||
return totalTokensVoted.multipliedBy(100).dividedBy(totalSupply);
|
.totalEquityLikeShareWeight
|
||||||
}, [totalTokensVoted, totalSupply]);
|
? new BigNumber(0)
|
||||||
|
: new BigNumber(proposal.votes.yes.totalEquityLikeShareWeight);
|
||||||
|
|
||||||
const willPass = React.useMemo(
|
const totalTokensVoted = yesTokens.plus(noTokens);
|
||||||
() =>
|
|
||||||
|
const totalEquityLikeShareWeight = yesEquityLikeShareWeight.plus(
|
||||||
|
noEquityLikeShareWeight
|
||||||
|
);
|
||||||
|
|
||||||
|
const yesPercentage = totalTokensVoted.isZero()
|
||||||
|
? new BigNumber(0)
|
||||||
|
: yesTokens.multipliedBy(100).dividedBy(totalTokensVoted);
|
||||||
|
|
||||||
|
const yesLPPercentage = totalEquityLikeShareWeight.isZero()
|
||||||
|
? new BigNumber(0)
|
||||||
|
: yesEquityLikeShareWeight
|
||||||
|
.multipliedBy(100)
|
||||||
|
.dividedBy(totalEquityLikeShareWeight);
|
||||||
|
|
||||||
|
const noPercentage = totalTokensVoted.isZero()
|
||||||
|
? new BigNumber(0)
|
||||||
|
: noTokens.multipliedBy(100).dividedBy(totalTokensVoted);
|
||||||
|
|
||||||
|
const noLPPercentage = totalEquityLikeShareWeight.isZero()
|
||||||
|
? new BigNumber(0)
|
||||||
|
: noEquityLikeShareWeight
|
||||||
|
.multipliedBy(100)
|
||||||
|
.dividedBy(totalEquityLikeShareWeight);
|
||||||
|
|
||||||
|
const participationMet = totalTokensVoted.isGreaterThan(
|
||||||
|
totalSupply.multipliedBy(requiredParticipation)
|
||||||
|
);
|
||||||
|
|
||||||
|
const participationLPMet = requiredParticipationLP
|
||||||
|
? totalEquityLikeShareWeight.isGreaterThan(
|
||||||
|
totalSupply.multipliedBy(requiredParticipationLP)
|
||||||
|
)
|
||||||
|
: false;
|
||||||
|
|
||||||
|
const majorityMet = yesPercentage.isGreaterThanOrEqualTo(
|
||||||
|
requiredMajorityPercentage
|
||||||
|
);
|
||||||
|
|
||||||
|
const majorityLPMet = yesLPPercentage.isGreaterThanOrEqualTo(
|
||||||
|
requiredMajorityLPPercentage
|
||||||
|
);
|
||||||
|
|
||||||
|
const totalTokensPercentage = totalTokensVoted
|
||||||
|
.multipliedBy(100)
|
||||||
|
.dividedBy(totalSupply);
|
||||||
|
|
||||||
|
const totalLPTokensPercentage = totalEquityLikeShareWeight
|
||||||
|
.multipliedBy(100)
|
||||||
|
.dividedBy(totalSupply);
|
||||||
|
|
||||||
|
const willPassByTokenVote =
|
||||||
participationMet &&
|
participationMet &&
|
||||||
new BigNumber(yesPercentage).isGreaterThanOrEqualTo(
|
new BigNumber(yesPercentage).isGreaterThanOrEqualTo(
|
||||||
requiredMajorityPercentage
|
requiredMajorityPercentage
|
||||||
),
|
);
|
||||||
[participationMet, requiredMajorityPercentage, yesPercentage]
|
|
||||||
);
|
const willPassByLPVote =
|
||||||
|
participationLPMet &&
|
||||||
|
new BigNumber(yesLPPercentage).isGreaterThanOrEqualTo(
|
||||||
|
requiredMajorityLPPercentage
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
requiredMajorityPercentage,
|
||||||
|
requiredMajorityLPPercentage,
|
||||||
|
noTokens,
|
||||||
|
noEquityLikeShareWeight,
|
||||||
|
yesTokens,
|
||||||
|
yesEquityLikeShareWeight,
|
||||||
|
totalTokensVoted,
|
||||||
|
totalEquityLikeShareWeight,
|
||||||
|
yesPercentage,
|
||||||
|
yesLPPercentage,
|
||||||
|
noPercentage,
|
||||||
|
noLPPercentage,
|
||||||
|
participationMet,
|
||||||
|
participationLPMet,
|
||||||
|
majorityMet,
|
||||||
|
majorityLPMet,
|
||||||
|
totalTokensPercentage,
|
||||||
|
totalLPTokensPercentage,
|
||||||
|
willPassByTokenVote,
|
||||||
|
willPassByLPVote,
|
||||||
|
};
|
||||||
|
}, [
|
||||||
|
proposal.votes.no.totalEquityLikeShareWeight,
|
||||||
|
proposal.votes.no.totalTokens,
|
||||||
|
proposal.votes.yes.totalEquityLikeShareWeight,
|
||||||
|
proposal.votes.yes.totalTokens,
|
||||||
|
requiredMajority,
|
||||||
|
requiredMajorityLP,
|
||||||
|
requiredParticipation,
|
||||||
|
requiredParticipationLP,
|
||||||
|
totalSupply,
|
||||||
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
willPass,
|
willPassByTokenVote,
|
||||||
|
willPassByLPVote,
|
||||||
totalTokensPercentage,
|
totalTokensPercentage,
|
||||||
|
totalLPTokensPercentage,
|
||||||
participationMet,
|
participationMet,
|
||||||
|
participationLPMet,
|
||||||
totalTokensVoted,
|
totalTokensVoted,
|
||||||
|
totalEquityLikeShareWeight,
|
||||||
noPercentage,
|
noPercentage,
|
||||||
|
noLPPercentage,
|
||||||
yesPercentage,
|
yesPercentage,
|
||||||
|
yesLPPercentage,
|
||||||
noTokens,
|
noTokens,
|
||||||
|
noEquityLikeShareWeight,
|
||||||
yesTokens,
|
yesTokens,
|
||||||
|
yesEquityLikeShareWeight,
|
||||||
yesVotes: new BigNumber(proposal.votes.yes.totalNumber),
|
yesVotes: new BigNumber(proposal.votes.yes.totalNumber),
|
||||||
noVotes: new BigNumber(proposal.votes.no.totalNumber),
|
noVotes: new BigNumber(proposal.votes.no.totalNumber),
|
||||||
totalVotes: new BigNumber(proposal.votes.yes.totalNumber).plus(
|
totalVotes: new BigNumber(proposal.votes.yes.totalNumber).plus(
|
||||||
proposal.votes.no.totalNumber
|
proposal.votes.no.totalNumber
|
||||||
),
|
),
|
||||||
requiredMajorityPercentage,
|
requiredMajorityPercentage,
|
||||||
|
requiredMajorityLPPercentage,
|
||||||
requiredParticipation: new BigNumber(requiredParticipation).times(100),
|
requiredParticipation: new BigNumber(requiredParticipation).times(100),
|
||||||
|
requiredParticipationLP:
|
||||||
|
requiredParticipationLP &&
|
||||||
|
new BigNumber(requiredParticipationLP).times(100),
|
||||||
majorityMet,
|
majorityMet,
|
||||||
|
majorityLPMet,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -645,6 +645,10 @@ export interface Proposal_proposal_votes_yes {
|
|||||||
* Total number of votes cast for this side
|
* Total number of votes cast for this side
|
||||||
*/
|
*/
|
||||||
totalNumber: string;
|
totalNumber: string;
|
||||||
|
/**
|
||||||
|
* Total equity like share weight for this side (only for UpdateMarket Proposals)
|
||||||
|
*/
|
||||||
|
totalEquityLikeShareWeight: string;
|
||||||
/**
|
/**
|
||||||
* All votes cast for this side
|
* All votes cast for this side
|
||||||
*/
|
*/
|
||||||
@ -697,6 +701,10 @@ export interface Proposal_proposal_votes_no {
|
|||||||
* Total number of votes cast for this side
|
* Total number of votes cast for this side
|
||||||
*/
|
*/
|
||||||
totalNumber: string;
|
totalNumber: string;
|
||||||
|
/**
|
||||||
|
* Total equity like share weight for this side (only for UpdateMarket Proposals)
|
||||||
|
*/
|
||||||
|
totalEquityLikeShareWeight: string;
|
||||||
/**
|
/**
|
||||||
* All votes cast for this side
|
* All votes cast for this side
|
||||||
*/
|
*/
|
||||||
|
@ -192,6 +192,7 @@ export const PROPOSAL_QUERY = gql`
|
|||||||
yes {
|
yes {
|
||||||
totalTokens
|
totalTokens
|
||||||
totalNumber
|
totalNumber
|
||||||
|
totalEquityLikeShareWeight
|
||||||
votes {
|
votes {
|
||||||
value
|
value
|
||||||
party {
|
party {
|
||||||
@ -206,6 +207,7 @@ export const PROPOSAL_QUERY = gql`
|
|||||||
no {
|
no {
|
||||||
totalTokens
|
totalTokens
|
||||||
totalNumber
|
totalNumber
|
||||||
|
totalEquityLikeShareWeight
|
||||||
votes {
|
votes {
|
||||||
value
|
value
|
||||||
party {
|
party {
|
||||||
|
@ -231,6 +231,10 @@ export interface ProposalFields_votes_yes {
|
|||||||
* Total number of votes cast for this side
|
* Total number of votes cast for this side
|
||||||
*/
|
*/
|
||||||
totalNumber: string;
|
totalNumber: string;
|
||||||
|
/**
|
||||||
|
* Total equity like share weight for this side (only for UpdateMarket Proposals)
|
||||||
|
*/
|
||||||
|
totalEquityLikeShareWeight: string;
|
||||||
/**
|
/**
|
||||||
* All votes cast for this side
|
* All votes cast for this side
|
||||||
*/
|
*/
|
||||||
@ -283,6 +287,10 @@ export interface ProposalFields_votes_no {
|
|||||||
* Total number of votes cast for this side
|
* Total number of votes cast for this side
|
||||||
*/
|
*/
|
||||||
totalNumber: string;
|
totalNumber: string;
|
||||||
|
/**
|
||||||
|
* Total equity like share weight for this side (only for UpdateMarket Proposals)
|
||||||
|
*/
|
||||||
|
totalEquityLikeShareWeight: string;
|
||||||
/**
|
/**
|
||||||
* All votes cast for this side
|
* All votes cast for this side
|
||||||
*/
|
*/
|
||||||
|
@ -231,6 +231,10 @@ export interface Proposals_proposalsConnection_edges_node_votes_yes {
|
|||||||
* Total number of votes cast for this side
|
* Total number of votes cast for this side
|
||||||
*/
|
*/
|
||||||
totalNumber: string;
|
totalNumber: string;
|
||||||
|
/**
|
||||||
|
* Total equity like share weight for this side (only for UpdateMarket Proposals)
|
||||||
|
*/
|
||||||
|
totalEquityLikeShareWeight: string;
|
||||||
/**
|
/**
|
||||||
* All votes cast for this side
|
* All votes cast for this side
|
||||||
*/
|
*/
|
||||||
@ -283,6 +287,10 @@ export interface Proposals_proposalsConnection_edges_node_votes_no {
|
|||||||
* Total number of votes cast for this side
|
* Total number of votes cast for this side
|
||||||
*/
|
*/
|
||||||
totalNumber: string;
|
totalNumber: string;
|
||||||
|
/**
|
||||||
|
* Total equity like share weight for this side (only for UpdateMarket Proposals)
|
||||||
|
*/
|
||||||
|
totalEquityLikeShareWeight: string;
|
||||||
/**
|
/**
|
||||||
* All votes cast for this side
|
* All votes cast for this side
|
||||||
*/
|
*/
|
||||||
|
@ -76,6 +76,7 @@ export const PROPOSAL_FRAGMENT = gql`
|
|||||||
yes {
|
yes {
|
||||||
totalTokens
|
totalTokens
|
||||||
totalNumber
|
totalNumber
|
||||||
|
totalEquityLikeShareWeight
|
||||||
votes {
|
votes {
|
||||||
value
|
value
|
||||||
party {
|
party {
|
||||||
@ -90,6 +91,7 @@ export const PROPOSAL_FRAGMENT = gql`
|
|||||||
no {
|
no {
|
||||||
totalTokens
|
totalTokens
|
||||||
totalNumber
|
totalNumber
|
||||||
|
totalEquityLikeShareWeight
|
||||||
votes {
|
votes {
|
||||||
value
|
value
|
||||||
party {
|
party {
|
||||||
|
@ -19,7 +19,7 @@ import { AsyncRenderer, Link } from '@vegaprotocol/ui-toolkit';
|
|||||||
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 { NetworkParams, useNetworkParams } from '@vegaprotocol/react-helpers';
|
import { NetworkParams, useNetworkParams } from '@vegaprotocol/react-helpers';
|
||||||
import { ProposalUserAction } from '@vegaprotocol/types';
|
import { ProposalUserAction } from '../../components/shared';
|
||||||
|
|
||||||
export interface FreeformProposalFormFields {
|
export interface FreeformProposalFormFields {
|
||||||
proposalVoteDeadline: string;
|
proposalVoteDeadline: string;
|
||||||
|
@ -33,7 +33,7 @@ import {
|
|||||||
} from '@vegaprotocol/ui-toolkit';
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
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 { ProposalUserAction } from '@vegaprotocol/types';
|
import { ProposalUserAction } from '../../components/shared';
|
||||||
|
|
||||||
interface SelectedNetworkParamCurrentValueProps {
|
interface SelectedNetworkParamCurrentValueProps {
|
||||||
value: string;
|
value: string;
|
||||||
|
@ -26,7 +26,7 @@ import { ProposalMinRequirements } from '../../components/shared';
|
|||||||
import { AsyncRenderer, Link } from '@vegaprotocol/ui-toolkit';
|
import { AsyncRenderer, Link } from '@vegaprotocol/ui-toolkit';
|
||||||
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 { ProposalUserAction } from '@vegaprotocol/types';
|
import { ProposalUserAction } from '../../components/shared';
|
||||||
|
|
||||||
export interface NewAssetProposalFormFields {
|
export interface NewAssetProposalFormFields {
|
||||||
proposalVoteDeadline: string;
|
proposalVoteDeadline: string;
|
||||||
|
@ -25,7 +25,7 @@ import { ProposalMinRequirements } from '../../components/shared';
|
|||||||
import { AsyncRenderer, Link } from '@vegaprotocol/ui-toolkit';
|
import { AsyncRenderer, Link } from '@vegaprotocol/ui-toolkit';
|
||||||
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 { ProposalUserAction } from '@vegaprotocol/types';
|
import { ProposalUserAction } from '../../components/shared';
|
||||||
|
|
||||||
export interface NewMarketProposalFormFields {
|
export interface NewMarketProposalFormFields {
|
||||||
proposalVoteDeadline: string;
|
proposalVoteDeadline: string;
|
||||||
|
@ -25,7 +25,7 @@ import { ProposalMinRequirements } from '../../components/shared';
|
|||||||
import { AsyncRenderer, Link } from '@vegaprotocol/ui-toolkit';
|
import { AsyncRenderer, Link } from '@vegaprotocol/ui-toolkit';
|
||||||
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 { ProposalUserAction } from '@vegaprotocol/types';
|
import { ProposalUserAction } from '../../components/shared';
|
||||||
|
|
||||||
export interface UpdateAssetProposalFormFields {
|
export interface UpdateAssetProposalFormFields {
|
||||||
proposalVoteDeadline: string;
|
proposalVoteDeadline: string;
|
||||||
|
@ -36,7 +36,7 @@ import {
|
|||||||
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 type { ProposalMarketsQuery } from './__generated__/ProposalMarketsQuery';
|
import type { ProposalMarketsQuery } from './__generated__/ProposalMarketsQuery';
|
||||||
import { ProposalUserAction } from '@vegaprotocol/types';
|
import { ProposalUserAction } from '../../components/shared';
|
||||||
|
|
||||||
export const MARKETS_QUERY = gql`
|
export const MARKETS_QUERY = gql`
|
||||||
query ProposalMarketsQuery {
|
query ProposalMarketsQuery {
|
||||||
|
@ -6,17 +6,17 @@ import mergeWith from 'lodash/mergeWith';
|
|||||||
|
|
||||||
import type { DeepPartial } from '../../../lib/type-helpers';
|
import type { DeepPartial } from '../../../lib/type-helpers';
|
||||||
import type {
|
import type {
|
||||||
ProposalFields,
|
Proposal_proposal,
|
||||||
ProposalFields_votes_no,
|
Proposal_proposal_votes_yes,
|
||||||
ProposalFields_votes_no_votes,
|
Proposal_proposal_votes_yes_votes,
|
||||||
ProposalFields_votes_yes,
|
Proposal_proposal_votes_no,
|
||||||
ProposalFields_votes_yes_votes,
|
Proposal_proposal_votes_no_votes,
|
||||||
} from '../__generated__/ProposalFields';
|
} from '../proposal/__generated__/Proposal';
|
||||||
|
|
||||||
export function generateProposal(
|
export function generateProposal(
|
||||||
override: DeepPartial<ProposalFields> = {}
|
override: DeepPartial<Proposal_proposal> = {}
|
||||||
): ProposalFields {
|
): Proposal_proposal {
|
||||||
const defaultProposal: ProposalFields = {
|
const defaultProposal: Proposal_proposal = {
|
||||||
__typename: 'Proposal',
|
__typename: 'Proposal',
|
||||||
id: faker.datatype.uuid(),
|
id: faker.datatype.uuid(),
|
||||||
rationale: {
|
rationale: {
|
||||||
@ -63,7 +63,7 @@ export function generateProposal(
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
return mergeWith<ProposalFields, DeepPartial<ProposalFields>>(
|
return mergeWith<Proposal_proposal, DeepPartial<Proposal_proposal>>(
|
||||||
defaultProposal,
|
defaultProposal,
|
||||||
override,
|
override,
|
||||||
(objValue, srcValue) => {
|
(objValue, srcValue) => {
|
||||||
@ -77,10 +77,11 @@ export function generateProposal(
|
|||||||
|
|
||||||
export const generateYesVotes = (
|
export const generateYesVotes = (
|
||||||
numberOfVotes = 5,
|
numberOfVotes = 5,
|
||||||
fixedTokenValue?: number
|
fixedTokenValue?: number,
|
||||||
): ProposalFields_votes_yes => {
|
totalEquityLikeShareWeight?: string
|
||||||
|
): Proposal_proposal_votes_yes => {
|
||||||
const votes = Array.from(Array(numberOfVotes)).map(() => {
|
const votes = Array.from(Array(numberOfVotes)).map(() => {
|
||||||
const vote: ProposalFields_votes_yes_votes = {
|
const vote: Proposal_proposal_votes_yes_votes = {
|
||||||
__typename: 'Vote',
|
__typename: 'Vote',
|
||||||
value: VoteValue.VALUE_YES,
|
value: VoteValue.VALUE_YES,
|
||||||
party: {
|
party: {
|
||||||
@ -112,15 +113,17 @@ export const generateYesVotes = (
|
|||||||
}, new BigNumber(0))
|
}, new BigNumber(0))
|
||||||
.toString(),
|
.toString(),
|
||||||
votes,
|
votes,
|
||||||
|
totalEquityLikeShareWeight: totalEquityLikeShareWeight || '0',
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const generateNoVotes = (
|
export const generateNoVotes = (
|
||||||
numberOfVotes = 5,
|
numberOfVotes = 5,
|
||||||
fixedTokenValue?: number
|
fixedTokenValue?: number,
|
||||||
): ProposalFields_votes_no => {
|
totalEquityLikeShareWeight?: string
|
||||||
|
): Proposal_proposal_votes_no => {
|
||||||
const votes = Array.from(Array(numberOfVotes)).map(() => {
|
const votes = Array.from(Array(numberOfVotes)).map(() => {
|
||||||
const vote: ProposalFields_votes_no_votes = {
|
const vote: Proposal_proposal_votes_no_votes = {
|
||||||
__typename: 'Vote',
|
__typename: 'Vote',
|
||||||
value: VoteValue.VALUE_NO,
|
value: VoteValue.VALUE_NO,
|
||||||
party: {
|
party: {
|
||||||
@ -151,5 +154,6 @@ export const generateNoVotes = (
|
|||||||
}, new BigNumber(0))
|
}, new BigNumber(0))
|
||||||
.toString(),
|
.toString(),
|
||||||
votes,
|
votes,
|
||||||
|
totalEquityLikeShareWeight: totalEquityLikeShareWeight || '0',
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -35,6 +35,8 @@ export const NetworkParams = {
|
|||||||
'governance_proposal_updateMarket_minVoterBalance',
|
'governance_proposal_updateMarket_minVoterBalance',
|
||||||
governance_proposal_updateMarket_requiredMajority:
|
governance_proposal_updateMarket_requiredMajority:
|
||||||
'governance_proposal_updateMarket_requiredMajority',
|
'governance_proposal_updateMarket_requiredMajority',
|
||||||
|
governance_proposal_updateMarket_requiredMajorityLP:
|
||||||
|
'governance_proposal_updateMarket_requiredMajorityLP',
|
||||||
governance_proposal_updateMarket_minClose:
|
governance_proposal_updateMarket_minClose:
|
||||||
'governance_proposal_updateMarket_minClose',
|
'governance_proposal_updateMarket_minClose',
|
||||||
governance_proposal_updateMarket_maxClose:
|
governance_proposal_updateMarket_maxClose:
|
||||||
@ -77,6 +79,8 @@ export const NetworkParams = {
|
|||||||
'governance_proposal_freeform_maxClose',
|
'governance_proposal_freeform_maxClose',
|
||||||
governance_proposal_updateMarket_requiredParticipation:
|
governance_proposal_updateMarket_requiredParticipation:
|
||||||
'governance_proposal_updateMarket_requiredParticipation',
|
'governance_proposal_updateMarket_requiredParticipation',
|
||||||
|
governance_proposal_updateMarket_requiredParticipationLP:
|
||||||
|
'governance_proposal_updateMarket_requiredParticipationLP',
|
||||||
governance_proposal_updateMarket_minProposerBalance:
|
governance_proposal_updateMarket_minProposerBalance:
|
||||||
'governance_proposal_updateMarket_minProposerBalance',
|
'governance_proposal_updateMarket_minProposerBalance',
|
||||||
governance_proposal_market_requiredMajority:
|
governance_proposal_market_requiredMajority:
|
||||||
@ -89,6 +93,10 @@ export const NetworkParams = {
|
|||||||
'governance_proposal_asset_requiredMajority',
|
'governance_proposal_asset_requiredMajority',
|
||||||
governance_proposal_asset_requiredParticipation:
|
governance_proposal_asset_requiredParticipation:
|
||||||
'governance_proposal_asset_requiredParticipation',
|
'governance_proposal_asset_requiredParticipation',
|
||||||
|
governance_proposal_updateAsset_requiredMajority:
|
||||||
|
'governance_proposal_updateAsset_requiredMajority',
|
||||||
|
governance_proposal_updateAsset_requiredParticipation:
|
||||||
|
'governance_proposal_updateAsset_requiredParticipation',
|
||||||
governance_proposal_asset_minProposerBalance:
|
governance_proposal_asset_minProposerBalance:
|
||||||
'governance_proposal_asset_minProposerBalance',
|
'governance_proposal_asset_minProposerBalance',
|
||||||
governance_proposal_updateAsset_minProposerBalance:
|
governance_proposal_updateAsset_minProposerBalance:
|
||||||
|
@ -31,6 +31,7 @@ export * from './syntax-highlighter';
|
|||||||
export * from './tabs';
|
export * from './tabs';
|
||||||
export * from './text-area';
|
export * from './text-area';
|
||||||
export * from './theme-switcher';
|
export * from './theme-switcher';
|
||||||
|
export * from './thumbs';
|
||||||
export * from './toggle';
|
export * from './toggle';
|
||||||
export * from './tooltip';
|
export * from './tooltip';
|
||||||
export * from './vega-icons';
|
export * from './vega-icons';
|
||||||
|
1
libs/ui-toolkit/src/components/thumbs/index.tsx
Normal file
1
libs/ui-toolkit/src/components/thumbs/index.tsx
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './thumbs';
|
19
libs/ui-toolkit/src/components/thumbs/thumbs.spec.tsx
Normal file
19
libs/ui-toolkit/src/components/thumbs/thumbs.spec.tsx
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { render, screen } from '@testing-library/react';
|
||||||
|
import { Thumbs } from './thumbs';
|
||||||
|
|
||||||
|
describe('Thumbs', () => {
|
||||||
|
it('renders up', () => {
|
||||||
|
render(<Thumbs up={true} />);
|
||||||
|
expect(screen.getByText('👍')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders down', () => {
|
||||||
|
render(<Thumbs up={false} />);
|
||||||
|
expect(screen.getByText('👎')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders text', () => {
|
||||||
|
render(<Thumbs up={true} text="test" />);
|
||||||
|
expect(screen.getByText('👍 test')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
26
libs/ui-toolkit/src/components/thumbs/thumbs.stories.tsx
Normal file
26
libs/ui-toolkit/src/components/thumbs/thumbs.stories.tsx
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { Thumbs } from './thumbs';
|
||||||
|
import type { ThumbsProps } from './thumbs';
|
||||||
|
import type { Meta, Story } from '@storybook/react';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
component: Thumbs,
|
||||||
|
title: 'Thumbs',
|
||||||
|
} as Meta;
|
||||||
|
|
||||||
|
const Template: Story<ThumbsProps> = (args) => <Thumbs {...args} />;
|
||||||
|
|
||||||
|
export const Up = Template.bind({});
|
||||||
|
Up.args = {
|
||||||
|
up: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Down = Template.bind({});
|
||||||
|
Down.args = {
|
||||||
|
up: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const WithText = Template.bind({});
|
||||||
|
WithText.args = {
|
||||||
|
up: true,
|
||||||
|
text: 'description text',
|
||||||
|
};
|
12
libs/ui-toolkit/src/components/thumbs/thumbs.tsx
Normal file
12
libs/ui-toolkit/src/components/thumbs/thumbs.tsx
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
export interface ThumbsProps {
|
||||||
|
up: boolean;
|
||||||
|
text?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Thumbs = ({ up, text }: ThumbsProps) => {
|
||||||
|
return (
|
||||||
|
<span>
|
||||||
|
{up ? '👍' : '👎'} {text}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user