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