Compare commits
20
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6334b689b9 | ||
|
|
7b06d8a770 | ||
|
|
4ae721ebae | ||
|
|
11f9fcb307 | ||
|
|
fd338c7400 | ||
|
|
0db5d0ce87 | ||
|
|
42c316c8e1 | ||
|
|
9e2474d39a | ||
|
|
2533e5ec44 | ||
|
|
22a43249ea | ||
|
|
b40ee0caf5 | ||
|
|
95aca70434 | ||
|
|
5e13266250 | ||
|
|
5c0588887c | ||
|
|
089a7daac7 | ||
|
|
02b6251b1a | ||
|
|
9ce8907861 | ||
|
|
3be9126906 | ||
|
|
77316092d1 | ||
|
|
fca229e62a |
@@ -62,17 +62,19 @@ jobs:
|
||||
- name: Define variables
|
||||
run: |
|
||||
envName=''
|
||||
domain="vega.rocks"
|
||||
if [[ "${{ github.event_name }}" = "push" ]]; then
|
||||
domain="vega.rocks"
|
||||
if [[ "${{ github.ref }}" =~ .*release/.* ]]; then
|
||||
envName="$(echo ${{ github.ref }} | rev | cut -d '/' -f 1 | rev)"
|
||||
if [[ "${{ github.ref }}" =~ .*mainnet.* ]]; then
|
||||
domain="vega.community"
|
||||
fi
|
||||
elif [[ "${{ github.ref }}" =~ .*develop$ ]]; then
|
||||
envName="stagnet1"
|
||||
elif [[ "${{ matrix.app}}" = "trading" ]] && [[ ${{ startsWith(github.ref, 'refs/tags/v') && 'true' || 'false' }} = "true" ]]; then
|
||||
envName="mainnet"
|
||||
elif [[ "${{ github.ref }}" =~ .*main$ ]]; then
|
||||
envName="mainnet"
|
||||
fi
|
||||
if [[ "${envName}" = "mainnet" ]]; then
|
||||
domain="vega.xyz"
|
||||
fi
|
||||
bucketName="${{ matrix.app }}.${envName}.${domain}"
|
||||
echo BUCKET_NAME=${bucketName} >> $GITHUB_ENV
|
||||
|
||||
@@ -14,6 +14,7 @@ NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/m
|
||||
NX_VEGA_GOVERNANCE_URL=https://stagnet1.governance.vega.xyz
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.jsoo
|
||||
NX_VEGA_NETWORKS='{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz"}'
|
||||
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
||||
|
||||
# App flags
|
||||
NX_EXPLORER_ASSETS=1
|
||||
|
||||
@@ -48,11 +48,13 @@ export const Footer = () => {
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div className="flex pl-2 content-center">
|
||||
<ExternalLink href={ENV.addresses.feedback}>
|
||||
{showFullFeedbackLabel ? t('Share your feedback') : t('Feedback')}
|
||||
</ExternalLink>
|
||||
</div>
|
||||
{ENV.addresses.feedback ? (
|
||||
<div className="flex pl-2 content-center">
|
||||
<ExternalLink href={ENV.addresses.feedback}>
|
||||
{showFullFeedbackLabel ? t('Share your feedback') : t('Feedback')}
|
||||
</ExternalLink>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
@@ -62,9 +64,5 @@ const NodeUrl = ({ url }: { url: string }) => {
|
||||
// get base url from api url, api sub domain
|
||||
const urlObj = new URL(url);
|
||||
const nodeUrl = urlObj.origin.replace(/^[^.]+\./g, '');
|
||||
return (
|
||||
<Link href={'https://' + nodeUrl} target="_blank">
|
||||
{nodeUrl}
|
||||
</Link>
|
||||
);
|
||||
return <span className="cursor-default">{nodeUrl}</span>;
|
||||
};
|
||||
|
||||
@@ -20,12 +20,10 @@ import isEqual from 'lodash/isEqual';
|
||||
export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
|
||||
if (!market) return null;
|
||||
|
||||
const settlementData =
|
||||
market.tradableInstrument.instrument.product.dataSourceSpecForSettlementData
|
||||
.data;
|
||||
const terminationData =
|
||||
market.tradableInstrument.instrument.product
|
||||
.dataSourceSpecForTradingTermination.data;
|
||||
const settlementData = market.tradableInstrument.instrument.product
|
||||
.dataSourceSpecForSettlementData.data as DataSourceDefinition;
|
||||
const terminationData = market.tradableInstrument.instrument.product
|
||||
.dataSourceSpecForTradingTermination.data as DataSourceDefinition;
|
||||
|
||||
const getSigners = (data: DataSourceDefinition) => {
|
||||
if (data.sourceType.__typename === 'DataSourceDefinitionExternal') {
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import type { Proposal } from './tx-proposal';
|
||||
import { proposalRequiresSignatureBundle } from './tx-proposal';
|
||||
|
||||
describe('proposalRequiresSignatureBundle', () => {
|
||||
it('should return false for freeform proposals, which do not require a signature bundle to enact', () => {
|
||||
const mock = {
|
||||
terms: {
|
||||
newFreeform: {},
|
||||
},
|
||||
};
|
||||
|
||||
expect(proposalRequiresSignatureBundle(mock)).toEqual(false);
|
||||
});
|
||||
|
||||
it('should return false for newMarket proposals, which do not require a signature bundle to enact', () => {
|
||||
const mock = {
|
||||
terms: {
|
||||
newMarket: {},
|
||||
},
|
||||
};
|
||||
|
||||
expect(proposalRequiresSignatureBundle(mock)).toEqual(false);
|
||||
});
|
||||
|
||||
it('should return true for newAsset proposals, which do require a signature bundle to enact', () => {
|
||||
const mock = {
|
||||
terms: {
|
||||
newAsset: {},
|
||||
},
|
||||
};
|
||||
|
||||
expect(proposalRequiresSignatureBundle(mock)).toEqual(true);
|
||||
});
|
||||
|
||||
it('should return true for updateAsset proposals, which do require a signature bundle to enact', () => {
|
||||
const mock = {
|
||||
terms: {
|
||||
updateAsset: {},
|
||||
},
|
||||
};
|
||||
|
||||
expect(proposalRequiresSignatureBundle(mock)).toEqual(true);
|
||||
});
|
||||
|
||||
it('should return false when bad data is supplied', () => {
|
||||
expect(
|
||||
proposalRequiresSignatureBundle(false as unknown as Proposal)
|
||||
).toEqual(false);
|
||||
expect(
|
||||
proposalRequiresSignatureBundle(undefined as unknown as Proposal)
|
||||
).toEqual(false);
|
||||
expect(
|
||||
proposalRequiresSignatureBundle({ test: false } as unknown as Proposal)
|
||||
).toEqual(false);
|
||||
});
|
||||
});
|
||||
@@ -28,11 +28,16 @@ interface TxProposalProps {
|
||||
* @returns boolean True if a signature bundle is required. Used to fetch a signature bundle
|
||||
*/
|
||||
export function proposalRequiresSignatureBundle(proposal?: Proposal): boolean {
|
||||
const proposalsThatRequireBundles = ['newAsset', 'updateAsset'];
|
||||
|
||||
if (!proposal?.terms) {
|
||||
return false;
|
||||
}
|
||||
return !!['newAsset', 'updateAsset'].filter((requiredIfExists) =>
|
||||
has(proposal.terms, requiredIfExists)
|
||||
|
||||
return (
|
||||
proposalsThatRequireBundles.filter((requiredIfExists) =>
|
||||
has(proposal.terms, requiredIfExists)
|
||||
).length > 0
|
||||
);
|
||||
}
|
||||
|
||||
@@ -81,6 +86,7 @@ export const TxProposal = ({ txData, pubKey, blockData }: TxProposalProps) => {
|
||||
|
||||
const tx = proposal.terms?.newAsset || proposal.terms?.updateAsset;
|
||||
|
||||
// This component is not rendered if no bundle is required
|
||||
const SignatureBundleComponent = proposal.terms?.newAsset
|
||||
? ProposalSignatureBundleNewAsset
|
||||
: ProposalSignatureBundleUpdateAsset;
|
||||
|
||||
@@ -17,6 +17,7 @@ NX_TRANCHES_SERVICE_URL=https://tranches-stagnet1-k8s.ops.vega.xyz
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json
|
||||
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
||||
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
|
||||
NX_VEGA_REST_URL=http://localhost:3008/api/v2/
|
||||
|
||||
#Test configuration variables
|
||||
CYPRESS_FAIRGROUND=false
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
{
|
||||
"rationale": {
|
||||
"title": "New Market Proposal E2E submission",
|
||||
"description": "E2E new market proposal"
|
||||
},
|
||||
"terms": {
|
||||
"newMarket": {
|
||||
"changes": {
|
||||
"decimalPlaces": "5",
|
||||
"positionDecimalPlaces": "5",
|
||||
"linearSlippageFactor": "0.001",
|
||||
"quadraticSlippageFactor": "0",
|
||||
"lpPriceRange": "10",
|
||||
"instrument": {
|
||||
"name": "Token test market",
|
||||
"code": "TEST.24h",
|
||||
"future": {
|
||||
"settlementAsset": "73174a6fb1d5802ba0ac7bd7ab79e0a3a4837b262de0a4e80815a55442692bd0",
|
||||
"quoteName": "fBTC",
|
||||
"dataSourceSpecForSettlementData": {
|
||||
"external": {
|
||||
"oracle": {
|
||||
"signers": [
|
||||
{
|
||||
"pubKey": {
|
||||
"key": "70d14a321e02e71992fd115563df765000ccc4775cbe71a0e2f9ff5a3b9dc680"
|
||||
}
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"key": {
|
||||
"name": "prices.ETH.value",
|
||||
"type": "TYPE_INTEGER",
|
||||
"numberDecimalPlaces": "0"
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"operator": "OPERATOR_GREATER_THAN",
|
||||
"value": "0"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"dataSourceSpecForTradingTermination": {
|
||||
"external": {
|
||||
"oracle": {
|
||||
"signers": [
|
||||
{
|
||||
"pubKey": {
|
||||
"key": "70d14a321e02e71992fd115563df765000ccc4775cbe71a0e2f9ff5a3b9dc680"
|
||||
}
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"key": {
|
||||
"name": "trading.terminated.ETH5",
|
||||
"type": "TYPE_BOOLEAN"
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"operator": "OPERATOR_EQUALS",
|
||||
"value": "true"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"dataSourceSpecBinding": {
|
||||
"settlementDataProperty": "prices.ETH.value",
|
||||
"tradingTerminationProperty": "trading.terminated.ETH5"
|
||||
}
|
||||
}
|
||||
},
|
||||
"metadata": ["sector:energy", "sector:tech", "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
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"closingTimestamp": 0,
|
||||
"enactmentTimestamp": 0
|
||||
}
|
||||
}
|
||||
@@ -7,17 +7,12 @@ import {
|
||||
import {
|
||||
createRawProposal,
|
||||
createTenDigitUnixTimeStampForSpecifiedDays,
|
||||
enterUniqueFreeFormProposalBody,
|
||||
generateFreeFormProposalTitle,
|
||||
getDateFormatForSpecifiedDays,
|
||||
getProposalIdFromList,
|
||||
getProposalFromTitle,
|
||||
getProposalInformationFromTable,
|
||||
getSubmittedProposalFromProposalList,
|
||||
goToMakeNewProposal,
|
||||
governanceProposalType,
|
||||
submitUniqueRawProposal,
|
||||
voteForProposal,
|
||||
waitForProposalSubmitted,
|
||||
waitForProposalSync,
|
||||
} from '../../../../governance-e2e/src/support/governance.functions';
|
||||
import { ensureSpecifiedUnstakedTokensAreAssociated } from '../../../../governance-e2e/src/support/staking.functions';
|
||||
import { ethereumWalletConnect } from '../../../../governance-e2e/src/support/wallet-eth.functions';
|
||||
@@ -38,6 +33,8 @@ const proposalDetailsTitle = '[data-testid="proposal-title"]';
|
||||
const proposalDetailsDescription = '[data-testid="proposal-description"]';
|
||||
const openProposals = '[data-testid="open-proposals"]';
|
||||
const viewProposalButton = '[data-testid="view-proposal-btn"]';
|
||||
const voteBreakdownToggle = 'vote-breakdown-toggle';
|
||||
const proposalTermsToggle = 'proposal-terms-toggle';
|
||||
|
||||
describe(
|
||||
'Governance flow for proposal details',
|
||||
@@ -62,23 +59,25 @@ describe(
|
||||
|
||||
// 3001-VOTE-050 3001-VOTE-054 3001-VOTE-055 3002-PROP-019
|
||||
it('Newly created raw proposal details - shows proposal title and full description', function () {
|
||||
const proposalDescription =
|
||||
'I propose that everyone evaluate the following IPFS document and vote Yes if they agree. bafybeigwwctpv37xdcwacqxvekr6e4kaemqsrv34em6glkbiceo3fcy4si';
|
||||
|
||||
createRawProposal();
|
||||
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
|
||||
getProposalIdFromList(rawProposal.rationale.title);
|
||||
cy.get('@proposalIdText').then((proposalId) => {
|
||||
cy.get(openProposals).within(() => {
|
||||
cy.get(`#${proposalId}`).within(() => {
|
||||
cy.get(viewProposalButton).should('be.visible').click();
|
||||
});
|
||||
cy.get(openProposals).within(() => {
|
||||
getProposalFromTitle(rawProposal.rationale.title).within(() => {
|
||||
cy.get(viewProposalButton).should('be.visible').click();
|
||||
});
|
||||
});
|
||||
cy.get(proposalDetailsTitle)
|
||||
.should('contain', rawProposal.rationale.title)
|
||||
.and('be.visible');
|
||||
cy.get(proposalDetailsTitle).should(
|
||||
'contain.text',
|
||||
rawProposal.rationale.title
|
||||
);
|
||||
cy.get(proposalDetailsDescription)
|
||||
.should('contain', rawProposal.rationale.description)
|
||||
.and('be.visible');
|
||||
.find('p')
|
||||
.should('have.text', proposalDescription);
|
||||
});
|
||||
cy.getByTestId(proposalTermsToggle).click();
|
||||
// 3001-VOTE-052
|
||||
cy.get('code.language-json')
|
||||
.should('exist')
|
||||
@@ -89,33 +88,36 @@ describe(
|
||||
|
||||
// 3001-VOTE-043
|
||||
it('Newly created freeform proposal details - shows proposed and closing dates', function () {
|
||||
const closingVoteHrs = '72';
|
||||
const proposalTitle = generateFreeFormProposalTitle();
|
||||
const proposalTimeStamp = createTenDigitUnixTimeStampForSpecifiedDays(3);
|
||||
// const currentDate = new Date(createTenDigitUnixTimeStampForSpecifiedDays(0) * 1000)
|
||||
// const proposedDate = new Date(currentDate.getTime() + 60000)
|
||||
|
||||
goToMakeNewProposal(governanceProposalType.FREEFORM);
|
||||
enterUniqueFreeFormProposalBody(closingVoteHrs, proposalTitle);
|
||||
waitForProposalSubmitted();
|
||||
waitForProposalSync();
|
||||
submitUniqueRawProposal({
|
||||
proposalTitle: proposalTitle,
|
||||
closingTimestamp: proposalTimeStamp,
|
||||
});
|
||||
navigateTo(navigation.proposals);
|
||||
getSubmittedProposalFromProposalList(proposalTitle).within(() =>
|
||||
getProposalFromTitle(proposalTitle).within(() =>
|
||||
cy.get(viewProposalButton).click()
|
||||
);
|
||||
cy.wrap(
|
||||
formatDateWithLocalTimezone(new Date(proposalTimeStamp * 1000))
|
||||
).then((closingDate) => {
|
||||
getProposalInformationFromTable('Closes on')
|
||||
.contains(closingDate)
|
||||
.should('be.visible');
|
||||
getProposalInformationFromTable('Closes on').should(
|
||||
'have.text',
|
||||
closingDate
|
||||
);
|
||||
});
|
||||
cy.wrap(
|
||||
formatDateWithLocalTimezone(
|
||||
new Date(createTenDigitUnixTimeStampForSpecifiedDays(0) * 1000)
|
||||
)
|
||||
).then((proposalDate) => {
|
||||
getProposalInformationFromTable('Proposed on')
|
||||
.contains(proposalDate)
|
||||
.should('be.visible');
|
||||
getProposalInformationFromTable('Proposed on').should(
|
||||
'have.text',
|
||||
proposalDate
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -125,13 +127,14 @@ describe(
|
||||
// 3001-VOTE-067
|
||||
createRawProposal();
|
||||
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
|
||||
getSubmittedProposalFromProposalList(
|
||||
rawProposal.rationale.title
|
||||
).within(() => cy.get(viewProposalButton).click());
|
||||
getProposalFromTitle(rawProposal.rationale.title).within(() =>
|
||||
cy.get(viewProposalButton).click()
|
||||
);
|
||||
});
|
||||
cy.contains('Participation: Not Met 0.00 0.00%(0.00% Required)').should(
|
||||
'be.visible'
|
||||
);
|
||||
cy.getByTestId(voteBreakdownToggle).click();
|
||||
getProposalInformationFromTable('Expected to pass')
|
||||
.contains('👎')
|
||||
.should('be.visible');
|
||||
@@ -151,9 +154,9 @@ describe(
|
||||
it('Newly created proposal details - ability to vote for and against proposal - with minimum required tokens associated', function () {
|
||||
createRawProposal();
|
||||
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
|
||||
getSubmittedProposalFromProposalList(
|
||||
rawProposal.rationale.title
|
||||
).within(() => cy.get(viewProposalButton).click());
|
||||
getProposalFromTitle(rawProposal.rationale.title).within(() =>
|
||||
cy.get(viewProposalButton).click()
|
||||
);
|
||||
});
|
||||
// 3001-VOTE-080
|
||||
cy.getByTestId('vote-buttons').contains('against').should('be.visible');
|
||||
@@ -179,6 +182,7 @@ describe(
|
||||
cy.get(proposalVoteProgressAgainstTokens)
|
||||
.contains('0.00')
|
||||
.and('be.visible');
|
||||
cy.getByTestId(voteBreakdownToggle).click();
|
||||
getProposalInformationFromTable('Tokens for proposal')
|
||||
.should('have.text', (1).toFixed(2))
|
||||
.and('be.visible');
|
||||
@@ -220,14 +224,15 @@ describe(
|
||||
vegaWalletSetSpecifiedApprovalAmount('1000');
|
||||
createRawProposal();
|
||||
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
|
||||
getSubmittedProposalFromProposalList(
|
||||
rawProposal.rationale.title
|
||||
).within(() => cy.get(viewProposalButton).click());
|
||||
getProposalFromTitle(rawProposal.rationale.title).within(() =>
|
||||
cy.get(viewProposalButton).click()
|
||||
);
|
||||
});
|
||||
voteForProposal('for');
|
||||
// 3001-VOTE-079
|
||||
cy.contains('You voted: For').should('be.visible');
|
||||
cy.get(proposalVoteProgressForTokens).contains('1').and('be.visible');
|
||||
cy.getByTestId(voteBreakdownToggle).click();
|
||||
getProposalInformationFromTable('Total Supply')
|
||||
.invoke('text')
|
||||
.then((totalSupply) => {
|
||||
@@ -235,14 +240,15 @@ describe(
|
||||
(Number(totalSupply.replace(/,/g, '')) * 0.001) /
|
||||
100
|
||||
).toFixed(2);
|
||||
ethereumWalletConnect();
|
||||
ensureSpecifiedUnstakedTokensAreAssociated(
|
||||
tokensRequiredToAchieveResult
|
||||
);
|
||||
navigateTo(navigation.proposals);
|
||||
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
|
||||
getSubmittedProposalFromProposalList(
|
||||
rawProposal.rationale.title
|
||||
).within(() => cy.get(viewProposalButton).click());
|
||||
getProposalFromTitle(rawProposal.rationale.title).within(() =>
|
||||
cy.get(viewProposalButton).click()
|
||||
);
|
||||
});
|
||||
cy.get(proposalVoteProgressForPercentage)
|
||||
.contains('100.00%')
|
||||
@@ -259,6 +265,7 @@ describe(
|
||||
cy.get(proposalVoteProgressAgainstTokens)
|
||||
.contains('0.00')
|
||||
.and('be.visible');
|
||||
cy.getByTestId(voteBreakdownToggle).click();
|
||||
getProposalInformationFromTable('Total tokens voted percentage')
|
||||
.should('have.text', '0.00%')
|
||||
.and('be.visible');
|
||||
|
||||
@@ -58,14 +58,12 @@ context(
|
||||
.parentsUntil(proposalListItem)
|
||||
.last()
|
||||
.within(() => {
|
||||
cy.get(proposalStatus).should('have.text', 'Enacted ');
|
||||
cy.get(proposalStatus).should('have.text', 'Enacted');
|
||||
cy.get(viewProposalButton).click();
|
||||
});
|
||||
});
|
||||
cy.getByTestId('proposal-type').should('have.text', 'New market');
|
||||
getProposalInformationFromTable('State')
|
||||
.contains('Enacted')
|
||||
.and('be.visible');
|
||||
cy.get(proposalStatus).should('have.text', 'Enacted');
|
||||
cy.get(votesTable).within(() => {
|
||||
cy.contains('Vote passed.').should('be.visible');
|
||||
cy.contains('Voting has ended.').should('be.visible');
|
||||
@@ -87,16 +85,10 @@ context(
|
||||
.last()
|
||||
.within(() => cy.get(viewProposalButton).click());
|
||||
});
|
||||
getProposalInformationFromTable('State')
|
||||
.contains('Open')
|
||||
.and('be.visible');
|
||||
cy.get(proposalStatus).should('have.text', 'Open');
|
||||
voteForProposal('for');
|
||||
getProposalInformationFromTable('State') // 3001-VOTE-047
|
||||
.contains('Passed', proposalTimeout)
|
||||
.and('be.visible');
|
||||
getProposalInformationFromTable('State')
|
||||
.contains('Enacted', proposalTimeout)
|
||||
.and('be.visible');
|
||||
cy.get(proposalStatus, proposalTimeout).should('have.text', 'Passed');
|
||||
cy.get(proposalStatus, proposalTimeout).should('have.text', 'Enacted');
|
||||
cy.get(votesTable).within(() => {
|
||||
cy.contains('Vote passed.').should('be.visible');
|
||||
cy.contains('Voting has ended.').should('be.visible');
|
||||
@@ -121,13 +113,9 @@ context(
|
||||
.last()
|
||||
.within(() => cy.get(viewProposalButton).click());
|
||||
});
|
||||
getProposalInformationFromTable('State')
|
||||
.contains('Open')
|
||||
.and('be.visible');
|
||||
cy.get(proposalStatus).should('have.text', 'Open');
|
||||
voteForProposal('for');
|
||||
getProposalInformationFromTable('State')
|
||||
.contains('Enacted', proposalTimeout)
|
||||
.and('be.visible');
|
||||
cy.get(proposalStatus, proposalTimeout).should('have.text', 'Enacted');
|
||||
});
|
||||
|
||||
// 3001-VOTE-048 3001-VOTE-049 3001-VOTE-050
|
||||
@@ -144,12 +132,8 @@ context(
|
||||
.last()
|
||||
.within(() => cy.get(viewProposalButton).click());
|
||||
});
|
||||
getProposalInformationFromTable('State')
|
||||
.contains('Open')
|
||||
.and('be.visible');
|
||||
getProposalInformationFromTable('State') // 3001-VOTE-047
|
||||
.contains('Declined', proposalTimeout)
|
||||
.and('be.visible');
|
||||
cy.get(proposalStatus).should('have.text', 'Open');
|
||||
cy.get(proposalStatus, proposalTimeout).should('have.text', 'Declined');
|
||||
getProposalInformationFromTable('Rejection reason')
|
||||
.contains('PROPOSAL_ERROR_PARTICIPATION_THRESHOLD_NOT_REACHED')
|
||||
.and('be.visible');
|
||||
|
||||
@@ -5,10 +5,11 @@ import {
|
||||
enterRawProposalBody,
|
||||
enterUniqueFreeFormProposalBody,
|
||||
generateFreeFormProposalTitle,
|
||||
getProposalFromTitle,
|
||||
getProposalInformationFromTable,
|
||||
getSubmittedProposalFromProposalList,
|
||||
goToMakeNewProposal,
|
||||
governanceProposalType,
|
||||
submitUniqueRawProposal,
|
||||
voteForProposal,
|
||||
waitForProposalSubmitted,
|
||||
waitForProposalSync,
|
||||
@@ -81,7 +82,6 @@ context(
|
||||
});
|
||||
|
||||
vegaWalletSetSpecifiedApprovalAmount('1000');
|
||||
cy.associateTokensToVegaWallet('1');
|
||||
});
|
||||
|
||||
beforeEach('visit governance tab', function () {
|
||||
@@ -95,7 +95,8 @@ context(
|
||||
navigateTo(navigation.proposals);
|
||||
});
|
||||
|
||||
it('Should be able to see that no proposals exist', function () {
|
||||
// Test can only pass if run before other proposal tests.
|
||||
it.skip('Should be able to see that no proposals exist', function () {
|
||||
// 3001-VOTE-003
|
||||
cy.get(noOpenProposals)
|
||||
.should('be.visible')
|
||||
@@ -107,7 +108,7 @@ context(
|
||||
|
||||
// 3002-PROP-002
|
||||
// 3002-PROP-003
|
||||
it('Submit a proposal form - shows how many vega tokens are required to make a proposal', function () {
|
||||
it('Proposal form - shows how many vega tokens are required to make a proposal', function () {
|
||||
// 3002-PROP-005
|
||||
goToMakeNewProposal(governanceProposalType.NEW_MARKET);
|
||||
cy.contains(
|
||||
@@ -115,8 +116,9 @@ context(
|
||||
).should('be.visible');
|
||||
});
|
||||
|
||||
// Skipping as currently unable to propose using forms other than raw
|
||||
// 3002-PROP-011
|
||||
it('Able to submit a valid freeform proposal - with minimum required tokens associated', function () {
|
||||
it.skip('Able to submit a valid freeform proposal - with minimum required tokens associated', function () {
|
||||
goToMakeNewProposal(governanceProposalType.FREEFORM);
|
||||
cy.get(minVoteButton).should('be.visible'); // 3002-PROP-008
|
||||
cy.get(maxVoteButton).should('be.visible');
|
||||
@@ -140,16 +142,13 @@ context(
|
||||
closeStakingDialog();
|
||||
|
||||
cy.get(vegaWalletStakedBalances, txTimeout).should('contain', '2');
|
||||
|
||||
navigateTo(navigation.proposals);
|
||||
goToMakeNewProposal(governanceProposalType.FREEFORM);
|
||||
enterUniqueFreeFormProposalBody('50', generateFreeFormProposalTitle());
|
||||
waitForProposalSubmitted();
|
||||
createRawProposal();
|
||||
});
|
||||
|
||||
it('Creating a proposal - proposal rejected - when closing time sooner than system default', function () {
|
||||
it.skip('Creating a proposal - proposal rejected - when closing time sooner than system default', function () {
|
||||
goToMakeNewProposal(governanceProposalType.FREEFORM);
|
||||
enterUniqueFreeFormProposalBody('0.1', generateFreeFormProposalTitle());
|
||||
|
||||
cy.contains('Awaiting network confirmation', epochTimeout).should(
|
||||
'not.exist'
|
||||
);
|
||||
@@ -158,7 +157,7 @@ context(
|
||||
.should('equal', 'Value must be greater than or equal to 1.');
|
||||
});
|
||||
|
||||
it('Creating a proposal - proposal rejected - when closing time later than system default', function () {
|
||||
it.skip('Creating a proposal - proposal rejected - when closing time later than system default', function () {
|
||||
goToMakeNewProposal(governanceProposalType.FREEFORM);
|
||||
enterUniqueFreeFormProposalBody(
|
||||
'100000',
|
||||
@@ -185,17 +184,13 @@ context(
|
||||
navigateTo(navigation.proposals);
|
||||
cy.get(rejectProposalsLink).click();
|
||||
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
|
||||
getSubmittedProposalFromProposalList(
|
||||
rawProposal.rationale.title
|
||||
).within(() => {
|
||||
getProposalFromTitle(rawProposal.rationale.title).within(() => {
|
||||
cy.contains('Rejected').should('be.visible');
|
||||
cy.contains('Close time too late').should('be.visible');
|
||||
cy.get(viewProposalButton).click();
|
||||
});
|
||||
});
|
||||
getProposalInformationFromTable('State')
|
||||
.contains('Rejected')
|
||||
.and('be.visible');
|
||||
cy.getByTestId('proposal-status').should('have.text', 'Rejected');
|
||||
getProposalInformationFromTable('Rejection reason')
|
||||
.contains('PROPOSAL_ERROR_CLOSE_TIME_TOO_LATE')
|
||||
.and('be.visible');
|
||||
@@ -290,18 +285,19 @@ context(
|
||||
const proposalTitle = generateFreeFormProposalTitle();
|
||||
|
||||
ensureSpecifiedUnstakedTokensAreAssociated('1');
|
||||
goToMakeNewProposal(governanceProposalType.FREEFORM);
|
||||
enterUniqueFreeFormProposalBody('50', proposalTitle);
|
||||
waitForProposalSubmitted();
|
||||
submitUniqueRawProposal({ proposalTitle: proposalTitle });
|
||||
ethereumWalletConnect();
|
||||
stakingPageDisassociateTokens('0.0001');
|
||||
cy.get(vegaWallet).within(() => {
|
||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
|
||||
'contain',
|
||||
'0.9999'
|
||||
);
|
||||
});
|
||||
cy.get(vegaWallet)
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
|
||||
'contain',
|
||||
'0.9999'
|
||||
);
|
||||
});
|
||||
navigateTo(navigation.proposals);
|
||||
getSubmittedProposalFromProposalList(proposalTitle).within(() =>
|
||||
getProposalFromTitle(proposalTitle).within(() =>
|
||||
cy.get(viewProposalButton).click()
|
||||
);
|
||||
cy.contains('Vote breakdown').should('be.visible', {
|
||||
@@ -319,9 +315,9 @@ context(
|
||||
cy.get('[data-testid="manage-vega-wallet"]:visible').click();
|
||||
cy.get('[data-testid="disconnect"]').click();
|
||||
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
|
||||
getSubmittedProposalFromProposalList(
|
||||
rawProposal.rationale.title
|
||||
).within(() => cy.get(viewProposalButton).click());
|
||||
getProposalFromTitle(rawProposal.rationale.title).within(() =>
|
||||
cy.get(viewProposalButton).click()
|
||||
);
|
||||
});
|
||||
// 3001-VOTE-075
|
||||
// 3001-VOTE-076
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
import {
|
||||
getProposalInformationFromTable,
|
||||
goToMakeNewProposal,
|
||||
governanceProposalType,
|
||||
voteForProposal,
|
||||
waitForProposalSubmitted,
|
||||
} from '../../support/governance.functions';
|
||||
@@ -56,18 +57,8 @@ const fUSDCId =
|
||||
const epochTimeout = Cypress.env('epochTimeout');
|
||||
const proposalTimeout = { timeout: 14000 };
|
||||
|
||||
const governanceProposalType = {
|
||||
NETWORK_PARAMETER: 'Network parameter',
|
||||
NEW_MARKET: 'New market',
|
||||
UPDATE_MARKET: 'Update market',
|
||||
NEW_ASSET: 'New asset',
|
||||
UPDATE_ASSET: 'Update asset',
|
||||
FREEFORM: 'Freeform',
|
||||
RAW: 'raw proposal',
|
||||
};
|
||||
|
||||
// 3001-VOTE-007
|
||||
context(
|
||||
context.skip(
|
||||
'Governance flow - form validations for different governance proposals',
|
||||
{ tags: '@slow' },
|
||||
function () {
|
||||
|
||||
@@ -6,16 +6,15 @@ import {
|
||||
waitForSpinner,
|
||||
} from '../../support/common.functions';
|
||||
import {
|
||||
createFreeformProposal,
|
||||
createRawProposal,
|
||||
createTenDigitUnixTimeStampForSpecifiedDays,
|
||||
enterRawProposalBody,
|
||||
generateFreeFormProposalTitle,
|
||||
getProposalIdFromList,
|
||||
getProposalFromTitle,
|
||||
getProposalInformationFromTable,
|
||||
getSubmittedProposalFromProposalList,
|
||||
goToMakeNewProposal,
|
||||
governanceProposalType,
|
||||
submitUniqueRawProposal,
|
||||
voteForProposal,
|
||||
waitForProposalSubmitted,
|
||||
waitForProposalSync,
|
||||
@@ -24,10 +23,14 @@ import { ensureSpecifiedUnstakedTokensAreAssociated } from '../../support/stakin
|
||||
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
|
||||
import { vegaWalletSetSpecifiedApprovalAmount } from '../../support/wallet-teardown.functions';
|
||||
|
||||
const proposalListItem = 'proposals-list-item';
|
||||
const openProposals = '[data-testid="open-proposals"]';
|
||||
const voteStatus = '[data-testid="vote-status"]';
|
||||
const voteStatus = 'vote-status';
|
||||
const proposalType = 'proposal-type';
|
||||
const proposalStatus = 'proposal-status';
|
||||
const proposalClosingDate = '[data-testid="vote-details"]';
|
||||
const viewProposalButton = '[data-testid="view-proposal-btn"]';
|
||||
const voteBreakDownToggle = 'vote-breakdown-toggle';
|
||||
|
||||
describe('Governance flow for proposal list', { tags: '@slow' }, function () {
|
||||
before('connect wallets and set approval limit', function () {
|
||||
@@ -60,12 +63,12 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () {
|
||||
|
||||
navigateTo(navigation.proposals);
|
||||
cy.get(openProposals).within(() => {
|
||||
cy.get(proposalClosingDate).first().should('contain.text', 'year');
|
||||
cy.get(proposalClosingDate).should('contain.text', 'months');
|
||||
cy.get(proposalClosingDate)
|
||||
.last()
|
||||
.first()
|
||||
.invoke('text')
|
||||
.should('match', /days|minutes/);
|
||||
cy.get(proposalClosingDate).should('contain.text', 'months');
|
||||
cy.get(proposalClosingDate).last().should('contain.text', 'year');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -73,36 +76,27 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () {
|
||||
const proposerId = Cypress.env('vegaWalletPublicKey');
|
||||
const proposalTitle = generateFreeFormProposalTitle();
|
||||
|
||||
createFreeformProposal(proposalTitle);
|
||||
getProposalIdFromList(proposalTitle);
|
||||
cy.get('@proposalIdText').then((proposalId) => {
|
||||
cy.get('[data-testid="set-proposals-filter-visible"]').click();
|
||||
cy.get('[data-testid="filter-input"]').type(proposerId);
|
||||
cy.get(`#${proposalId}`).should('contain', proposalId);
|
||||
});
|
||||
submitUniqueRawProposal({ proposalTitle: proposalTitle });
|
||||
cy.get('[data-testid="set-proposals-filter-visible"]').click();
|
||||
cy.get('[data-testid="filter-input"]').type(proposerId);
|
||||
// cy.get(`#${proposalId}`).should('contain', proposalId);
|
||||
cy.contains(proposalTitle).should('be.visible');
|
||||
cy.get('[data-testid="filter-input"]').type('123');
|
||||
cy.getByTestId(proposalListItem).should('not.exist');
|
||||
});
|
||||
|
||||
it('Newly created proposals list - shows title and portion of summary', function () {
|
||||
createRawProposal(this.minProposerBalance); // 3001-VOTE-052
|
||||
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
|
||||
getProposalIdFromList(rawProposal.rationale.title);
|
||||
cy.get('@proposalIdText').then((proposalId) => {
|
||||
cy.get(openProposals).within(() => {
|
||||
// 3001-VOTE-008
|
||||
// 3001-VOTE-034
|
||||
cy.get(`#${proposalId}`)
|
||||
// 3001-VOTE-097
|
||||
.should('contain', rawProposal.rationale.title)
|
||||
.and('be.visible');
|
||||
cy.get(`#${proposalId}`)
|
||||
.should(
|
||||
'contain',
|
||||
rawProposal.rationale.description.substring(0, 59)
|
||||
)
|
||||
.and('be.visible');
|
||||
});
|
||||
});
|
||||
});
|
||||
const proposalPath = '/proposals/new-market-raw.json';
|
||||
const enactmentTimestamp = createTenDigitUnixTimeStampForSpecifiedDays(3);
|
||||
submitUniqueRawProposal({
|
||||
proposalBody: proposalPath,
|
||||
enactmentTimestamp: enactmentTimestamp,
|
||||
}); // 3001-VOTE-052
|
||||
// 3001-VOTE-008
|
||||
// 3001-VOTE-034
|
||||
// 3001-VOTE-097
|
||||
cy.contains('New Market Proposal E2E submission');
|
||||
cy.contains('Code: TEST.24h. fBTC settled future.').should('be.visible');
|
||||
});
|
||||
|
||||
it('Newly created proposals list - shows open proposals in an open state', function () {
|
||||
@@ -110,23 +104,11 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () {
|
||||
// 3001-VOTE-035
|
||||
createRawProposal(this.minProposerBalance);
|
||||
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
|
||||
getSubmittedProposalFromProposalList(rawProposal.rationale.title).within(
|
||||
() => {
|
||||
cy.get(viewProposalButton).should('be.visible').click();
|
||||
}
|
||||
);
|
||||
|
||||
cy.get('@proposalIdText').then((proposalId) => {
|
||||
getProposalInformationFromTable('ID')
|
||||
.contains(String(proposalId))
|
||||
.and('be.visible');
|
||||
getProposalFromTitle(rawProposal.rationale.title).within(() => {
|
||||
cy.get(viewProposalButton).should('be.visible');
|
||||
cy.getByTestId(proposalType).should('have.text', 'Freeform');
|
||||
cy.getByTestId(proposalStatus).should('have.text', 'Open');
|
||||
});
|
||||
getProposalInformationFromTable('State')
|
||||
.contains('Open')
|
||||
.and('be.visible');
|
||||
getProposalInformationFromTable('Type')
|
||||
.contains('Freeform')
|
||||
.and('be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -134,18 +116,22 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () {
|
||||
it('Newly created freeform proposals list - shows proposal participation - both met and not', function () {
|
||||
const proposalTitle = generateFreeFormProposalTitle();
|
||||
|
||||
createFreeformProposal(proposalTitle);
|
||||
getSubmittedProposalFromProposalList(proposalTitle).within(() => {
|
||||
submitUniqueRawProposal({ proposalTitle: proposalTitle });
|
||||
getProposalFromTitle(proposalTitle).within(() => {
|
||||
// 3001-VOTE-039
|
||||
cy.get(voteStatus).should('have.text', 'Participation not reached');
|
||||
cy.getByTestId(voteStatus).should(
|
||||
'have.text',
|
||||
'Participation not reached'
|
||||
);
|
||||
cy.get(viewProposalButton).click();
|
||||
});
|
||||
voteForProposal('for');
|
||||
navigateTo(navigation.proposals);
|
||||
getSubmittedProposalFromProposalList(proposalTitle).within(() => {
|
||||
cy.get(voteStatus).should('have.text', 'Set to pass');
|
||||
getProposalFromTitle(proposalTitle).within(() => {
|
||||
cy.getByTestId(voteStatus).should('have.text', 'Set to pass');
|
||||
cy.get(viewProposalButton).click();
|
||||
});
|
||||
cy.getByTestId(voteBreakDownToggle).click();
|
||||
getProposalInformationFromTable('Token participation met')
|
||||
.contains('👍')
|
||||
.should('be.visible');
|
||||
|
||||
@@ -96,7 +96,7 @@ context(
|
||||
navigateTo(navigation.validators);
|
||||
|
||||
// 2002-SINC-007
|
||||
validateValidatorListTotalStakeAndShare('0', '2.00', '100.00%');
|
||||
validateValidatorListTotalStakeAndShare('0', '3,002.00', '50.02%');
|
||||
});
|
||||
|
||||
it('Able to view validators staked by me', function () {
|
||||
@@ -146,7 +146,7 @@ context(
|
||||
verifyThisEpochValue(2.0);
|
||||
closeStakingDialog();
|
||||
navigateTo(navigation.validators);
|
||||
validateValidatorListTotalStakeAndShare('0', '2.00', '100.00%');
|
||||
validateValidatorListTotalStakeAndShare('0', '3,002.00', '50.02%');
|
||||
});
|
||||
|
||||
it('Able to stake against a validator - using vega from both wallet and vesting contract', function () {
|
||||
@@ -166,10 +166,11 @@ context(
|
||||
verifyThisEpochValue(6.0);
|
||||
closeStakingDialog();
|
||||
navigateTo(navigation.validators);
|
||||
validateValidatorListTotalStakeAndShare('0', '6.00', '100.00%');
|
||||
validateValidatorListTotalStakeAndShare('0', '3,006.00', '50.05%');
|
||||
});
|
||||
|
||||
it('Able to stake against multiple validators', function () {
|
||||
vegaWalletTeardown();
|
||||
stakingPageAssociateTokens('5');
|
||||
verifyUnstakedBalance(5.0);
|
||||
cy.get('button').contains('Select a validator to nominate').click();
|
||||
@@ -197,14 +198,10 @@ context(
|
||||
.eq(1)
|
||||
.within(() => {
|
||||
cy.getByTestId(stakeValidatorListTotalStake)
|
||||
.should('have.text', '2.00')
|
||||
.should('have.text', '3,002.00')
|
||||
.and('be.visible');
|
||||
cy.getByTestId(stakeValidatorListTotalShare)
|
||||
.should('have.text', '66.67%')
|
||||
.and('be.visible');
|
||||
cy.getByTestId(stakeValidatorListTotalStake)
|
||||
.scrollIntoView()
|
||||
.should('have.text', '2.00')
|
||||
.should('have.text', '50.01%')
|
||||
.and('be.visible');
|
||||
});
|
||||
cy.get(`[row-id="${1}"]`)
|
||||
@@ -212,14 +209,10 @@ context(
|
||||
.within(() => {
|
||||
cy.getByTestId(stakeValidatorListTotalStake)
|
||||
.scrollIntoView()
|
||||
.should('have.text', '1.00')
|
||||
.should('have.text', '3,001.00')
|
||||
.and('be.visible');
|
||||
cy.getByTestId(stakeValidatorListTotalShare)
|
||||
.should('have.text', '33.33%')
|
||||
.and('be.visible');
|
||||
cy.getByTestId(stakeValidatorListTotalStake)
|
||||
.scrollIntoView()
|
||||
.should('have.text', '1.00')
|
||||
.should('have.text', '49.99%')
|
||||
.and('be.visible');
|
||||
});
|
||||
});
|
||||
@@ -282,7 +275,7 @@ context(
|
||||
txTimeout
|
||||
);
|
||||
navigateTo(navigation.validators);
|
||||
validateValidatorListTotalStakeAndShare('0', '0.00', '0.00%');
|
||||
validateValidatorListTotalStakeAndShare('0', '3,000.00', '50.00%');
|
||||
|
||||
cy.getByTestId(userStakeBtn).should('not.exist');
|
||||
cy.getByTestId(userStake).should('not.exist');
|
||||
@@ -354,7 +347,7 @@ context(
|
||||
txTimeout
|
||||
);
|
||||
navigateTo(navigation.validators);
|
||||
validateValidatorListTotalStakeAndShare('0', '0.00', '0.00%');
|
||||
validateValidatorListTotalStakeAndShare('0', '3,000.00', '50.00%');
|
||||
});
|
||||
|
||||
it('Disassociating all vesting contract tokens max - removes all staked tokens', function () {
|
||||
@@ -382,7 +375,7 @@ context(
|
||||
txTimeout
|
||||
);
|
||||
navigateTo(navigation.validators);
|
||||
validateValidatorListTotalStakeAndShare('0', '0.00', '0.00%');
|
||||
validateValidatorListTotalStakeAndShare('0', '3,000.00', '50.00%');
|
||||
});
|
||||
|
||||
it('Disassociating some tokens - prioritizes unstaked tokens', function () {
|
||||
@@ -404,7 +397,7 @@ context(
|
||||
});
|
||||
verifyStakedBalance(2.0);
|
||||
navigateTo(navigation.validators);
|
||||
validateValidatorListTotalStakeAndShare('0', '2.00', '100.00%');
|
||||
validateValidatorListTotalStakeAndShare('0', '3,002.00', '50.02%');
|
||||
});
|
||||
|
||||
it('Associating wallet tokens - when some already staked - auto stakes tokens to staked validator', function () {
|
||||
|
||||
@@ -111,10 +111,10 @@ context(
|
||||
// 1004-ASSO-028
|
||||
// 1004-ASSO-029
|
||||
// 1004-ASSO-031
|
||||
|
||||
vegaWalletTeardown();
|
||||
stakingPageAssociateTokens('2');
|
||||
verifyEthWalletAssociatedBalance('2.0');
|
||||
verifyEthWalletTotalAssociatedBalance('2.0');
|
||||
verifyEthWalletTotalAssociatedBalance('6,002.00');
|
||||
cy.get('button').contains('Select a validator to nominate').click();
|
||||
stakingPageDisassociateTokens('2');
|
||||
cy.getByTestId('currency-title', txTimeout).should(
|
||||
@@ -125,17 +125,18 @@ context(
|
||||
validateWalletCurrency('Pending association', '2.00');
|
||||
validateWalletCurrency('Total associated after pending', '0.00');
|
||||
cy.getByTestId('currency-title', txTimeout).should('have.length', 6);
|
||||
cy.getByTestId('eth-wallet-associated-balances', txTimeout).should(
|
||||
'not.exist'
|
||||
);
|
||||
verifyEthWalletTotalAssociatedBalance('0.00');
|
||||
cy.get(
|
||||
'[data-testid="eth-wallet-associated-balances"]:visible',
|
||||
txTimeout
|
||||
).should('have.length', 2);
|
||||
verifyEthWalletTotalAssociatedBalance('6,000.00');
|
||||
});
|
||||
|
||||
it('Able to associate more tokens than the approved amount of 1000 - requires re-approval', function () {
|
||||
//1004-ASSO-011
|
||||
stakingPageAssociateTokens('1001', { approve: true });
|
||||
verifyEthWalletAssociatedBalance('1,001.00');
|
||||
verifyEthWalletTotalAssociatedBalance('1,001.00');
|
||||
verifyEthWalletTotalAssociatedBalance('7,001.00');
|
||||
cy.get(vegaWallet)
|
||||
.last()
|
||||
.within(() => {
|
||||
|
||||
@@ -47,11 +47,8 @@ context(
|
||||
function () {
|
||||
before('visit withdrawals and connect vega wallet', function () {
|
||||
cy.visit('/');
|
||||
// When running tests locally, will fail if run without restarting capsule
|
||||
cy.updateCapsuleMultiSig().then(() => {
|
||||
ethereumWalletConnect();
|
||||
depositAsset(usdcEthAddress, '1000', 5);
|
||||
});
|
||||
ethereumWalletConnect();
|
||||
depositAsset(usdcEthAddress, '1000', 5);
|
||||
});
|
||||
|
||||
beforeEach('Navigate to withdrawal page', function () {
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
import {
|
||||
enterUniqueFreeFormProposalBody,
|
||||
goToMakeNewProposal,
|
||||
governanceProposalType,
|
||||
} from '../../support/governance.functions';
|
||||
import { vegaWalletFaucetAssetsWithoutCheck } from '../../support/wallet-vega.functions';
|
||||
|
||||
@@ -50,7 +51,7 @@ context('View functionality with public key', { tags: '@smoke' }, function () {
|
||||
const expectedErrorTxt = `You are connected in a view only state for public key: ${vegaWalletPubKey}. In order to send transactions you must connect to a real wallet.`;
|
||||
|
||||
navigateTo(navigation.proposals);
|
||||
goToMakeNewProposal('Freeform');
|
||||
goToMakeNewProposal(governanceProposalType.FREEFORM);
|
||||
enterUniqueFreeFormProposalBody('50', 'pub key proposal test');
|
||||
cy.getByTestId('dialog-content')
|
||||
.first()
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
import { format } from 'date-fns';
|
||||
import { closeDialog, navigateTo, navigation } from './common.functions';
|
||||
import {
|
||||
closeDialog,
|
||||
navigateTo,
|
||||
navigation,
|
||||
waitForSpinner,
|
||||
} from './common.functions';
|
||||
import { ensureSpecifiedUnstakedTokensAreAssociated } from './staking.functions';
|
||||
|
||||
const newProposalButton = '[data-testid="new-proposal-link"]';
|
||||
const proposalInformationTableRows = '[data-testid="key-value-table-row"]';
|
||||
const proposalListItem = '[data-testid="proposals-list-item"]';
|
||||
const newProposalTitle = '[data-testid="proposal-title"]';
|
||||
@@ -46,6 +50,53 @@ export function enterRawProposalBody(timestamp: number) {
|
||||
});
|
||||
}
|
||||
|
||||
export function submitUniqueRawProposal(proposalFields: {
|
||||
proposalBody?: string;
|
||||
proposalTitle?: string;
|
||||
proposalDescription?: string;
|
||||
closingTimestamp?: number;
|
||||
enactmentTimestamp?: number;
|
||||
submit?: boolean;
|
||||
}) {
|
||||
goToMakeNewProposal(governanceProposalType.RAW);
|
||||
let proposalBodyPath = '/proposals/raw.json';
|
||||
if (proposalFields.proposalBody) {
|
||||
proposalBodyPath = proposalFields.proposalBody;
|
||||
}
|
||||
cy.fixture(proposalBodyPath).then((rawProposal) => {
|
||||
if (proposalFields.proposalTitle) {
|
||||
rawProposal.rationale.title = proposalFields.proposalTitle;
|
||||
cy.wrap(proposalFields.proposalTitle).as('proposalTitle');
|
||||
}
|
||||
if (proposalFields.proposalDescription) {
|
||||
rawProposal.rationale.description = proposalFields.proposalDescription;
|
||||
}
|
||||
if (proposalFields.closingTimestamp) {
|
||||
rawProposal.terms.closingTimestamp = proposalFields.closingTimestamp;
|
||||
} else {
|
||||
const minTimeStamp = createTenDigitUnixTimeStampForSpecifiedDays(2);
|
||||
rawProposal.terms.closingTimestamp = minTimeStamp;
|
||||
}
|
||||
if (proposalFields.enactmentTimestamp) {
|
||||
rawProposal.terms.enactmentTimestamp = proposalFields.enactmentTimestamp;
|
||||
}
|
||||
|
||||
const proposalPayload = JSON.stringify(rawProposal);
|
||||
cy.get(rawProposalData).type(proposalPayload, {
|
||||
parseSpecialCharSequences: false,
|
||||
delay: 2,
|
||||
});
|
||||
|
||||
if (proposalFields.submit !== false) {
|
||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
||||
cy.wrap(rawProposal).as('rawProposal');
|
||||
waitForProposalSubmitted();
|
||||
waitForProposalSync();
|
||||
navigateTo(navigation.proposals);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function enterUniqueFreeFormProposalBody(
|
||||
timestamp: string,
|
||||
proposalTitle: string
|
||||
@@ -58,6 +109,10 @@ export function enterUniqueFreeFormProposalBody(
|
||||
cy.getByTestId('proposal-submit').should('be.visible').click();
|
||||
}
|
||||
|
||||
export function getProposalFromTitle(proposalTitle: string) {
|
||||
return cy.contains(proposalTitle).parentsUntil(proposalListItem).last();
|
||||
}
|
||||
|
||||
export function getSubmittedProposalFromProposalList(proposalTitle: string) {
|
||||
getProposalIdFromList(proposalTitle);
|
||||
cy.get('@proposalIdText').then((proposalId) => {
|
||||
@@ -120,13 +175,17 @@ export function waitForProposalSync() {
|
||||
});
|
||||
}
|
||||
|
||||
export function goToMakeNewProposal(proposalType: string) {
|
||||
navigateTo(navigation.proposals);
|
||||
cy.get(newProposalButton).should('be.visible').click();
|
||||
export function goToMakeNewProposal(proposalType: governanceProposalType) {
|
||||
cy.visit('/proposals/propose');
|
||||
waitForSpinner();
|
||||
cy.url().should('include', '/proposals/propose');
|
||||
cy.get(navigation.pageSpinner, { timeout: 20000 }).should('not.exist');
|
||||
cy.get('li').should('contain.text', proposalType).and('be.visible');
|
||||
cy.get('li').contains(proposalType).click();
|
||||
if (proposalType == governanceProposalType.RAW) {
|
||||
cy.get('[href="/proposals/propose/raw"]').click();
|
||||
} else {
|
||||
cy.get('li').should('contain.text', proposalType).and('be.visible');
|
||||
cy.get('li').contains(proposalType).click();
|
||||
}
|
||||
}
|
||||
|
||||
export function waitForProposalSubmitted() {
|
||||
@@ -163,11 +222,12 @@ export function createFreeformProposal(proposalTitle: string) {
|
||||
navigateTo(navigation.proposals);
|
||||
}
|
||||
|
||||
export const governanceProposalType = {
|
||||
NETWORK_PARAMETER: 'Network parameter',
|
||||
NEW_MARKET: 'New market',
|
||||
UPDATE_MARKET: 'Update market',
|
||||
NEW_ASSET: 'New asset',
|
||||
FREEFORM: 'Freeform',
|
||||
RAW: 'raw proposal',
|
||||
};
|
||||
export enum governanceProposalType {
|
||||
NETWORK_PARAMETER = 'Network parameter',
|
||||
NEW_MARKET = 'New market',
|
||||
UPDATE_MARKET = 'Update market',
|
||||
NEW_ASSET = 'New asset',
|
||||
UPDATE_ASSET = 'Update asset',
|
||||
FREEFORM = 'Freeform',
|
||||
RAW = 'raw proposal',
|
||||
}
|
||||
|
||||
@@ -85,6 +85,132 @@ export function createFreeFormProposalTxBody(): ProposalSubmissionBody {
|
||||
};
|
||||
}
|
||||
|
||||
export function createNewMarketProposalTxBody(): ProposalSubmissionBody {
|
||||
const MIN_CLOSE_SEC = 5;
|
||||
const MIN_ENACT_SEC = 7;
|
||||
|
||||
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: 'New Market Proposal E2E submission',
|
||||
description: 'E2E new market proposal',
|
||||
},
|
||||
terms: {
|
||||
newMarket: {
|
||||
changes: {
|
||||
decimalPlaces: '5',
|
||||
positionDecimalPlaces: '5',
|
||||
linearSlippageFactor: '0.001',
|
||||
quadraticSlippageFactor: '0',
|
||||
lpPriceRange: '10',
|
||||
instrument: {
|
||||
name: 'Token test market',
|
||||
code: 'TEST.24h',
|
||||
future: {
|
||||
settlementAsset:
|
||||
'73174a6fb1d5802ba0ac7bd7ab79e0a3a4837b262de0a4e80815a55442692bd0',
|
||||
quoteName: 'fBTC',
|
||||
dataSourceSpecForSettlementData: {
|
||||
external: {
|
||||
oracle: {
|
||||
signers: [
|
||||
{
|
||||
pubKey: {
|
||||
key: '70d14a321e02e71992fd115563df765000ccc4775cbe71a0e2f9ff5a3b9dc680',
|
||||
},
|
||||
},
|
||||
],
|
||||
filters: [
|
||||
{
|
||||
key: {
|
||||
name: 'prices.ETH.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.ETH.value',
|
||||
tradingTerminationProperty: 'trading.terminated.ETH5',
|
||||
},
|
||||
},
|
||||
},
|
||||
metadata: ['sector:energy', 'sector:tech', '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,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
closingTimestamp,
|
||||
enactmentTimestamp,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function mockNetworkUpgradeProposal() {
|
||||
cy.mockGQL((req) => {
|
||||
aliasGQLQuery(req, 'Nodes', nodeData);
|
||||
|
||||
@@ -67,7 +67,6 @@ export async function faucetAsset(assetEthAddress: string) {
|
||||
|
||||
export async function vegaWalletTeardown() {
|
||||
cy.get(associatedAmountInWallet)
|
||||
.should('be.visible')
|
||||
.invoke('text')
|
||||
.then((associatedAmount) => {
|
||||
cy.get('body').then(($body) => {
|
||||
@@ -82,9 +81,11 @@ export async function vegaWalletTeardown() {
|
||||
cy.get(vegaWalletContainer).within(() => {
|
||||
cy.get(associatedAmountInWallet, {
|
||||
timeout: transactionTimeout,
|
||||
}).contains('0.00', {
|
||||
timeout: transactionTimeout,
|
||||
});
|
||||
})
|
||||
.should('have.length', 1, { timeout: transactionTimeout })
|
||||
.contains('0.00', {
|
||||
timeout: transactionTimeout,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ NX_DELEGATIONS_PAGINATION=50
|
||||
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet1-k8s.ops.vega.xyz
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/main/announcements.json
|
||||
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
|
||||
NX_VEGA_REST_URL=https://api.n00.stagnet1.vega.xyz/api/v2/
|
||||
|
||||
#Test configuration variables
|
||||
CYPRESS_FAIRGROUND=false
|
||||
|
||||
@@ -17,6 +17,7 @@ NX_VEGA_WALLET_URL=http://localhost:1789
|
||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
||||
NX_DELEGATIONS_PAGINATION=50
|
||||
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet1-k8s.ops.vega.xyz
|
||||
NX_VEGA_REST_URL=http://localhost:3008/api/v2/
|
||||
|
||||
#Test configuration variables
|
||||
CYPRESS_FAIRGROUND=false
|
||||
|
||||
@@ -11,3 +11,4 @@ NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
||||
NX_DELEGATIONS_PAGINATION=50
|
||||
NX_TRANCHES_SERVICE_URL=https://tranches-devnet1-k8s.ops.vega.xyz
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
NX_VEGA_REST_URL=https://api.n00.devnet1.vega.xyz/api/v2/
|
||||
|
||||
@@ -12,3 +12,4 @@ NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40:87edc2605e544f888305d7fc4
|
||||
NX_DELEGATIONS_PAGINATION=50
|
||||
NX_TRANCHES_SERVICE_URL=https://tranches-mainnet-k8s.ops.vega.xyz
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
||||
NX_VEGA_REST_URL=https://api.vega.community/api/v2/
|
||||
|
||||
@@ -8,3 +8,4 @@ NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
||||
NX_DELEGATIONS_PAGINATION=50
|
||||
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet1-k8s.ops.vega.xyz
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
NX_VEGA_REST_URL=https://api.n00.stagnet1.vega.xyz/api/v2/
|
||||
|
||||
@@ -12,3 +12,4 @@ NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
|
||||
NX_DELEGATIONS_PAGINATION=50
|
||||
NX_TRANCHES_SERVICE_URL=https://tranches-testnet-k8s.ops.vega.xyz
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
NX_VEGA_REST_URL=https://api.n07.testnet.vega.xyz/api/v2/
|
||||
@@ -9,3 +9,4 @@ NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
||||
NX_VEGA_EXPLORER_URL=https://dev.explorer.vega.xyz
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||
NX_VEGA_REST_URL=https://api-validators-testnet.vega.rocks/api/v2/
|
||||
@@ -62,6 +62,7 @@ export const ENV = {
|
||||
ethWalletMnemonic: windowOrDefault('NX_ETH_WALLET_MNEMONIC'),
|
||||
localProviderUrl: windowOrDefault('NX_LOCAL_PROVIDER_URL'),
|
||||
delegationsPagination: windowOrDefault('NX_DELEGATIONS_PAGINATION'),
|
||||
rest: windowOrDefault('NX_VEGA_REST_URL'),
|
||||
flags: {
|
||||
NETWORK_DOWN: TRUTHY.includes(windowOrDefault('NX_NETWORK_DOWN')),
|
||||
MOCK: TRUTHY.includes(windowOrDefault('NX_MOCKED')),
|
||||
|
||||
@@ -27,6 +27,10 @@ import type { ProposalFieldsFragment } from '../proposals/proposals/__generated_
|
||||
import type { NodesFragmentFragment } from '../staking/home/__generated__/Nodes';
|
||||
import type { ProtocolUpgradeProposalFieldsFragment } from '@vegaprotocol/proposals';
|
||||
import { useProtocolUpgradeProposalsQuery } from '@vegaprotocol/proposals';
|
||||
import {
|
||||
orderByDate,
|
||||
orderByUpgradeBlockHeight,
|
||||
} from '../proposals/components/proposals-list/proposals-list';
|
||||
|
||||
const nodesToShow = 6;
|
||||
|
||||
@@ -200,17 +204,17 @@ const GovernanceHome = ({ name }: RouteChildProps) => {
|
||||
const proposals = useMemo(
|
||||
() =>
|
||||
proposalsData
|
||||
? getNotRejectedProposals<ProposalFieldsFragment>(
|
||||
proposalsData.proposalsConnection
|
||||
)
|
||||
? getNotRejectedProposals(proposalsData.proposalsConnection)
|
||||
: [],
|
||||
[proposalsData]
|
||||
);
|
||||
|
||||
const sortedProposals = useMemo(() => orderByDate(proposals), [proposals]);
|
||||
|
||||
const protocolUpgradeProposals = useMemo(
|
||||
() =>
|
||||
protocolUpgradesData
|
||||
? getNotRejectedProtocolUpgradeProposals<ProtocolUpgradeProposalFieldsFragment>(
|
||||
? getNotRejectedProtocolUpgradeProposals(
|
||||
protocolUpgradesData.protocolUpgradeProposals
|
||||
).filter(
|
||||
(p) =>
|
||||
@@ -221,15 +225,20 @@ const GovernanceHome = ({ name }: RouteChildProps) => {
|
||||
[protocolUpgradesData]
|
||||
);
|
||||
|
||||
const sortedProtocolUpgradeProposals = useMemo(
|
||||
() => orderByUpgradeBlockHeight(protocolUpgradeProposals),
|
||||
[protocolUpgradeProposals]
|
||||
);
|
||||
|
||||
const totalProposalsDesired = 4;
|
||||
const protocolUpgradeProposalsToShow = protocolUpgradeProposals.slice(
|
||||
const protocolUpgradeProposalsToShow = sortedProtocolUpgradeProposals.slice(
|
||||
0,
|
||||
totalProposalsDesired
|
||||
);
|
||||
const proposalsToShow =
|
||||
protocolUpgradeProposalsToShow.length === totalProposalsDesired
|
||||
? []
|
||||
: proposals.slice(
|
||||
: sortedProposals.slice(
|
||||
0,
|
||||
totalProposalsDesired - protocolUpgradeProposalsToShow.length
|
||||
);
|
||||
|
||||
@@ -43,13 +43,17 @@ jest.mock('../list-asset', () => ({
|
||||
|
||||
it('Renders with data-testid', async () => {
|
||||
const proposal = generateProposal();
|
||||
render(<Proposal proposal={proposal as ProposalQuery['proposal']} />);
|
||||
render(
|
||||
<Proposal restData={{}} proposal={proposal as ProposalQuery['proposal']} />
|
||||
);
|
||||
expect(await screen.findByTestId('proposal')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders each section', async () => {
|
||||
const proposal = generateProposal();
|
||||
render(<Proposal proposal={proposal as ProposalQuery['proposal']} />);
|
||||
render(
|
||||
<Proposal restData={{}} proposal={proposal as ProposalQuery['proposal']} />
|
||||
);
|
||||
expect(await screen.findByTestId('proposal-header')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('proposal-change-table')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('proposal-json')).toBeInTheDocument();
|
||||
@@ -76,6 +80,8 @@ it('renders whitelist section if proposal is new asset and source is erc20', asy
|
||||
},
|
||||
},
|
||||
});
|
||||
render(<Proposal proposal={proposal as ProposalQuery['proposal']} />);
|
||||
render(
|
||||
<Proposal restData={{}} proposal={proposal as ProposalQuery['proposal']} />
|
||||
);
|
||||
expect(screen.getByTestId('proposal-list-asset')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
@@ -24,9 +24,11 @@ export enum ProposalType {
|
||||
}
|
||||
export interface ProposalProps {
|
||||
proposal: ProposalFieldsFragment | ProposalQuery['proposal'];
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
restData: any;
|
||||
}
|
||||
|
||||
export const Proposal = ({ proposal }: ProposalProps) => {
|
||||
export const Proposal = ({ proposal, restData }: ProposalProps) => {
|
||||
const { params, loading, error } = useNetworkParams([
|
||||
NetworkParams.governance_proposal_market_minVoterBalance,
|
||||
NetworkParams.governance_proposal_updateMarket_minVoterBalance,
|
||||
@@ -99,12 +101,15 @@ export const Proposal = ({ proposal }: ProposalProps) => {
|
||||
<ProposalDescription description={proposal.rationale.description} />
|
||||
</div>
|
||||
|
||||
<div className="mb-4">
|
||||
<ProposalTerms data={proposal.terms} />
|
||||
</div>
|
||||
{proposal.terms.change.__typename !== 'NewMarket' &&
|
||||
proposal.terms.change.__typename !== 'UpdateMarket' && (
|
||||
<div className="mb-4">
|
||||
<ProposalTerms data={proposal.terms} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mb-6">
|
||||
<ProposalJson proposal={proposal} />
|
||||
<ProposalJson proposal={restData?.data?.proposal} />
|
||||
</div>
|
||||
|
||||
<div className="mb-10">
|
||||
|
||||
+4
-4
@@ -132,10 +132,10 @@ describe('Proposals list', () => {
|
||||
const closedProposalsItems = closedProposals.getAllByTestId(
|
||||
'proposals-list-item'
|
||||
);
|
||||
expect(openProposalsItems[0]).toHaveAttribute('id', 'proposal1');
|
||||
expect(openProposalsItems[1]).toHaveAttribute('id', 'proposal2');
|
||||
expect(closedProposalsItems[0]).toHaveAttribute('id', 'proposal4');
|
||||
expect(closedProposalsItems[1]).toHaveAttribute('id', 'proposal3');
|
||||
expect(openProposalsItems[0]).toHaveAttribute('id', 'proposal2');
|
||||
expect(openProposalsItems[1]).toHaveAttribute('id', 'proposal1');
|
||||
expect(closedProposalsItems[0]).toHaveAttribute('id', 'proposal3');
|
||||
expect(closedProposalsItems[1]).toHaveAttribute('id', 'proposal4');
|
||||
});
|
||||
|
||||
it('Displays info on no proposals', () => {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import orderBy from 'lodash/orderBy';
|
||||
import { isFuture } from 'date-fns';
|
||||
import { useState } from 'react';
|
||||
import { useState, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Heading, SubHeading } from '../../../../components/heading';
|
||||
import { ProposalsListItem } from '../proposals-list-item';
|
||||
@@ -30,6 +31,25 @@ interface SortedProtocolUpgradeProposalsProps {
|
||||
closed: ProtocolUpgradeProposalFieldsFragment[];
|
||||
}
|
||||
|
||||
export const orderByDate = (arr: ProposalFieldsFragment[]) =>
|
||||
orderBy(
|
||||
arr,
|
||||
[
|
||||
(p) => new Date(p?.terms?.closingDatetime).getTime(),
|
||||
(p) => new Date(p?.datetime).getTime(),
|
||||
],
|
||||
['asc', 'asc']
|
||||
);
|
||||
|
||||
export const orderByUpgradeBlockHeight = (
|
||||
arr: ProtocolUpgradeProposalFieldsFragment[]
|
||||
) =>
|
||||
orderBy(
|
||||
arr,
|
||||
[(p) => p?.upgradeBlockHeight, (p) => p.vegaReleaseTag],
|
||||
['desc', 'desc']
|
||||
);
|
||||
|
||||
export const ProposalsList = ({
|
||||
proposals,
|
||||
protocolUpgradeProposals,
|
||||
@@ -37,35 +57,57 @@ export const ProposalsList = ({
|
||||
}: ProposalsListProps) => {
|
||||
const { t } = useTranslation();
|
||||
const [filterString, setFilterString] = useState('');
|
||||
const sortedProposals = proposals.reduce(
|
||||
(acc: SortedProposalsProps, proposal) => {
|
||||
if (isFuture(new Date(proposal?.terms.closingDatetime))) {
|
||||
acc.open.push(proposal);
|
||||
} else {
|
||||
acc.closed.push(proposal);
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{
|
||||
open: [],
|
||||
closed: [],
|
||||
}
|
||||
);
|
||||
|
||||
const sortedProtocolUpgradeProposals = protocolUpgradeProposals.reduce(
|
||||
(acc: SortedProtocolUpgradeProposalsProps, proposal) => {
|
||||
if (Number(proposal?.upgradeBlockHeight) > Number(lastBlockHeight)) {
|
||||
acc.open.push(proposal);
|
||||
} else {
|
||||
acc.closed.push(proposal);
|
||||
const sortedProposals: SortedProposalsProps = useMemo(() => {
|
||||
const initialSorting = proposals.reduce(
|
||||
(acc: SortedProposalsProps, proposal) => {
|
||||
if (isFuture(new Date(proposal?.terms.closingDatetime))) {
|
||||
acc.open.push(proposal);
|
||||
} else {
|
||||
acc.closed.push(proposal);
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{
|
||||
open: [],
|
||||
closed: [],
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{
|
||||
open: [],
|
||||
closed: [],
|
||||
}
|
||||
);
|
||||
);
|
||||
return {
|
||||
open:
|
||||
initialSorting.open.length > 0
|
||||
? orderByDate(initialSorting.open as ProposalFieldsFragment[])
|
||||
: [],
|
||||
closed:
|
||||
initialSorting.closed.length > 0
|
||||
? orderByDate(
|
||||
initialSorting.closed as ProposalFieldsFragment[]
|
||||
).reverse()
|
||||
: [],
|
||||
};
|
||||
}, [proposals]);
|
||||
|
||||
const sortedProtocolUpgradeProposals: SortedProtocolUpgradeProposalsProps =
|
||||
useMemo(() => {
|
||||
const initialSorting = protocolUpgradeProposals.reduce(
|
||||
(acc: SortedProtocolUpgradeProposalsProps, proposal) => {
|
||||
if (Number(proposal?.upgradeBlockHeight) > Number(lastBlockHeight)) {
|
||||
acc.open.push(proposal);
|
||||
} else {
|
||||
acc.closed.push(proposal);
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{
|
||||
open: [],
|
||||
closed: [],
|
||||
}
|
||||
);
|
||||
return {
|
||||
open: orderByUpgradeBlockHeight(initialSorting.open),
|
||||
closed: orderByUpgradeBlockHeight(initialSorting.closed).reverse(),
|
||||
};
|
||||
}, [protocolUpgradeProposals, lastBlockHeight]);
|
||||
|
||||
const filterPredicate = (
|
||||
p: ProposalFieldsFragment | ProposalQuery['proposal']
|
||||
|
||||
+1
-1
@@ -107,7 +107,7 @@ export const ProtocolUpgradeProposalsListItem = ({
|
||||
<div className="grid grid-cols-1 mt-3">
|
||||
<div className="justify-self-end">
|
||||
<Link
|
||||
to={`${Routes.PROPOSALS}/protocol-upgrade/${stripFullStops(
|
||||
to={`${Routes.PROTOCOL_UPGRADES}/${stripFullStops(
|
||||
proposal.vegaReleaseTag
|
||||
)}`}
|
||||
>
|
||||
|
||||
@@ -5,9 +5,14 @@ import { useParams } from 'react-router-dom';
|
||||
import { Proposal } from '../components/proposal';
|
||||
import { ProposalNotFound } from '../components/proposal-not-found';
|
||||
import { useProposalQuery } from './__generated__/Proposal';
|
||||
import { useFetch } from '@vegaprotocol/react-helpers';
|
||||
import { ENV } from '../../../config';
|
||||
|
||||
export const ProposalContainer = () => {
|
||||
const params = useParams<{ proposalId: string }>();
|
||||
const {
|
||||
state: { data: restData },
|
||||
} = useFetch(`${ENV.rest}governance?proposalId=${params.proposalId}`);
|
||||
const { data, loading, error, refetch } = useProposalQuery({
|
||||
fetchPolicy: 'network-only',
|
||||
errorPolicy: 'ignore',
|
||||
@@ -23,7 +28,7 @@ export const ProposalContainer = () => {
|
||||
return (
|
||||
<AsyncRenderer loading={loading} error={error} data={data}>
|
||||
{data?.proposal ? (
|
||||
<Proposal proposal={data.proposal} />
|
||||
<Proposal proposal={data.proposal} restData={restData} />
|
||||
) : (
|
||||
<ProposalNotFound />
|
||||
)}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import flow from 'lodash/flow';
|
||||
import { Callout, Intent, Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import { useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -6,36 +7,15 @@ import { SplashLoader } from '../../../components/splash-loader';
|
||||
import { ProposalsList } from '../components/proposals-list';
|
||||
import { useProposalsQuery } from './__generated__/Proposals';
|
||||
import { getNodes } from '@vegaprotocol/utils';
|
||||
import flow from 'lodash/flow';
|
||||
import {
|
||||
ProposalState,
|
||||
ProtocolUpgradeProposalStatus,
|
||||
} from '@vegaprotocol/types';
|
||||
import type { NodeConnection, NodeEdge } from '@vegaprotocol/utils';
|
||||
import type { ProposalFieldsFragment } from './__generated__/Proposals';
|
||||
import orderBy from 'lodash/orderBy';
|
||||
import type { ProtocolUpgradeProposalFieldsFragment } from '@vegaprotocol/proposals';
|
||||
import { useProtocolUpgradeProposalsQuery } from '@vegaprotocol/proposals';
|
||||
|
||||
const orderByDate = (arr: ProposalFieldsFragment[]) =>
|
||||
orderBy(
|
||||
arr,
|
||||
[
|
||||
(p) => new Date(p?.terms?.closingDatetime).getTime(),
|
||||
(p) => new Date(p?.datetime).getTime(),
|
||||
],
|
||||
['asc', 'asc']
|
||||
);
|
||||
|
||||
const orderByUpgradeBlockHeight = (
|
||||
arr: ProtocolUpgradeProposalFieldsFragment[]
|
||||
) =>
|
||||
orderBy(
|
||||
arr,
|
||||
[(p) => p?.upgradeBlockHeight, (p) => p.vegaReleaseTag],
|
||||
['desc', 'desc']
|
||||
);
|
||||
|
||||
export function getNotRejectedProposals<T extends ProposalFieldsFragment>(
|
||||
data?: NodeConnection<NodeEdge<T>> | null
|
||||
): T[] {
|
||||
@@ -44,7 +24,6 @@ export function getNotRejectedProposals<T extends ProposalFieldsFragment>(
|
||||
getNodes<ProposalFieldsFragment>(data, (p) =>
|
||||
p ? p.state !== ProposalState.STATE_REJECTED : false
|
||||
),
|
||||
orderByDate,
|
||||
])(data);
|
||||
}
|
||||
|
||||
@@ -59,7 +38,6 @@ export function getNotRejectedProtocolUpgradeProposals<
|
||||
ProtocolUpgradeProposalStatus.PROTOCOL_UPGRADE_PROPOSAL_STATUS_REJECTED
|
||||
: false
|
||||
),
|
||||
orderByUpgradeBlockHeight,
|
||||
])(data);
|
||||
}
|
||||
|
||||
@@ -82,17 +60,14 @@ export const ProposalsContainer = () => {
|
||||
});
|
||||
|
||||
const proposals = useMemo(
|
||||
() =>
|
||||
getNotRejectedProposals<ProposalFieldsFragment>(
|
||||
data?.proposalsConnection
|
||||
),
|
||||
() => getNotRejectedProposals(data?.proposalsConnection),
|
||||
[data]
|
||||
);
|
||||
|
||||
const protocolUpgradeProposals = useMemo(
|
||||
() =>
|
||||
protocolUpgradesData
|
||||
? getNotRejectedProtocolUpgradeProposals<ProtocolUpgradeProposalFieldsFragment>(
|
||||
? getNotRejectedProtocolUpgradeProposals(
|
||||
protocolUpgradesData.protocolUpgradeProposals
|
||||
)
|
||||
: [],
|
||||
|
||||
@@ -16,11 +16,10 @@ const orderByDate = (arr: ProposalFieldsFragment[]) =>
|
||||
orderBy(
|
||||
arr,
|
||||
[
|
||||
(p) => new Date(p?.terms?.enactmentDatetime || 0).getTime(), // has to be defaulted to 0 because new Date(null).getTime() -> NaN which is first when ordered.
|
||||
(p) => new Date(p?.terms?.closingDatetime).getTime(),
|
||||
(p) => new Date(p?.terms?.closingDatetime || 0).getTime(), // has to be defaulted to 0 because new Date(null).getTime() -> NaN which is first when ordered
|
||||
(p) => p.id,
|
||||
],
|
||||
['desc', 'desc', 'desc']
|
||||
['desc', 'desc']
|
||||
);
|
||||
|
||||
export function getRejectedProposals<T extends ProposalFieldsFragment>(
|
||||
|
||||
@@ -224,6 +224,10 @@ const redirects = [
|
||||
path: '/vesting',
|
||||
element: <Navigate to={Routes.REDEEM} replace />,
|
||||
},
|
||||
{
|
||||
path: Routes.PROTOCOL_UPGRADES,
|
||||
element: <Navigate to={Routes.PROPOSALS} replace />,
|
||||
},
|
||||
];
|
||||
|
||||
const routerConfig = [
|
||||
@@ -264,13 +268,13 @@ const routerConfig = [
|
||||
},
|
||||
{ path: 'proposals', element: <LazyProposalsList /> },
|
||||
{ path: ':proposalId', element: <LazyProposal /> },
|
||||
{
|
||||
path: 'protocol-upgrade/:proposalReleaseTag',
|
||||
element: <LazyProtocolUpgradeProposal />,
|
||||
},
|
||||
{ path: 'rejected', element: <LazyRejectedProposalsList /> },
|
||||
],
|
||||
},
|
||||
{
|
||||
path: `${Routes.PROTOCOL_UPGRADES}/:proposalReleaseTag`,
|
||||
element: <LazyProtocolUpgradeProposal />,
|
||||
},
|
||||
{
|
||||
path: Routes.VALIDATORS,
|
||||
element: <LazyStaking name="Staking" />,
|
||||
|
||||
@@ -5,6 +5,7 @@ const Routes = {
|
||||
REWARDS: '/rewards',
|
||||
PROPOSALS: '/proposals',
|
||||
PROPOSALS_REJECTED: '/proposals/rejected',
|
||||
PROTOCOL_UPGRADES: '/protocol-upgrades',
|
||||
NOT_PERMITTED: '/not-permitted',
|
||||
NOT_FOUND: '/not-found',
|
||||
CONTRACTS: '/contracts',
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -194,6 +194,7 @@ describe('capsule', { tags: '@slow', testIsolation: true }, () => {
|
||||
});
|
||||
|
||||
it('shows node health', function () {
|
||||
// 0006-NETW-010
|
||||
const market = this.market;
|
||||
cy.visit(`/#/markets/${market.id}`);
|
||||
cy.getByTestId('node-health')
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
import { closeWelcomeDialog } from '../support/helpers';
|
||||
|
||||
const dialogContent = 'dialog-content';
|
||||
const nodeHealth = 'node-health';
|
||||
|
||||
describe('home', { tags: '@regression' }, () => {
|
||||
before(() => {
|
||||
cy.clearAllLocalStorage();
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.visit('/');
|
||||
closeWelcomeDialog();
|
||||
});
|
||||
|
||||
describe('footer', () => {
|
||||
it.skip('shows current block height', () => {
|
||||
closeWelcomeDialog();
|
||||
// 0006-NETW-004
|
||||
// 0006-NETW-005
|
||||
// 0006-NETW-008
|
||||
// 0006-NETW-009
|
||||
// 0006-NETW-011
|
||||
|
||||
cy.intercept('POST', 'http://localhost:3008/graphql', (req) => {
|
||||
req.on('response', (res) => {
|
||||
res.setDelay(3001);
|
||||
});
|
||||
});
|
||||
|
||||
cy.getByTestId(nodeHealth)
|
||||
.children()
|
||||
.first()
|
||||
.should('contain.text', 'Warning delay ( >3 sec)');
|
||||
|
||||
cy.intercept('POST', 'http://localhost:3008/graphql', (req) => {
|
||||
req.on('response', (res) => {
|
||||
res.setDelay(1);
|
||||
});
|
||||
});
|
||||
|
||||
cy.getByTestId(nodeHealth)
|
||||
.children()
|
||||
.first()
|
||||
.should('contain.text', 'Operational', { timeout: 10000 })
|
||||
.next()
|
||||
.should('contain.text', new URL(Cypress.env('VEGA_URL')).origin)
|
||||
.next()
|
||||
.should('contain.text', '100'); // all mocked queries have x-block-height header set to 100
|
||||
});
|
||||
|
||||
it('shows node switcher details', () => {
|
||||
// 0006-NETW-012
|
||||
// 0006-NETW-013
|
||||
// 0006-NETW-014
|
||||
// 0006-NETW-015
|
||||
// 0006-NETW-016
|
||||
cy.getByTestId(nodeHealth).click();
|
||||
cy.getByTestId(dialogContent).should('contain.text', 'Connected node');
|
||||
cy.getByTestId(dialogContent).should(
|
||||
'contain.text',
|
||||
'This app will only work on CUSTOM. Select a node to connect to.'
|
||||
);
|
||||
cy.getByTestId('node')
|
||||
.first()
|
||||
.should('contain.text', new URL(Cypress.env('VEGA_URL')).origin)
|
||||
.next()
|
||||
.should('contain.text', 'Response time')
|
||||
.next()
|
||||
.should('contain.text', 'Block')
|
||||
.next()
|
||||
.should('contain.text', 'Subscription');
|
||||
cy.getByTestId('custom-row').should('contain.text', 'Other');
|
||||
cy.getByTestId('dialog-close').click();
|
||||
});
|
||||
|
||||
it('switch to other node', () => {
|
||||
// 0006-NETW-017
|
||||
// 0006-NETW-018
|
||||
// 0006-NETW-019
|
||||
// 0006-NETW-020
|
||||
cy.getByTestId(nodeHealth).click();
|
||||
cy.getByTestId('connect').should('be.disabled');
|
||||
cy.getByTestId('node-url-custom').click();
|
||||
cy.getByTestId('connect').should('be.disabled');
|
||||
cy.get("input[placeholder='https://']")
|
||||
.focus()
|
||||
.type(new URL(Cypress.env('VEGA_URL')).origin + '/graphql');
|
||||
cy.getByTestId('connect').click();
|
||||
cy.getByTestId(nodeHealth)
|
||||
.children()
|
||||
.first()
|
||||
.should('contain.text', 'Operational');
|
||||
});
|
||||
});
|
||||
describe('Network switcher', () => {
|
||||
before(() => {
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.visit('/');
|
||||
});
|
||||
|
||||
// 0006-NETW-002
|
||||
// 0006-NETW-003
|
||||
it('switch to fairground network', () => {
|
||||
cy.getByTestId('network-switcher').click();
|
||||
cy.getByTestId('network-item').contains('Fairground testnet').click();
|
||||
cy.get('[aria-haspopup="menu"]').should('contain.text', 'Fairground');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -4,6 +4,7 @@ import { marketsDataQuery } from '@vegaprotocol/mock';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
|
||||
const selectMarketOverlay = 'select-market-list';
|
||||
const dialogContent = 'dialog-content';
|
||||
|
||||
const generateProposal = (code: string): ProposalListFieldsFragment => ({
|
||||
__typename: 'Proposal',
|
||||
@@ -81,20 +82,12 @@ const generateProposal = (code: string): ProposalListFieldsFragment => ({
|
||||
__typename: 'DataSourceDefinition',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceDefinitionInternal',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceSpecConfigurationTime',
|
||||
conditions: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
dataSourceSpecForTradingTermination: {
|
||||
__typename: 'DataSourceDefinition',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceDefinitionInternal',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceSpecConfigurationTime',
|
||||
conditions: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -288,7 +281,7 @@ describe('home', { tags: '@regression' }, () => {
|
||||
cy.visit('/');
|
||||
cy.wait('@Markets');
|
||||
cy.location('hash').should('equal', '#/markets/market-1');
|
||||
cy.getByTestId('dialog-content').should('not.exist');
|
||||
cy.getByTestId(dialogContent).should('not.exist');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -301,22 +294,8 @@ describe('home', { tags: '@regression' }, () => {
|
||||
cy.visit('/');
|
||||
cy.wait('@Markets');
|
||||
cy.location('hash').should('equal', '#/markets/market-not-existing');
|
||||
cy.getByTestId('dialog-content').should('not.exist');
|
||||
cy.getByTestId(dialogContent).should('not.exist');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('footer', () => {
|
||||
it('shows current block height', () => {
|
||||
cy.visit('/');
|
||||
cy.getByTestId('node-health')
|
||||
.children()
|
||||
.first()
|
||||
.should('contain.text', 'Operational')
|
||||
.next()
|
||||
.should('contain.text', new URL(Cypress.env('VEGA_URL')).origin)
|
||||
.next()
|
||||
.should('contain.text', '100'); // all mocked queries have x-block-height header set to 100
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -482,7 +482,7 @@ describe('amend and cancel order', { tags: '@smoke' }, () => {
|
||||
testOrderCancellation(order);
|
||||
});
|
||||
});
|
||||
it('must be able to cancel all orders on a market', () => {
|
||||
it('must be able to cancel all orders on all markets', () => {
|
||||
// 7003-MORD-009
|
||||
// 7003-MORD-010
|
||||
// 7003-MORD-011
|
||||
@@ -496,9 +496,7 @@ describe('amend and cancel order', { tags: '@smoke' }, () => {
|
||||
.should('have.text', 'Cancel all')
|
||||
.then(($btn) => {
|
||||
cy.wrap($btn).click({ force: true });
|
||||
const order: OrderCancellation = {
|
||||
marketId: 'market-0',
|
||||
};
|
||||
const order: OrderCancellation = {};
|
||||
testOrderCancellation(order);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -107,6 +107,7 @@ export const NetworkSwitcher = ({
|
||||
onOpenChange={handleOpen}
|
||||
trigger={
|
||||
<DropdownMenuTrigger
|
||||
data-testid="network-switcher"
|
||||
ref={menuRef}
|
||||
className={classNames(
|
||||
'flex justify-between items-center text-sm text-vega-dark-600 dark:text-vega-light-600 py-1 px-2 rounded border border-vega-dark-200 whitespace-nowrap dark:hover:bg-vega-dark-500 hover:bg-vega-light-500',
|
||||
|
||||
@@ -16,16 +16,6 @@ fragment DataSource on DataSourceDefinition {
|
||||
}
|
||||
}
|
||||
}
|
||||
... on DataSourceDefinitionInternal {
|
||||
sourceType {
|
||||
... on DataSourceSpecConfigurationTime {
|
||||
conditions {
|
||||
operator
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,14 +3,14 @@ import * as Types from '@vegaprotocol/types';
|
||||
import { gql } from '@apollo/client';
|
||||
import * as Apollo from '@apollo/client';
|
||||
const defaultOptions = {} as const;
|
||||
export type DataSourceFragment = { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null } | null> } } };
|
||||
export type DataSourceFragment = { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } };
|
||||
|
||||
export type MarketInfoQueryVariables = Types.Exact<{
|
||||
marketId: Types.Scalars['ID'];
|
||||
}>;
|
||||
|
||||
|
||||
export type MarketInfoQuery = { __typename?: 'Query', market?: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradingMode: Types.MarketTradingMode, lpPriceRange: string, proposal?: { __typename?: 'Proposal', id?: string | null, rationale: { __typename?: 'ProposalRationale', title: string, description: string } } | null, marketTimestamps: { __typename?: 'MarketTimestamps', open: any, close: any }, openingAuction: { __typename?: 'AuctionDuration', durationSecs: number, volume: number }, accountsConnection?: { __typename?: 'AccountsConnection', edges?: Array<{ __typename?: 'AccountEdge', node: { __typename?: 'AccountBalance', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', id: string } } } | null> | null } | null, fees: { __typename?: 'Fees', factors: { __typename?: 'FeeFactors', makerFee: string, infrastructureFee: string, liquidityFee: string } }, priceMonitoringSettings: { __typename?: 'PriceMonitoringSettings', parameters?: { __typename?: 'PriceMonitoringParameters', triggers?: Array<{ __typename?: 'PriceMonitoringTrigger', horizonSecs: number, probability: number, auctionExtensionSecs: number }> | null } | null }, riskFactors?: { __typename?: 'RiskFactor', market: string, short: string, long: string } | null, liquidityMonitoringParameters: { __typename?: 'LiquidityMonitoringParameters', triggeringRatio: string, targetStakeParameters: { __typename?: 'TargetStakeParameters', timeWindow: number, scalingFactor: number } }, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', id: string, name: string, code: string, metadata: { __typename?: 'InstrumentMetadata', tags?: Array<string> | null }, product: { __typename?: 'Future', quoteName: string, settlementAsset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number }, dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null } | null> } } } }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null } | null> } } } }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecToFutureBinding', settlementDataProperty: string, tradingTerminationProperty: string } } }, riskModel: { __typename?: 'LogNormalRiskModel', tau: number, riskAversionParameter: number, params: { __typename?: 'LogNormalModelParams', r: number, sigma: number, mu: number } } | { __typename?: 'SimpleRiskModel', params: { __typename?: 'SimpleRiskModelParams', factorLong: number, factorShort: number } }, marginCalculator?: { __typename?: 'MarginCalculator', scalingFactors: { __typename?: 'ScalingFactors', searchLevel: number, initialMargin: number, collateralRelease: number } } | null } } | null };
|
||||
export type MarketInfoQuery = { __typename?: 'Query', market?: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradingMode: Types.MarketTradingMode, lpPriceRange: string, proposal?: { __typename?: 'Proposal', id?: string | null, rationale: { __typename?: 'ProposalRationale', title: string, description: string } } | null, marketTimestamps: { __typename?: 'MarketTimestamps', open: any, close: any }, openingAuction: { __typename?: 'AuctionDuration', durationSecs: number, volume: number }, accountsConnection?: { __typename?: 'AccountsConnection', edges?: Array<{ __typename?: 'AccountEdge', node: { __typename?: 'AccountBalance', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', id: string } } } | null> | null } | null, fees: { __typename?: 'Fees', factors: { __typename?: 'FeeFactors', makerFee: string, infrastructureFee: string, liquidityFee: string } }, priceMonitoringSettings: { __typename?: 'PriceMonitoringSettings', parameters?: { __typename?: 'PriceMonitoringParameters', triggers?: Array<{ __typename?: 'PriceMonitoringTrigger', horizonSecs: number, probability: number, auctionExtensionSecs: number }> | null } | null }, riskFactors?: { __typename?: 'RiskFactor', market: string, short: string, long: string } | null, liquidityMonitoringParameters: { __typename?: 'LiquidityMonitoringParameters', triggeringRatio: string, targetStakeParameters: { __typename?: 'TargetStakeParameters', timeWindow: number, scalingFactor: number } }, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', id: string, name: string, code: string, metadata: { __typename?: 'InstrumentMetadata', tags?: Array<string> | null }, product: { __typename?: 'Future', quoteName: string, settlementAsset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number }, dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } } }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } } }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecToFutureBinding', settlementDataProperty: string, tradingTerminationProperty: string } } }, riskModel: { __typename?: 'LogNormalRiskModel', tau: number, riskAversionParameter: number, params: { __typename?: 'LogNormalModelParams', r: number, sigma: number, mu: number } } | { __typename?: 'SimpleRiskModel', params: { __typename?: 'SimpleRiskModelParams', factorLong: number, factorShort: number } }, marginCalculator?: { __typename?: 'MarginCalculator', scalingFactors: { __typename?: 'ScalingFactors', searchLevel: number, initialMargin: number, collateralRelease: number } } | null } } | null };
|
||||
|
||||
export const DataSourceFragmentDoc = gql`
|
||||
fragment DataSource on DataSourceDefinition {
|
||||
@@ -31,16 +31,6 @@ export const DataSourceFragmentDoc = gql`
|
||||
}
|
||||
}
|
||||
}
|
||||
... on DataSourceDefinitionInternal {
|
||||
sourceType {
|
||||
... on DataSourceSpecConfigurationTime {
|
||||
conditions {
|
||||
operator
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -105,12 +105,10 @@ export const MarketInfoAccordion = ({
|
||||
content: <InsurancePoolInfoPanel market={market} account={a} />,
|
||||
})),
|
||||
];
|
||||
const settlementData =
|
||||
market.tradableInstrument.instrument.product.dataSourceSpecForSettlementData
|
||||
.data;
|
||||
const terminationData =
|
||||
market.tradableInstrument.instrument.product
|
||||
.dataSourceSpecForTradingTermination.data;
|
||||
const settlementData = market.tradableInstrument.instrument.product
|
||||
.dataSourceSpecForSettlementData.data as DataSourceDefinition;
|
||||
const terminationData = market.tradableInstrument.instrument.product
|
||||
.dataSourceSpecForTradingTermination.data as DataSourceDefinition;
|
||||
|
||||
const getSigners = (data: DataSourceDefinition) => {
|
||||
if (data.sourceType.__typename === 'DataSourceDefinitionExternal') {
|
||||
|
||||
@@ -5,7 +5,7 @@ import { AssetDetailsTable, useAssetDataProvider } from '@vegaprotocol/assets';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { marketDataProvider } from '../../market-data-provider';
|
||||
import { totalFeesPercentage } from '../../market-utils';
|
||||
import { Dialog, ExternalLink, Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import { ExternalLink, Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
addDecimalsFormatNumber,
|
||||
formatNumber,
|
||||
@@ -25,12 +25,9 @@ import { ConditionOperatorMapping } from '@vegaprotocol/types';
|
||||
import { MarketTradingModeMapping } from '@vegaprotocol/types';
|
||||
import { useEnvironment } from '@vegaprotocol/environment';
|
||||
import type { Provider } from '../../oracle-schema';
|
||||
import {
|
||||
OracleBasicProfile,
|
||||
OracleProfileTitle,
|
||||
OracleFullProfile,
|
||||
} from '../../components';
|
||||
import { useOracleProofs, useOracleMarkets } from '../../hooks';
|
||||
import { OracleBasicProfile } from '../../components/oracle-basic-profile';
|
||||
import { useOracleProofs } from '../../hooks';
|
||||
import { OracleDialog } from '../oracle-dialog/oracle-dialog';
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
|
||||
type PanelProps = Pick<
|
||||
@@ -465,15 +462,17 @@ export const OracleInfoPanel = ({
|
||||
? product.dataSourceSpecForSettlementData.id
|
||||
: product.dataSourceSpecForTradingTermination.id;
|
||||
|
||||
const dataSourceSpec = (
|
||||
type === 'settlementData'
|
||||
? product.dataSourceSpecForSettlementData.data
|
||||
: product.dataSourceSpecForTradingTermination.data
|
||||
) as DataSourceDefinition;
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-4">
|
||||
<DataSourceProof
|
||||
data-testid="oracle-proof-links"
|
||||
data={
|
||||
type === 'settlementData'
|
||||
? product.dataSourceSpecForSettlementData.data
|
||||
: product.dataSourceSpecForTradingTermination.data
|
||||
}
|
||||
data={dataSourceSpec}
|
||||
providers={data}
|
||||
type={type}
|
||||
dataSourceSpecId={dataSourceSpecId}
|
||||
@@ -530,19 +529,27 @@ export const DataSourceProof = ({
|
||||
}
|
||||
|
||||
if (data.sourceType.__typename === 'DataSourceDefinitionInternal') {
|
||||
return (
|
||||
<div>
|
||||
<h3>{t('Internal conditions')}</h3>
|
||||
{data.sourceType.sourceType.conditions.map((condition, i) => {
|
||||
if (!condition) return null;
|
||||
return (
|
||||
<p key={i}>
|
||||
{ConditionOperatorMapping[condition.operator]} {condition.value}
|
||||
</p>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
if (data.sourceType.sourceType) {
|
||||
return (
|
||||
<div>
|
||||
<h3>{t('Internal conditions')}</h3>
|
||||
{data.sourceType.sourceType?.conditions.map((condition, i) => {
|
||||
if (!condition) return null;
|
||||
return (
|
||||
<p key={i}>
|
||||
{ConditionOperatorMapping[condition.operator]} {condition.value}
|
||||
</p>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<div>
|
||||
{t('No oracle spec for trading termination. Internal timestamp used')}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return <div>{t('Invalid data source')}</div>;
|
||||
@@ -613,34 +620,6 @@ const NoOracleProof = ({
|
||||
);
|
||||
};
|
||||
|
||||
export const OracleDialog = ({
|
||||
provider,
|
||||
dataSourceSpecId,
|
||||
open,
|
||||
onChange,
|
||||
}: {
|
||||
dataSourceSpecId: string;
|
||||
provider: Provider;
|
||||
open: boolean;
|
||||
onChange?: (isOpen: boolean) => void;
|
||||
}) => {
|
||||
const oracleMarkets = useOracleMarkets(provider);
|
||||
return (
|
||||
<Dialog
|
||||
title={<OracleProfileTitle provider={provider} />}
|
||||
aria-labelledby="oracle-proof-dialog"
|
||||
open={open}
|
||||
onChange={onChange}
|
||||
>
|
||||
<OracleFullProfile
|
||||
provider={provider}
|
||||
dataSourceSpecId={dataSourceSpecId}
|
||||
markets={oracleMarkets}
|
||||
/>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
const OracleProfile = (props: {
|
||||
provider: Provider;
|
||||
dataSourceSpecId: string;
|
||||
|
||||
@@ -143,7 +143,7 @@ export const marketInfoQuery = (
|
||||
__typename: 'Signer',
|
||||
signer: {
|
||||
__typename: 'PubKey',
|
||||
key: '69464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6f',
|
||||
key: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61',
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -164,7 +164,7 @@ export const marketInfoQuery = (
|
||||
__typename: 'Signer',
|
||||
signer: {
|
||||
__typename: 'PubKey',
|
||||
key: '69464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6f',
|
||||
key: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61',
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { useMemo } from 'react';
|
||||
import { useEnvironment } from '@vegaprotocol/environment';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { Icon } from '@vegaprotocol/ui-toolkit';
|
||||
import type { IconName } from '@blueprintjs/icons';
|
||||
import { getMatchingOracleProvider, useOracleProofs } from '../../hooks';
|
||||
import type { Market } from '../../markets-provider';
|
||||
import { getVerifiedStatusIcon } from '../oracle-basic-profile';
|
||||
|
||||
export const OracleStatus = ({
|
||||
dataSourceSpecForSettlementData,
|
||||
@@ -23,22 +25,15 @@ export const OracleStatus = ({
|
||||
dataSourceSpecForTradingTermination.data,
|
||||
providers
|
||||
);
|
||||
if (
|
||||
(settlementDataProvider &&
|
||||
settlementDataProvider.oracle.status !== 'GOOD') ||
|
||||
(tradingTerminationDataProvider &&
|
||||
tradingTerminationDataProvider.oracle.status !== 'GOOD')
|
||||
) {
|
||||
return (
|
||||
<span
|
||||
className="ml-1"
|
||||
role="img"
|
||||
aria-label={t('oracle status not healthy')}
|
||||
>
|
||||
⛔
|
||||
</span>
|
||||
);
|
||||
let maliciousOracleProvider = null;
|
||||
if (settlementDataProvider?.oracle.status !== 'GOOD') {
|
||||
maliciousOracleProvider = settlementDataProvider;
|
||||
} else if (tradingTerminationDataProvider?.oracle.status !== 'GOOD') {
|
||||
maliciousOracleProvider = tradingTerminationDataProvider;
|
||||
}
|
||||
if (!maliciousOracleProvider) return null;
|
||||
const { icon } = getVerifiedStatusIcon(maliciousOracleProvider);
|
||||
return <Icon size={3} name={icon as IconName} className="ml-1" />;
|
||||
}
|
||||
return null;
|
||||
}, [
|
||||
|
||||
@@ -6,27 +6,13 @@ import {
|
||||
NotificationBanner,
|
||||
ButtonLink,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { OracleDialog } from '../market-info';
|
||||
|
||||
export const oracleStatuses = {
|
||||
UNKNOWN: t(
|
||||
"This public key's proofs have not been verified yet, or no proofs have been provided yet."
|
||||
),
|
||||
GOOD: t("This public key's proofs have been verified."),
|
||||
SUSPICIOUS: t(
|
||||
'This public key is suspected to be acting in bad faith, pending investigation.'
|
||||
),
|
||||
MALICIOUS: t('This public key has been observed acting in bad faith.'),
|
||||
RETIRED: t('This public key is no longer in use.'),
|
||||
COMPROMISED: t(
|
||||
'This public key is no longer in the control of its original owners.'
|
||||
),
|
||||
};
|
||||
import { OracleDialog } from '../oracle-dialog';
|
||||
import { oracleStatuses } from './oracle-statuses';
|
||||
|
||||
export const OracleBanner = ({ marketId }: { marketId: string }) => {
|
||||
const [open, onChange] = useState(false);
|
||||
const settlementOracle = useMarketOracle(marketId);
|
||||
const tradingTerminationOracle = useMarketOracle(
|
||||
const { data: settlementOracle } = useMarketOracle(marketId);
|
||||
const { data: tradingTerminationOracle } = useMarketOracle(
|
||||
marketId,
|
||||
'dataSourceSpecForTradingTermination'
|
||||
);
|
||||
@@ -36,15 +22,7 @@ export const OracleBanner = ({ marketId }: { marketId: string }) => {
|
||||
} else if (tradingTerminationOracle?.provider.oracle.status !== 'GOOD') {
|
||||
maliciousOracle = tradingTerminationOracle;
|
||||
}
|
||||
|
||||
if (!maliciousOracle) return null;
|
||||
if (!settlementOracle && !tradingTerminationOracle) {
|
||||
return (
|
||||
<NotificationBanner intent={Intent.Primary}>
|
||||
<div>{t('There is no oracle for this market.')} </div>
|
||||
</NotificationBanner>
|
||||
);
|
||||
}
|
||||
|
||||
const { provider } = maliciousOracle;
|
||||
return (
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
|
||||
export const oracleStatuses = {
|
||||
UNKNOWN: t(
|
||||
"This public key's proofs have not been verified yet, or no proofs have been provided yet."
|
||||
),
|
||||
GOOD: t("This public key's proofs have been verified."),
|
||||
SUSPICIOUS: t(
|
||||
'This public key is suspected to be acting in bad faith, pending investigation.'
|
||||
),
|
||||
MALICIOUS: t('This public key has been observed acting in bad faith.'),
|
||||
RETIRED: t('This public key is no longer in use.'),
|
||||
COMPROMISED: t(
|
||||
'This public key is no longer in the control of its original owners.'
|
||||
),
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export * from './oracle-dialog';
|
||||
@@ -0,0 +1,35 @@
|
||||
import { Dialog } from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
OracleProfileTitle,
|
||||
OracleFullProfile,
|
||||
} from '../../components/oracle-full-profile';
|
||||
import { useOracleMarkets } from '../../hooks';
|
||||
import type { Provider } from '../../oracle-schema';
|
||||
|
||||
export const OracleDialog = ({
|
||||
provider,
|
||||
dataSourceSpecId,
|
||||
open,
|
||||
onChange,
|
||||
}: {
|
||||
dataSourceSpecId: string;
|
||||
provider: Provider;
|
||||
open: boolean;
|
||||
onChange?: (isOpen: boolean) => void;
|
||||
}) => {
|
||||
const oracleMarkets = useOracleMarkets(provider);
|
||||
return (
|
||||
<Dialog
|
||||
title={<OracleProfileTitle provider={provider} />}
|
||||
aria-labelledby="oracle-proof-dialog"
|
||||
open={open}
|
||||
onChange={onChange}
|
||||
>
|
||||
<OracleFullProfile
|
||||
provider={provider}
|
||||
dataSourceSpecId={dataSourceSpecId}
|
||||
markets={oracleMarkets}
|
||||
/>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
@@ -1,2 +1 @@
|
||||
export * from './oracle-full-profile.stories';
|
||||
export * from './oracle-full-profile';
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
VegaIcon,
|
||||
VegaIconNames,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { oracleStatuses } from '../oracle-banner';
|
||||
import { oracleStatuses } from '../oracle-banner/oracle-statuses';
|
||||
import type { IconName } from '@blueprintjs/icons';
|
||||
import classNames from 'classnames';
|
||||
import { getLinkIcon, getVerifiedStatusIcon } from '../oracle-basic-profile';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { useMarketOracle } from './use-market-oracle';
|
||||
import type { MarketInfoQuery } from '../components/market-info/__generated__/MarketInfo';
|
||||
import type { MarketFieldsFragment } from '../__generated__/markets';
|
||||
import type { Provider } from '../oracle-schema';
|
||||
|
||||
const ORACLE_PROOFS_URL = 'ORACLE_PROOFS_URL';
|
||||
@@ -10,43 +10,42 @@ const key = 'key';
|
||||
const dataSourceSpecId = 'dataSourceSpecId';
|
||||
|
||||
const mockEnvironment = jest.fn(() => ({ ORACLE_PROOFS_URL }));
|
||||
const mockDataProvider = jest.fn<
|
||||
{ data: MarketInfoQuery['market'] },
|
||||
unknown[]
|
||||
>(() => ({
|
||||
data: {
|
||||
tradableInstrument: {
|
||||
instrument: {
|
||||
product: {
|
||||
dataSourceSpecForSettlementData: {
|
||||
id: dataSourceSpecId,
|
||||
data: {
|
||||
sourceType: {
|
||||
__typename: 'DataSourceDefinitionExternal',
|
||||
const mockMarket = jest.fn<{ data: MarketFieldsFragment | null }, unknown[]>(
|
||||
() => ({
|
||||
data: {
|
||||
tradableInstrument: {
|
||||
instrument: {
|
||||
product: {
|
||||
dataSourceSpecForSettlementData: {
|
||||
id: dataSourceSpecId,
|
||||
data: {
|
||||
sourceType: {
|
||||
signers: [
|
||||
{
|
||||
signer: {
|
||||
__typename: 'ETHAddress',
|
||||
address,
|
||||
__typename: 'DataSourceDefinitionExternal',
|
||||
sourceType: {
|
||||
signers: [
|
||||
{
|
||||
signer: {
|
||||
__typename: 'ETHAddress',
|
||||
address,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
signer: {
|
||||
__typename: 'PubKey',
|
||||
key,
|
||||
{
|
||||
signer: {
|
||||
__typename: 'PubKey',
|
||||
key,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as MarketInfoQuery['market'],
|
||||
}));
|
||||
} as MarketFieldsFragment,
|
||||
})
|
||||
);
|
||||
|
||||
const mockOracleProofs = jest.fn<{ data?: Provider[] }, unknown[]>(() => ({}));
|
||||
|
||||
@@ -54,9 +53,8 @@ jest.mock('@vegaprotocol/environment', () => ({
|
||||
useEnvironment: jest.fn((args) => mockEnvironment()),
|
||||
}));
|
||||
|
||||
jest.mock('@vegaprotocol/data-provider', () => ({
|
||||
...jest.requireActual('@vegaprotocol/data-provider'),
|
||||
useDataProvider: jest.fn((args) => mockDataProvider()),
|
||||
jest.mock('../markets-provider', () => ({
|
||||
useMarket: jest.fn((args) => mockMarket()),
|
||||
}));
|
||||
|
||||
jest.mock('./use-oracle-proofs', () => ({
|
||||
@@ -66,15 +64,15 @@ jest.mock('./use-oracle-proofs', () => ({
|
||||
const marketId = 'marketId';
|
||||
describe('useMarketOracle', () => {
|
||||
it('returns undefined if no market info present', () => {
|
||||
mockDataProvider.mockReturnValueOnce({ data: null });
|
||||
mockMarket.mockReturnValueOnce({ data: null });
|
||||
const { result } = renderHook(() => useMarketOracle(marketId));
|
||||
expect(result.current).toBeUndefined();
|
||||
expect(result.current?.data).toBeUndefined();
|
||||
});
|
||||
|
||||
it('returns undefined if no oracle proofs present', () => {
|
||||
mockOracleProofs.mockReturnValueOnce({ data: undefined });
|
||||
const { result } = renderHook(() => useMarketOracle(marketId));
|
||||
expect(result.current).toBeUndefined();
|
||||
expect(result.current?.data).toBeUndefined();
|
||||
});
|
||||
|
||||
it('returns oracle matched by eth_address', () => {
|
||||
@@ -102,8 +100,8 @@ describe('useMarketOracle', () => {
|
||||
data,
|
||||
});
|
||||
const { result } = renderHook(() => useMarketOracle(marketId));
|
||||
expect(result.current?.dataSourceSpecId).toBe(dataSourceSpecId);
|
||||
expect(result.current?.provider).toBe(data[1]);
|
||||
expect(result.current?.data?.dataSourceSpecId).toBe(dataSourceSpecId);
|
||||
expect(result.current?.data?.provider).toBe(data[1]);
|
||||
});
|
||||
|
||||
it('returns oracle matching by public_key', () => {
|
||||
@@ -131,7 +129,7 @@ describe('useMarketOracle', () => {
|
||||
data,
|
||||
});
|
||||
const { result } = renderHook(() => useMarketOracle(marketId));
|
||||
expect(result.current?.dataSourceSpecId).toBe(dataSourceSpecId);
|
||||
expect(result.current?.provider).toBe(data[1]);
|
||||
expect(result.current?.data?.dataSourceSpecId).toBe(dataSourceSpecId);
|
||||
expect(result.current?.data?.provider).toBe(data[1]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useEnvironment } from '@vegaprotocol/environment';
|
||||
import { useOracleProofs } from './use-oracle-proofs';
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
import { marketInfoProvider } from '../components/market-info/market-info-data-provider';
|
||||
import { useMarket } from '../markets-provider';
|
||||
|
||||
import { useMemo } from 'react';
|
||||
import type { Provider } from '../oracle-schema';
|
||||
import type { DataSourceSpecFragment } from '../__generated__/OracleMarketsSpec';
|
||||
@@ -41,23 +41,30 @@ export const useMarketOracle = (
|
||||
dataSourceType:
|
||||
| 'dataSourceSpecForSettlementData'
|
||||
| 'dataSourceSpecForTradingTermination' = 'dataSourceSpecForSettlementData'
|
||||
) => {
|
||||
): {
|
||||
data?: {
|
||||
provider: NonNullable<ReturnType<typeof getMatchingOracleProvider>>;
|
||||
dataSourceSpecId: string;
|
||||
};
|
||||
loading?: boolean;
|
||||
} => {
|
||||
const { ORACLE_PROOFS_URL } = useEnvironment();
|
||||
const { data: marketInfo } = useDataProvider({
|
||||
dataProvider: marketInfoProvider,
|
||||
variables: { marketId },
|
||||
});
|
||||
const { data: providers } = useOracleProofs(ORACLE_PROOFS_URL);
|
||||
const { data: market, loading: marketLoading } = useMarket(marketId);
|
||||
const { data: providers, loading: providersLoading } =
|
||||
useOracleProofs(ORACLE_PROOFS_URL);
|
||||
return useMemo(() => {
|
||||
if (!providers || !marketInfo) {
|
||||
return undefined;
|
||||
if (marketLoading || providersLoading) {
|
||||
return { loading: true };
|
||||
}
|
||||
if (!providers || !market) {
|
||||
return { data: undefined };
|
||||
}
|
||||
const dataSourceSpec =
|
||||
marketInfo.tradableInstrument.instrument.product[dataSourceType];
|
||||
market.tradableInstrument.instrument.product[dataSourceType];
|
||||
const provider = getMatchingOracleProvider(dataSourceSpec.data, providers);
|
||||
if (provider) {
|
||||
return { provider, dataSourceSpecId: dataSourceSpec.id };
|
||||
return { data: { provider, dataSourceSpecId: dataSourceSpec.id } };
|
||||
}
|
||||
return undefined;
|
||||
}, [marketInfo, dataSourceType, providers]);
|
||||
return { data: undefined };
|
||||
}, [market, dataSourceType, providers, marketLoading, providersLoading]);
|
||||
};
|
||||
|
||||
@@ -64,26 +64,44 @@ export const createMarketFragment = (
|
||||
},
|
||||
dataSourceSpecForTradingTermination: {
|
||||
__typename: 'DataSourceSpec',
|
||||
id: 'oracleId',
|
||||
id: 'f028fe5ea7de3890962a05a7163fdde562629af649ed81b8c8902fafb6eef04f',
|
||||
data: {
|
||||
__typename: 'DataSourceDefinition',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceDefinitionExternal',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceSpecConfiguration',
|
||||
signers: [
|
||||
{
|
||||
__typename: 'Signer',
|
||||
signer: {
|
||||
__typename: 'PubKey',
|
||||
key: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
dataSourceSpecForSettlementData: {
|
||||
__typename: 'DataSourceSpec',
|
||||
id: 'oracleId',
|
||||
id: 'f028fe5ea7de3890962a05a7163fdde562629af649ed81b8c8902fafb6eef04f',
|
||||
data: {
|
||||
__typename: 'DataSourceDefinition',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceDefinitionExternal',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceSpecConfiguration',
|
||||
signers: [
|
||||
{
|
||||
__typename: 'Signer',
|
||||
signer: {
|
||||
__typename: 'PubKey',
|
||||
key: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -133,11 +133,9 @@ export const OrderListManager = ({
|
||||
|
||||
const cancelAll = useCallback(() => {
|
||||
create({
|
||||
orderCancellation: {
|
||||
marketId,
|
||||
},
|
||||
orderCancellation: {},
|
||||
});
|
||||
}, [create, marketId]);
|
||||
}, [create]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -226,8 +226,8 @@ describe('OrderListTable', () => {
|
||||
const amendCell = getAmendCell();
|
||||
const typeCell = screen.getAllByRole('gridcell')[2];
|
||||
expect(typeCell).toHaveTextContent('Mid - 10.0 Peg limit');
|
||||
expect(amendCell.queryByTestId('edit')).not.toBeInTheDocument();
|
||||
expect(amendCell.queryByTestId('cancel')).not.toBeInTheDocument();
|
||||
expect(amendCell.queryByTestId('edit')).toBeInTheDocument();
|
||||
expect(amendCell.queryByTestId('cancel')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it.each([
|
||||
|
||||
@@ -329,7 +329,7 @@ export const isOrderActive = (status: Schema.OrderStatus) => {
|
||||
};
|
||||
|
||||
export const isOrderAmendable = (order: Order | undefined) => {
|
||||
if (!order || order.peggedOrder || order.liquidityProvision) {
|
||||
if (!order || order.liquidityProvision) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ export const useColumnDefs = () => {
|
||||
colId: 'market',
|
||||
headerName: t('Market'),
|
||||
field: 'terms.change.instrument.code',
|
||||
width: 150,
|
||||
minWidth: 150,
|
||||
cellStyle: { lineHeight: '14px' },
|
||||
cellRenderer: ({
|
||||
data,
|
||||
|
||||
@@ -13,16 +13,6 @@ fragment NewMarketFields on NewMarket {
|
||||
quoteName
|
||||
dataSourceSpecForSettlementData {
|
||||
sourceType {
|
||||
... on DataSourceDefinitionInternal {
|
||||
sourceType {
|
||||
... on DataSourceSpecConfigurationTime {
|
||||
conditions {
|
||||
operator
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
... on DataSourceDefinitionExternal {
|
||||
sourceType {
|
||||
... on DataSourceSpecConfiguration {
|
||||
@@ -53,16 +43,6 @@ fragment NewMarketFields on NewMarket {
|
||||
}
|
||||
dataSourceSpecForTradingTermination {
|
||||
sourceType {
|
||||
... on DataSourceDefinitionInternal {
|
||||
sourceType {
|
||||
... on DataSourceSpecConfigurationTime {
|
||||
conditions {
|
||||
operator
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
... on DataSourceDefinitionExternal {
|
||||
sourceType {
|
||||
... on DataSourceSpecConfiguration {
|
||||
@@ -145,16 +125,6 @@ fragment UpdateMarketFields on UpdateMarket {
|
||||
quoteName
|
||||
dataSourceSpecForSettlementData {
|
||||
sourceType {
|
||||
... on DataSourceDefinitionInternal {
|
||||
sourceType {
|
||||
... on DataSourceSpecConfigurationTime {
|
||||
conditions {
|
||||
operator
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
... on DataSourceDefinitionExternal {
|
||||
sourceType {
|
||||
... on DataSourceSpecConfiguration {
|
||||
@@ -185,16 +155,6 @@ fragment UpdateMarketFields on UpdateMarket {
|
||||
}
|
||||
dataSourceSpecForTradingTermination {
|
||||
sourceType {
|
||||
... on DataSourceDefinitionInternal {
|
||||
sourceType {
|
||||
... on DataSourceSpecConfigurationTime {
|
||||
conditions {
|
||||
operator
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
... on DataSourceDefinitionExternal {
|
||||
sourceType {
|
||||
... on DataSourceSpecConfiguration {
|
||||
|
||||
+4
-44
File diff suppressed because one or more lines are too long
@@ -76,20 +76,12 @@ export const marketUpdateProposal: ProposalListFieldsFragment = {
|
||||
__typename: 'DataSourceDefinition',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceDefinitionInternal',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceSpecConfigurationTime',
|
||||
conditions: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
dataSourceSpecForTradingTermination: {
|
||||
__typename: 'DataSourceDefinition',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceDefinitionInternal',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceSpecConfigurationTime',
|
||||
conditions: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -185,20 +177,12 @@ const proposalListFields: ProposalListFieldsFragment[] = [
|
||||
__typename: 'DataSourceDefinition',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceDefinitionInternal',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceSpecConfigurationTime',
|
||||
conditions: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
dataSourceSpecForTradingTermination: {
|
||||
__typename: 'DataSourceDefinition',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceDefinitionInternal',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceSpecConfigurationTime',
|
||||
conditions: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
__typename: 'FutureProduct',
|
||||
@@ -283,20 +267,12 @@ const proposalListFields: ProposalListFieldsFragment[] = [
|
||||
__typename: 'DataSourceDefinition',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceDefinitionInternal',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceSpecConfigurationTime',
|
||||
conditions: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
dataSourceSpecForTradingTermination: {
|
||||
__typename: 'DataSourceDefinition',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceDefinitionInternal',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceSpecConfigurationTime',
|
||||
conditions: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
__typename: 'FutureProduct',
|
||||
@@ -381,20 +357,12 @@ const proposalListFields: ProposalListFieldsFragment[] = [
|
||||
__typename: 'DataSourceDefinition',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceDefinitionInternal',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceSpecConfigurationTime',
|
||||
conditions: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
dataSourceSpecForTradingTermination: {
|
||||
__typename: 'DataSourceDefinition',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceDefinitionInternal',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceSpecConfigurationTime',
|
||||
conditions: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
__typename: 'FutureProduct',
|
||||
@@ -479,20 +447,12 @@ const proposalListFields: ProposalListFieldsFragment[] = [
|
||||
__typename: 'DataSourceDefinition',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceDefinitionInternal',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceSpecConfigurationTime',
|
||||
conditions: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
dataSourceSpecForTradingTermination: {
|
||||
__typename: 'DataSourceDefinition',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceDefinitionInternal',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceSpecConfigurationTime',
|
||||
conditions: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
__typename: 'FutureProduct',
|
||||
@@ -577,20 +537,12 @@ const proposalListFields: ProposalListFieldsFragment[] = [
|
||||
__typename: 'DataSourceDefinition',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceDefinitionInternal',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceSpecConfigurationTime',
|
||||
conditions: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
dataSourceSpecForTradingTermination: {
|
||||
__typename: 'DataSourceDefinition',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceDefinitionInternal',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceSpecConfigurationTime',
|
||||
conditions: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
__typename: 'FutureProduct',
|
||||
@@ -675,20 +627,12 @@ const proposalListFields: ProposalListFieldsFragment[] = [
|
||||
__typename: 'DataSourceDefinition',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceDefinitionInternal',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceSpecConfigurationTime',
|
||||
conditions: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
dataSourceSpecForTradingTermination: {
|
||||
__typename: 'DataSourceDefinition',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceDefinitionInternal',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceSpecConfigurationTime',
|
||||
conditions: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
__typename: 'FutureProduct',
|
||||
@@ -773,20 +717,12 @@ const proposalListFields: ProposalListFieldsFragment[] = [
|
||||
__typename: 'DataSourceDefinition',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceDefinitionInternal',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceSpecConfigurationTime',
|
||||
conditions: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
dataSourceSpecForTradingTermination: {
|
||||
__typename: 'DataSourceDefinition',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceDefinitionInternal',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceSpecConfigurationTime',
|
||||
conditions: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
__typename: 'FutureProduct',
|
||||
@@ -871,20 +807,12 @@ const proposalListFields: ProposalListFieldsFragment[] = [
|
||||
__typename: 'DataSourceDefinition',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceDefinitionInternal',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceSpecConfigurationTime',
|
||||
conditions: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
dataSourceSpecForTradingTermination: {
|
||||
__typename: 'DataSourceDefinition',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceDefinitionInternal',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceSpecConfigurationTime',
|
||||
conditions: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
__typename: 'FutureProduct',
|
||||
@@ -969,20 +897,12 @@ const proposalListFields: ProposalListFieldsFragment[] = [
|
||||
__typename: 'DataSourceDefinition',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceDefinitionInternal',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceSpecConfigurationTime',
|
||||
conditions: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
dataSourceSpecForTradingTermination: {
|
||||
__typename: 'DataSourceDefinition',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceDefinitionInternal',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceSpecConfigurationTime',
|
||||
conditions: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
__typename: 'FutureProduct',
|
||||
@@ -1067,20 +987,12 @@ const proposalListFields: ProposalListFieldsFragment[] = [
|
||||
__typename: 'DataSourceDefinition',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceDefinitionInternal',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceSpecConfigurationTime',
|
||||
conditions: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
dataSourceSpecForTradingTermination: {
|
||||
__typename: 'DataSourceDefinition',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceDefinitionInternal',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceSpecConfigurationTime',
|
||||
conditions: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
__typename: 'FutureProduct',
|
||||
@@ -1165,20 +1077,12 @@ const proposalListFields: ProposalListFieldsFragment[] = [
|
||||
__typename: 'DataSourceDefinition',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceDefinitionInternal',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceSpecConfigurationTime',
|
||||
conditions: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
dataSourceSpecForTradingTermination: {
|
||||
__typename: 'DataSourceDefinition',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceDefinitionInternal',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceSpecConfigurationTime',
|
||||
conditions: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
__typename: 'FutureProduct',
|
||||
@@ -1263,20 +1167,12 @@ const proposalListFields: ProposalListFieldsFragment[] = [
|
||||
__typename: 'DataSourceDefinition',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceDefinitionInternal',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceSpecConfigurationTime',
|
||||
conditions: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
dataSourceSpecForTradingTermination: {
|
||||
__typename: 'DataSourceDefinition',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceDefinitionInternal',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceSpecConfigurationTime',
|
||||
conditions: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
__typename: 'FutureProduct',
|
||||
@@ -1361,20 +1257,12 @@ const proposalListFields: ProposalListFieldsFragment[] = [
|
||||
__typename: 'DataSourceDefinition',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceDefinitionInternal',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceSpecConfigurationTime',
|
||||
conditions: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
dataSourceSpecForTradingTermination: {
|
||||
__typename: 'DataSourceDefinition',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceDefinitionInternal',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceSpecConfigurationTime',
|
||||
conditions: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
__typename: 'FutureProduct',
|
||||
|
||||
@@ -133,19 +133,11 @@ const generateUpdateMarketProposal = (
|
||||
dataSourceSpecForSettlementData: {
|
||||
sourceType: {
|
||||
__typename: 'DataSourceDefinitionInternal',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceSpecConfigurationTime',
|
||||
conditions: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
dataSourceSpecForTradingTermination: {
|
||||
sourceType: {
|
||||
__typename: 'DataSourceDefinitionInternal',
|
||||
sourceType: {
|
||||
__typename: 'DataSourceSpecConfigurationTime',
|
||||
conditions: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
__typename:
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import classNames from 'classnames';
|
||||
import { useMemo } from 'react';
|
||||
import Highlighter from 'react-syntax-highlighter';
|
||||
|
||||
export const SyntaxHighlighter = ({
|
||||
@@ -8,6 +9,13 @@ export const SyntaxHighlighter = ({
|
||||
data: unknown;
|
||||
size?: 'smaller' | 'default';
|
||||
}) => {
|
||||
const parsedData = useMemo(() => {
|
||||
try {
|
||||
return JSON.stringify(data, null, ' ');
|
||||
} catch (e) {
|
||||
return 'Unable to parse data';
|
||||
}
|
||||
}, [data]);
|
||||
return (
|
||||
<div
|
||||
className={classNames('syntax-highlighter-wrapper', {
|
||||
@@ -15,7 +23,7 @@ export const SyntaxHighlighter = ({
|
||||
})}
|
||||
>
|
||||
<Highlighter language="json" useInlineStyles={false}>
|
||||
{JSON.stringify(data, null, ' ')}
|
||||
{parsedData}
|
||||
</Highlighter>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user