diff --git a/apps/governance-e2e/.env b/apps/governance-e2e/.env index 51b30c340..347136e3a 100644 --- a/apps/governance-e2e/.env +++ b/apps/governance-e2e/.env @@ -18,6 +18,7 @@ NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/annou NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72 NX_VEGA_REST_URL=http://localhost:3008/api/v2/ +NX_SUCCESSOR_MARKETS=true #Test configuration variables CYPRESS_FAIRGROUND=false diff --git a/apps/governance-e2e/src/integration/flow/proposal-details.cy.ts b/apps/governance-e2e/src/integration/flow/proposal-details.cy.ts index cb064a749..ca8a61e33 100644 --- a/apps/governance-e2e/src/integration/flow/proposal-details.cy.ts +++ b/apps/governance-e2e/src/integration/flow/proposal-details.cy.ts @@ -11,7 +11,9 @@ import { getDateFormatForSpecifiedDays, getProposalFromTitle, getProposalInformationFromTable, + proposalChangeType, submitUniqueRawProposal, + validateProposalDetailsDiff, voteForProposal, } from '../../../../governance-e2e/src/support/governance.functions'; import { @@ -26,7 +28,9 @@ import { } from '../../support/wallet-functions'; import type { testFreeformProposal } from '../../support/common-interfaces'; import { formatDateWithLocalTimezone } from '@vegaprotocol/utils'; +import { createSuccessorMarketProposalTxBody } from '../../support/proposal.functions'; +const proposalListItem = '[data-testid="proposals-list-item"]'; const proposalVoteProgressForPercentage = 'vote-progress-indicator-percentage-for'; const proposalVoteProgressAgainstPercentage = @@ -42,6 +46,7 @@ const viewProposalButton = 'view-proposal-btn'; const proposalDescriptionToggle = 'proposal-description-toggle'; const voteBreakdownToggle = 'vote-breakdown-toggle'; const proposalTermsToggle = 'proposal-json-toggle'; +const marketDataToggle = 'proposal-market-data-toggle'; describe( 'Governance flow for proposal details', @@ -354,5 +359,98 @@ describe( switchVegaWalletPubKey(); stakingPageDisassociateAllTokens(); }); + + it('Able to see successor market details with new and updated values', function () { + cy.createMarket(); + cy.reload(); + waitForSpinner(); + cy.getByTestId('closed-proposals').within(() => { + cy.contains('Add Lorem Ipsum market') + .parentsUntil(proposalListItem) + .last() + .within(() => { + cy.getByTestId(viewProposalButton).click(); + }); + }); + getProposalInformationFromTable('ID') + .invoke('text') + .as('parentMarketId') + .then(() => { + cy.VegaWalletSubmitProposal( + createSuccessorMarketProposalTxBody(this.parentMarketId) + ); + }); + navigateTo(navigation.proposals); + cy.reload(); + getProposalFromTitle('Test successor market proposal details').within( + () => cy.getByTestId(viewProposalButton).click() + ); + // #3003-PMAN-010 + cy.getByTestId(proposalTermsToggle).click(); + cy.get('.language-json').within(() => { + cy.get('.hljs-attr').should('contain.text', 'parentMarketId'); + cy.get('.hljs-string').should('contain.text', this.parentMarketId); + cy.get('.hljs-attr').should('contain.text', 'insurancePoolFraction'); + cy.get('.hljs-string').should('contain.text', '0.75'); + }); + // 3003-PMAN-011 3003-PMAN-012 + cy.getByTestId(marketDataToggle).click(); + cy.getByTestId('proposal-market-data').within(() => { + cy.contains('Key details').click(); + validateProposalDetailsDiff( + 'Name', + proposalChangeType.UPDATED, + 'Token test market', + 'Test market 1' + ); + validateProposalDetailsDiff( + 'Parent Market ID', + proposalChangeType.ADDED, + this.parentMarketId + ); + validateProposalDetailsDiff( + 'Insurance Pool Fraction', + proposalChangeType.ADDED, + '0.75' + ); + validateProposalDetailsDiff( + 'Trading Mode', + proposalChangeType.UPDATED, + 'No trading', + 'Opening auction' + ); + + cy.contains('Instrument').click(); + validateProposalDetailsDiff( + 'Market Name', + proposalChangeType.UPDATED, + 'Token test market', + 'Test market 1' + ); + + cy.contains('Metadata').click(); + validateProposalDetailsDiff( + 'Sector', + proposalChangeType.UPDATED, + 'materials', + 'tech' + ); + }); + + // 3003-PMAN-011 + cy.get('.underline').contains('Parent Market ID').realHover(); + cy.getByTestId('tooltip-content', { timeout: 8000 }).should( + 'contain.text', + 'The ID of the market this market succeeds.' + ); + cy.get('.underline') + .contains('Insurance Pool Fraction') + .realMouseUp() + .realHover(); + cy.getByTestId('tooltip-content', { timeout: 8000 }).should( + 'contain.text', + 'The fraction of the insurance pool balance that is carried over from the parent market to the successor.' + ); + }); } ); diff --git a/apps/governance-e2e/src/integration/flow/proposal-forms.cy.ts b/apps/governance-e2e/src/integration/flow/proposal-forms.cy.ts index 4e9ec9784..a506de724 100644 --- a/apps/governance-e2e/src/integration/flow/proposal-forms.cy.ts +++ b/apps/governance-e2e/src/integration/flow/proposal-forms.cy.ts @@ -654,44 +654,7 @@ context( .find('a') .should('have.attr', 'href') .and('contain', this.parentMarketId); - cy.getByTestId('view-proposal-btn').click(); }); - // #3003-PMAN-010 - cy.getByTestId(proposalJsonToggle).click(); - cy.get('.language-json').within(() => { - cy.get('.hljs-attr').should('contain.text', 'parentMarketId'); - cy.get('.hljs-string').should('contain.text', this.parentMarketId); - cy.get('.hljs-attr').should('contain.text', 'insurancePoolFraction'); - cy.get('.hljs-string').should('contain.text', '0.75'); - }); - cy.getByTestId('proposal-market-data').within(() => { - cy.getByTestId('proposal-market-data-toggle').click(); - cy.contains('Key details').click(); - // 3003-PMAN-009 - getMarketProposalDetailsFromTable('Parent Market ID').should( - 'have.text', - this.parentMarketId - ); - getMarketProposalDetailsFromTable('Insurance Pool Fraction').should( - 'have.text', - '0.75' - ); - getMarketProposalDetailsFromTable('Trading Mode').should( - 'have.text', - 'No trading' - ); - }); - // 3003-PMAN-011 - cy.contains('Parent Market ID').realHover(); - cy.getByTestId('tooltip-content').should( - 'contain.text', - 'The ID of the market this market succeeds.' - ); - cy.contains('Insurance Pool Fraction').realHover(); - cy.getByTestId('tooltip-content').should( - 'contain.text', - 'The fraction of the insurance pool balance that is carried over from the parent market to the successor.' - ); }); after('Disassociate from second wallet key if present', function () { diff --git a/apps/governance-e2e/src/support/governance.functions.ts b/apps/governance-e2e/src/support/governance.functions.ts index dcd7dd7eb..f356e2935 100644 --- a/apps/governance-e2e/src/support/governance.functions.ts +++ b/apps/governance-e2e/src/support/governance.functions.ts @@ -232,6 +232,23 @@ export function getDownloadedProposalJsonPath(proposalType: string) { return filepath; } +export function validateProposalDetailsDiff( + RowName: string, + changeType: proposalChangeType, + newValue: string, + oldValue?: string +) { + cy.contains(RowName) + .parentsUntil(proposalInformationTableRows) + .parent() + .first() + .within(() => { + cy.contains(changeType).should('be.visible'); + cy.contains(newValue).should('be.visible'); + if (oldValue) cy.contains(oldValue).should('have.class', 'line-through'); + }); +} + function getFormattedTime() { const now = new Date(); const day = now.getDate().toString().padStart(2, '0'); @@ -252,3 +269,8 @@ export enum governanceProposalType { FREEFORM = 'Freeform', RAW = 'raw proposal', } + +export enum proposalChangeType { + UPDATED = 'Updated', + ADDED = 'Added', +} diff --git a/apps/governance-e2e/src/support/proposal.functions.ts b/apps/governance-e2e/src/support/proposal.functions.ts index 2ba270cd9..9da49a3eb 100644 --- a/apps/governance-e2e/src/support/proposal.functions.ts +++ b/apps/governance-e2e/src/support/proposal.functions.ts @@ -211,6 +211,143 @@ export function createNewMarketProposalTxBody(): ProposalSubmissionBody { }; } +// Requires cy.createMarket() to be run to set up parent market +export function createSuccessorMarketProposalTxBody( + parentMarketId: string +): ProposalSubmissionBody { + const MIN_CLOSE_SEC = 10000; + const MIN_ENACT_SEC = 10000; + + const closingDate = addSeconds(new Date(), MIN_CLOSE_SEC); + const enactmentDate = addSeconds(closingDate, MIN_ENACT_SEC); + const closingTimestamp = millisecondsToSeconds(closingDate.getTime()); + const enactmentTimestamp = millisecondsToSeconds(enactmentDate.getTime()); + return { + proposalSubmission: { + rationale: { + title: 'Test successor market proposal details', + description: 'E2E test for successor market', + }, + terms: { + newMarket: { + changes: { + decimalPlaces: '5', + positionDecimalPlaces: '5', + linearSlippageFactor: '0.001', + quadraticSlippageFactor: '0', + lpPriceRange: '10', + instrument: { + name: 'Token test market', + code: 'TEST.24h', + future: { + settlementAsset: + '816af99af60d684502a40824758f6b5377e6af48e50a9ee8ef478ecb879ea8bc', + quoteName: 'fUSDC', + dataSourceSpecForSettlementData: { + external: { + oracle: { + signers: [ + { + pubKey: { + key: '70d14a321e02e71992fd115563df765000ccc4775cbe71a0e2f9ff5a3b9dc680', + }, + }, + ], + filters: [ + { + key: { + name: 'prices.BTC.value', + type: 'TYPE_INTEGER' as const, + numberDecimalPlaces: '0', + }, + conditions: [ + { + operator: 'OPERATOR_GREATER_THAN' as const, + value: '0', + }, + ], + }, + ], + }, + }, + }, + dataSourceSpecForTradingTermination: { + external: { + oracle: { + signers: [ + { + pubKey: { + key: '70d14a321e02e71992fd115563df765000ccc4775cbe71a0e2f9ff5a3b9dc680', + }, + }, + ], + filters: [ + { + key: { + name: 'trading.terminated.ETH5', + type: 'TYPE_BOOLEAN' as const, + }, + conditions: [ + { + operator: 'OPERATOR_EQUALS' as const, + value: 'true', + }, + ], + }, + ], + }, + }, + }, + dataSourceSpecBinding: { + settlementDataProperty: 'prices.BTC.value', + tradingTerminationProperty: 'trading.terminated.ETH5', + }, + }, + }, + metadata: [ + 'sector:food', + 'sector:materials', + 'source:docs.vega.xyz', + ], + priceMonitoringParameters: { + triggers: [ + { + horizon: '43200', + probability: '0.9999999', + auctionExtension: '600', + }, + ], + }, + liquidityMonitoringParameters: { + targetStakeParameters: { + timeWindow: '3600', + scalingFactor: 10, + }, + triggeringRatio: '0.7', + auctionExtension: '1', + }, + logNormal: { + tau: 0.0001140771161, + riskAversionParameter: 0.01, + params: { + mu: 0, + r: 0.016, + sigma: 0.5, + }, + }, + successor: { + parentMarketId: parentMarketId, + insurancePoolFraction: '0.75', + }, + }, + }, + closingTimestamp, + enactmentTimestamp, + }, + }, + }; +} + export function mockNetworkUpgradeProposal() { cy.mockGQL((req) => { aliasGQLQuery(req, 'Nodes', nodeData); diff --git a/libs/wallet/src/connectors/vega-connector.ts b/libs/wallet/src/connectors/vega-connector.ts index 79d411345..dd82c8e55 100644 --- a/libs/wallet/src/connectors/vega-connector.ts +++ b/libs/wallet/src/connectors/vega-connector.ts @@ -154,6 +154,7 @@ interface ProposalNewMarketTerms { auctionExtension: string; }; logNormal: LogNormal; + successor?: Successor; }; }; closingTimestamp: number; @@ -298,6 +299,11 @@ interface Condition { value: string; } +interface Successor { + parentMarketId: string; + insurancePoolFraction: string; +} + interface LogNormal { tau: number; riskAversionParameter: number; diff --git a/specs/3003-PMAN-propose_new_market.md b/specs/3003-PMAN-propose_new_market.md index 27da6b758..04b93e383 100644 --- a/specs/3003-PMAN-propose_new_market.md +++ b/specs/3003-PMAN-propose_new_market.md @@ -32,4 +32,8 @@ - **must** I can see an explanation of what "Parent market ID" using a tooltip (3003-PMAN-011) If the proposal has been enacted, I can see the status of the market i.e. opening auction, continuous trading, rejected +- **must** be able to see the market specification with the proposed update (3003-PMAN-012) + +- **must** be a simple way to visually highlight / compare the difference with this market specification from the original markets specification (3003-PMAN-013) + back to [Propose](./3002-PROP-propose.md) for details on proposing