Compare commits

..
Author SHA1 Message Date
asiaznik 8039b236aa fix: failing tests for closed 2023-10-03 16:49:43 +02:00
asiaznik 6ff9fa6bcb feat(governance): governance transfers
feat: feature flag suppoert

chore: feature flag, borders and conflicts
2023-10-03 14:11:49 +02:00
Mikołaj Młodzikowski 600ea0eeab Revert "Update Jenkinsfile"
This reverts commit 7c3f7a7ab1.
2023-10-03 12:30:39 +02:00
Mikołaj Młodzikowski 7c3f7a7ab1 Update Jenkinsfile
feat(ci): check jenkins execution
2023-10-03 12:15:03 +02:00
Maciek 539abce8af chore(trading): cant view settled market (#4958) 2023-10-03 11:08:30 +01:00
Art ee73e4d5e2 fix(trading): missing wallet connect button (#4959) 2023-10-03 10:38:37 +01:00
Joe Tsang 14928d318d chore(governance): add e2e tests for market update proposals (#4945) 2023-10-02 20:50:47 +01:00
m.ray a19ea1c939 fix(trading): update filter for market selector to include suspended via governance (#4957) 2023-10-02 18:00:49 +01:00
m.rayandMatthew Russell c65c296db2 feat(trading): ethereum oracle spec in oracle panels (#4914)
Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
2023-10-02 17:48:12 +01:00
Maciek 6c5cd85d96 fix(deal-ticket): prevent empty call estimate position (#4950) 2023-10-02 18:26:10 +02:00
m.ray 8efadda98c fix(trading): remove market value proxy and formatting (#4916) 2023-10-02 16:00:55 +01:00
Maciek 0872a14f44 feat(positions): close position with max possible size (#4940) 2023-10-02 16:38:22 +02:00
Ben 13817e4d57 chore(trading): delete duplicate asset details test (#4954) 2023-10-02 13:57:54 +00:00
64 changed files with 1347 additions and 248 deletions
@@ -49,6 +49,37 @@ fragment ExplorerOracleDataSource on OracleSpec {
}
... on DataSourceDefinitionExternal {
sourceType {
... on EthCallSpec {
abi
args
method
requiredConfirmations
address
normalisers {
name
expression
}
trigger {
trigger {
... on EthTimeTrigger {
initial
every
until
}
}
}
filters {
key {
name
type
numberDecimalPlaces
}
conditions {
value
operator
}
}
}
... on DataSourceSpecConfiguration {
signers {
signer {
+34 -3
View File
@@ -5,19 +5,19 @@ import * as Apollo from '@apollo/client';
const defaultOptions = {} as const;
export type ExplorerOracleDataConnectionFragment = { __typename?: 'OracleSpec', dataConnection: { __typename?: 'OracleDataConnection', edges?: Array<{ __typename?: 'OracleDataEdge', node: { __typename?: 'OracleData', externalData: { __typename?: 'ExternalData', data: { __typename?: 'Data', matchedSpecIds?: Array<string> | null, broadcastAt: any, signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, data?: Array<{ __typename?: 'Property', name: string, value: string }> | null } } } } | null> | null } };
export type ExplorerOracleDataSourceFragment = { __typename?: 'OracleSpec', dataSourceSpec: { __typename?: 'ExternalDataSourceSpec', spec: { __typename?: 'DataSourceSpec', id: string, createdAt: any, updatedAt?: any | null, status: Types.DataSourceSpecStatus, 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, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null }, conditions?: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator }> | null }> | null } | { __typename?: 'EthCallSpec' } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null> } | { __typename?: 'DataSourceSpecConfigurationTimeTrigger' } } } } }, dataConnection: { __typename?: 'OracleDataConnection', edges?: Array<{ __typename?: 'OracleDataEdge', node: { __typename?: 'OracleData', externalData: { __typename?: 'ExternalData', data: { __typename?: 'Data', matchedSpecIds?: Array<string> | null, broadcastAt: any, signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, data?: Array<{ __typename?: 'Property', name: string, value: string }> | null } } } } | null> | null } };
export type ExplorerOracleDataSourceFragment = { __typename?: 'OracleSpec', dataSourceSpec: { __typename?: 'ExternalDataSourceSpec', spec: { __typename?: 'DataSourceSpec', id: string, createdAt: any, updatedAt?: any | null, status: Types.DataSourceSpecStatus, 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, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null }, conditions?: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator }> | null }> | null } | { __typename?: 'EthCallSpec', abi?: Array<string> | null, args?: Array<string> | null, method: string, requiredConfirmations: number, address: string, normalisers?: Array<{ __typename?: 'Normaliser', name: string, expression: string }> | null, trigger: { __typename?: 'EthCallTrigger', trigger: { __typename?: 'EthTimeTrigger', initial?: any | null, every?: number | null, until?: any | null } }, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null }, conditions?: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator }> | null }> | null } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null> } | { __typename?: 'DataSourceSpecConfigurationTimeTrigger' } } } } }, dataConnection: { __typename?: 'OracleDataConnection', edges?: Array<{ __typename?: 'OracleDataEdge', node: { __typename?: 'OracleData', externalData: { __typename?: 'ExternalData', data: { __typename?: 'Data', matchedSpecIds?: Array<string> | null, broadcastAt: any, signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, data?: Array<{ __typename?: 'Property', name: string, value: string }> | null } } } } | null> | null } };
export type ExplorerOracleSpecsQueryVariables = Types.Exact<{ [key: string]: never; }>;
export type ExplorerOracleSpecsQuery = { __typename?: 'Query', oracleSpecsConnection?: { __typename?: 'OracleSpecsConnection', pageInfo: { __typename?: 'PageInfo', hasNextPage: boolean }, edges?: Array<{ __typename?: 'OracleSpecEdge', node: { __typename?: 'OracleSpec', dataSourceSpec: { __typename?: 'ExternalDataSourceSpec', spec: { __typename?: 'DataSourceSpec', id: string, createdAt: any, updatedAt?: any | null, status: Types.DataSourceSpecStatus, 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, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null }, conditions?: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator }> | null }> | null } | { __typename?: 'EthCallSpec' } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null> } | { __typename?: 'DataSourceSpecConfigurationTimeTrigger' } } } } }, dataConnection: { __typename?: 'OracleDataConnection', edges?: Array<{ __typename?: 'OracleDataEdge', node: { __typename?: 'OracleData', externalData: { __typename?: 'ExternalData', data: { __typename?: 'Data', matchedSpecIds?: Array<string> | null, broadcastAt: any, signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, data?: Array<{ __typename?: 'Property', name: string, value: string }> | null } } } } | null> | null } } } | null> | null } | null };
export type ExplorerOracleSpecsQuery = { __typename?: 'Query', oracleSpecsConnection?: { __typename?: 'OracleSpecsConnection', pageInfo: { __typename?: 'PageInfo', hasNextPage: boolean }, edges?: Array<{ __typename?: 'OracleSpecEdge', node: { __typename?: 'OracleSpec', dataSourceSpec: { __typename?: 'ExternalDataSourceSpec', spec: { __typename?: 'DataSourceSpec', id: string, createdAt: any, updatedAt?: any | null, status: Types.DataSourceSpecStatus, 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, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null }, conditions?: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator }> | null }> | null } | { __typename?: 'EthCallSpec', abi?: Array<string> | null, args?: Array<string> | null, method: string, requiredConfirmations: number, address: string, normalisers?: Array<{ __typename?: 'Normaliser', name: string, expression: string }> | null, trigger: { __typename?: 'EthCallTrigger', trigger: { __typename?: 'EthTimeTrigger', initial?: any | null, every?: number | null, until?: any | null } }, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null }, conditions?: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator }> | null }> | null } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null> } | { __typename?: 'DataSourceSpecConfigurationTimeTrigger' } } } } }, dataConnection: { __typename?: 'OracleDataConnection', edges?: Array<{ __typename?: 'OracleDataEdge', node: { __typename?: 'OracleData', externalData: { __typename?: 'ExternalData', data: { __typename?: 'Data', matchedSpecIds?: Array<string> | null, broadcastAt: any, signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, data?: Array<{ __typename?: 'Property', name: string, value: string }> | null } } } } | null> | null } } } | null> | null } | null };
export type ExplorerOracleSpecByIdQueryVariables = Types.Exact<{
id: Types.Scalars['ID'];
}>;
export type ExplorerOracleSpecByIdQuery = { __typename?: 'Query', oracleSpec?: { __typename?: 'OracleSpec', dataSourceSpec: { __typename?: 'ExternalDataSourceSpec', spec: { __typename?: 'DataSourceSpec', id: string, createdAt: any, updatedAt?: any | null, status: Types.DataSourceSpecStatus, 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, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null }, conditions?: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator }> | null }> | null } | { __typename?: 'EthCallSpec' } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null> } | { __typename?: 'DataSourceSpecConfigurationTimeTrigger' } } } } }, dataConnection: { __typename?: 'OracleDataConnection', edges?: Array<{ __typename?: 'OracleDataEdge', node: { __typename?: 'OracleData', externalData: { __typename?: 'ExternalData', data: { __typename?: 'Data', matchedSpecIds?: Array<string> | null, broadcastAt: any, signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, data?: Array<{ __typename?: 'Property', name: string, value: string }> | null } } } } | null> | null } } | null };
export type ExplorerOracleSpecByIdQuery = { __typename?: 'Query', oracleSpec?: { __typename?: 'OracleSpec', dataSourceSpec: { __typename?: 'ExternalDataSourceSpec', spec: { __typename?: 'DataSourceSpec', id: string, createdAt: any, updatedAt?: any | null, status: Types.DataSourceSpecStatus, 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, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null }, conditions?: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator }> | null }> | null } | { __typename?: 'EthCallSpec', abi?: Array<string> | null, args?: Array<string> | null, method: string, requiredConfirmations: number, address: string, normalisers?: Array<{ __typename?: 'Normaliser', name: string, expression: string }> | null, trigger: { __typename?: 'EthCallTrigger', trigger: { __typename?: 'EthTimeTrigger', initial?: any | null, every?: number | null, until?: any | null } }, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null }, conditions?: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator }> | null }> | null } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null> } | { __typename?: 'DataSourceSpecConfigurationTimeTrigger' } } } } }, dataConnection: { __typename?: 'OracleDataConnection', edges?: Array<{ __typename?: 'OracleDataEdge', node: { __typename?: 'OracleData', externalData: { __typename?: 'ExternalData', data: { __typename?: 'Data', matchedSpecIds?: Array<string> | null, broadcastAt: any, signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, data?: Array<{ __typename?: 'Property', name: string, value: string }> | null } } } } | null> | null } } | null };
export const ExplorerOracleDataConnectionFragmentDoc = gql`
fragment ExplorerOracleDataConnection on OracleSpec {
@@ -72,6 +72,37 @@ export const ExplorerOracleDataSourceFragmentDoc = gql`
}
... on DataSourceDefinitionExternal {
sourceType {
... on EthCallSpec {
abi
args
method
requiredConfirmations
address
normalisers {
name
expression
}
trigger {
trigger {
... on EthTimeTrigger {
initial
every
until
}
}
}
filters {
key {
name
type
numberDecimalPlaces
}
conditions {
value
operator
}
}
}
... on DataSourceSpecConfiguration {
signers {
signer {
+1
View File
@@ -22,6 +22,7 @@ NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
NX_VEGA_REST_URL=http://localhost:3008/api/v2/
NX_SUCCESSOR_MARKETS=true
NX_PRODUCT_PERPETUALS=true
NX_UPDATE_MARKET_STATE=true
NX_VEGA_EXPLORER_URL=https://explorer.fairground.wtf
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
@@ -1,21 +0,0 @@
{
"rationale": {
"title": "Add USDT Coin (USDT)",
"description": "Proposal to add USDT Coin (USDT) as an asset"
},
"terms": {
"newAsset": {
"changes": {
"name": "USDT Coin",
"symbol": "USDT",
"decimals": "18",
"quantum": "1",
"erc20": {
"contractAddress": "0xb404c51bbc10dcbe948077f18a4b8e553d160084"
}
}
},
"closingTimestamp": 1662374250,
"enactmentTimestamp": 1662460650
}
}
@@ -0,0 +1,16 @@
{
"rationale": {
"title": "Market resume test",
"description": "E2E test for market resume proposal"
},
"terms": {
"updateMarketState": {
"changes": {
"marketId": "b33bb4157e12355db22e41f277ddd0c10104dec29a4d6960bbcb96d186c40cbd",
"updateType": "MARKET_STATE_UPDATE_TYPE_RESUME"
}
},
"closingTimestamp": 0,
"enactmentTimestamp": 0
}
}
@@ -0,0 +1,16 @@
{
"rationale": {
"title": "Market suspended test",
"description": "E2E test for market suspended proposal"
},
"terms": {
"updateMarketState": {
"changes": {
"marketId": "",
"updateType": "MARKET_STATE_UPDATE_TYPE_SUSPEND"
}
},
"closingTimestamp": 0,
"enactmentTimestamp": 0
}
}
@@ -0,0 +1,17 @@
{
"rationale": {
"title": "Market terminate test",
"description": "E2E test for market terminate proposal"
},
"terms": {
"updateMarketState": {
"changes": {
"marketId": "",
"updateType": "MARKET_STATE_UPDATE_TYPE_TERMINATE",
"price": "100"
}
},
"closingTimestamp": 0,
"enactmentTimestamp": 0
}
}
@@ -1,85 +0,0 @@
{
"instrument": {
"code": "Token.24h",
"future": {
"quoteName": "fBTC",
"dataSourceSpecForSettlementData": {
"external": {
"oracle": {
"signers": [
{
"pubKey": {
"key": "70d14a321e02e71992fd115563df765000ccc4775cbe71a0e2f9ff5a3b9dc680"
}
}
],
"filters": [
{
"key": {
"name": "prices.BTC.value",
"type": "TYPE_INTEGER"
},
"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_GREATER_THAN_OR_EQUAL",
"value": "1648684800000000000"
}
]
}
]
}
}
},
"dataSourceSpecBinding": {
"settlementDataProperty": "prices.BTC.value",
"tradingTerminationProperty": "trading.terminated.ETH5"
}
}
},
"metadata": ["sector:energy", "sector:food", "source:docs.vega.xyz"],
"priceMonitoringParameters": {
"triggers": [
{
"horizon": "43200",
"probability": "0.9999999",
"auctionExtension": "600"
}
]
},
"logNormal": {
"tau": 0.0001140771161,
"riskAversionParameter": 0.001,
"params": {
"mu": 0,
"r": 0.016,
"sigma": 0.3
}
}
}
@@ -60,6 +60,17 @@ describe(
before('connect wallets and set approval limit', function () {
cy.visit('/');
ethereumWalletConnect();
cy.createMarket();
navigateTo(navigation.proposals);
cy.getByTestId('closed-proposals').within(() => {
cy.contains('Add Lorem Ipsum market')
.parentsUntil(proposalListItem)
.last()
.within(() => {
cy.getByTestId(viewProposalButton).click();
});
});
getProposalInformationFromTable('ID').invoke('text').as('parentMarketId');
});
beforeEach('visit proposals tab', function () {
@@ -298,9 +309,6 @@ describe(
});
it('Able to see successor market details with new and updated values', function () {
cy.createMarket();
cy.reload();
waitForSpinner();
cy.getByTestId('closed-proposals').within(() => {
cy.contains('Add Lorem Ipsum market')
.parentsUntil(proposalListItem)
@@ -309,14 +317,9 @@ describe(
cy.getByTestId(viewProposalButton).click();
});
});
getProposalInformationFromTable('ID')
.invoke('text')
.as('parentMarketId')
.then(() => {
cy.VegaWalletSubmitProposal(
createSuccessorMarketProposalTxBody(this.parentMarketId)
);
});
cy.VegaWalletSubmitProposal(
createSuccessorMarketProposalTxBody(this.parentMarketId)
);
navigateTo(navigation.proposals);
cy.reload();
getProposalFromTitle('Test successor market proposal details').within(
@@ -434,5 +437,87 @@ describe(
'Minimum Probability Of Trading LP Orders'
).should('contain.text', '1e-8');
});
it('Able to see suspended market proposal', function () {
const proposalPath = 'src/fixtures/proposals/suspend-market-raw.json';
const enactmentTimestamp = createTenDigitUnixTimeStampForSpecifiedDays(3);
const closingTimestamp = createTenDigitUnixTimeStampForSpecifiedDays(2);
submitUniqueRawProposal({
proposalBody: proposalPath,
updateMarketId: this.parentMarketId,
enactmentTimestamp: enactmentTimestamp,
closingTimestamp: closingTimestamp,
});
getProposalFromTitle('Market suspended test').within(() => {
cy.getByTestId(marketProposalType).should(
'have.text',
'Suspend market'
);
cy.getByTestId(viewProposalButton).click();
});
cy.getByTestId(marketProposalType).should('have.text', 'Suspend market');
cy.getByTestId(marketDataToggle).click();
cy.getByTestId('proposal-update-market-state').within(() => {
getProposalInformationFromTable('Market ID')
.invoke('text')
.and('eq', this.parentMarketId);
});
});
it('Able to see resume market proposal', function () {
const proposalPath = 'src/fixtures/proposals/resume-market-raw.json';
const enactmentTimestamp = createTenDigitUnixTimeStampForSpecifiedDays(3);
const closingTimestamp = createTenDigitUnixTimeStampForSpecifiedDays(2);
submitUniqueRawProposal({
proposalBody: proposalPath,
updateMarketId: this.parentMarketId,
enactmentTimestamp: enactmentTimestamp,
closingTimestamp: closingTimestamp,
});
getProposalFromTitle('Market resume test').within(() => {
cy.getByTestId(marketProposalType).should('have.text', 'Resume market');
cy.getByTestId(viewProposalButton).click();
});
cy.getByTestId(marketProposalType).should('have.text', 'Resume market');
cy.getByTestId(marketDataToggle).click();
cy.getByTestId('proposal-update-market-state').within(() => {
getProposalInformationFromTable('Market ID')
.invoke('text')
.and('eq', this.parentMarketId);
});
});
it('Able to see terminate market proposal', function () {
const proposalPath = 'src/fixtures/proposals/terminate-market-raw.json';
const enactmentTimestamp = createTenDigitUnixTimeStampForSpecifiedDays(3);
const closingTimestamp = createTenDigitUnixTimeStampForSpecifiedDays(2);
submitUniqueRawProposal({
proposalBody: proposalPath,
updateMarketId: this.parentMarketId,
enactmentTimestamp: enactmentTimestamp,
closingTimestamp: closingTimestamp,
});
getProposalFromTitle('Market terminate test').within(() => {
cy.getByTestId(marketProposalType).should(
'have.text',
'Terminate market'
);
cy.getByTestId(viewProposalButton).click();
});
cy.getByTestId(marketProposalType).should(
'have.text',
'Terminate market'
);
cy.getByTestId(marketDataToggle).click();
cy.getByTestId('proposal-update-market-state').within(() => {
getProposalInformationFromTable('Market ID')
.invoke('text')
.and('eq', this.parentMarketId);
getProposalDetailsValue('Termination Price').should(
'contain.text',
'0.001 fUSDC'
);
});
});
}
);
@@ -54,6 +54,7 @@ export function submitUniqueRawProposal(proposalFields: {
proposalBody?: string;
proposalTitle?: string;
proposalDescription?: string;
updateMarketId?: string;
closingTimestamp?: number;
enactmentTimestamp?: number;
submit?: boolean;
@@ -71,6 +72,10 @@ export function submitUniqueRawProposal(proposalFields: {
if (proposalFields.proposalDescription) {
rawProposal.rationale.description = proposalFields.proposalDescription;
}
if (proposalFields.updateMarketId) {
rawProposal.terms.updateMarketState.changes.marketId =
proposalFields.updateMarketId;
}
if (proposalFields.closingTimestamp) {
rawProposal.terms.closingTimestamp = proposalFields.closingTimestamp;
} else if (
+1
View File
@@ -34,3 +34,4 @@ NX_SUCCESSOR_MARKETS=true
NX_METAMASK_SNAPS=true
NX_PRODUCT_PERPETUALS=false
NX_UPDATE_MARKET_STATE=false
NX_GOVERNANCE_TRANSFERS=false
+1
View File
@@ -22,3 +22,4 @@ NX_SUCCESSOR_MARKETS=true
NX_METAMASK_SNAPS=true
NX_PRODUCT_PERPETUALS=true
NX_UPDATE_MARKET_STATE=true
NX_GOVERNANCE_TRANSFERS=true
@@ -888,5 +888,7 @@
"HowToPropose": "How to make a proposal",
"HowToProposeRawStep1": "1. Sense check your proposal with the community on the forum:",
"HowToProposeRawStep2": "2. Use the appropriate proposal template in the docs:",
"HowToProposeRawStep3": "3. Submit on-chain below"
"HowToProposeRawStep3": "3. Submit on-chain below",
"proposalTransferDetails": "New governance transfer details",
"proposalCancelTransferDetails": "Cancel governance transfer details"
}
@@ -7,12 +7,17 @@ import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
import { truncateMiddle } from '../../../../lib/truncate-middle';
import { CurrentProposalState } from '../current-proposal-state';
import { ProposalInfoLabel } from '../proposal-info-label';
import { useSuccessorMarketProposalDetails } from '@vegaprotocol/proposals';
import {
useCancelTransferProposalDetails,
useNewTransferProposalDetails,
useSuccessorMarketProposalDetails,
} from '@vegaprotocol/proposals';
import { FLAGS } from '@vegaprotocol/environment';
import Routes from '../../../routes';
import { Link } from 'react-router-dom';
import type { VoteState } from '../vote-details/use-user-vote';
import { VoteBreakdown } from '../vote-breakdown';
import { GovernanceTransferKindMapping } from '@vegaprotocol/types';
export const ProposalHeader = ({
proposal,
@@ -147,6 +152,20 @@ export const ProposalHeader = ({
);
break;
}
case 'NewTransfer':
proposalType = 'NewTransfer';
fallbackTitle = t('NewTransferProposal');
details = FLAGS.GOVERNANCE_TRANSFERS ? (
<NewTransferSummary proposalId={proposal?.id} />
) : null;
break;
case 'CancelTransfer':
proposalType = 'CancelTransfer';
fallbackTitle = t('CancelTransferProposal');
details = FLAGS.GOVERNANCE_TRANSFERS ? (
<CancelTransferSummary proposalId={proposal?.id} />
) : null;
break;
}
return (
@@ -224,3 +243,36 @@ const SuccessorCode = ({ proposalId }: { proposalId?: string | null }) => {
</span>
) : null;
};
const NewTransferSummary = ({ proposalId }: { proposalId?: string | null }) => {
const { t } = useTranslation();
const details = useNewTransferProposalDetails(proposalId);
if (!details) return null;
return (
<span>
{GovernanceTransferKindMapping[details.kind.__typename]}{' '}
{t('transfer from')} <Lozenge>{truncateMiddle(details.source)}</Lozenge>{' '}
{t('to')} <Lozenge>{truncateMiddle(details.destination)}</Lozenge>
</span>
);
};
const CancelTransferSummary = ({
proposalId,
}: {
proposalId?: string | null;
}) => {
const { t } = useTranslation();
const details = useCancelTransferProposalDetails(proposalId);
if (!details) return null;
return (
<span>
{t('Cancel transfer: ')}{' '}
<Lozenge>{truncateMiddle(details.transferId)}</Lozenge>
</span>
);
};
@@ -0,0 +1,2 @@
export * from './proposal-transfer-details';
export * from './proposal-cancel-transfer-details';
@@ -0,0 +1,37 @@
import { useTranslation } from 'react-i18next';
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
import type { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals';
import { useCancelTransferProposalDetails } from '@vegaprotocol/proposals';
import {
KeyValueTable,
KeyValueTableRow,
RoundedWrapper,
} from '@vegaprotocol/ui-toolkit';
import { SubHeading } from '../../../../components/heading';
export const ProposalCancelTransferDetails = ({
proposal,
}: {
proposal: ProposalFieldsFragment | ProposalQuery['proposal'];
}) => {
const { t } = useTranslation();
const details = useCancelTransferProposalDetails(proposal?.id);
if (!details) {
return null;
}
return (
<>
<SubHeading title={t('proposalCancelTransferDetails')} />
<RoundedWrapper paddingBottom={true}>
<KeyValueTable data-testid="proposal-cancel-transfer-details-table">
<KeyValueTableRow noBorder={true}>
{t('transferId')}
{details.transferId}
</KeyValueTableRow>
</KeyValueTable>
</RoundedWrapper>
</>
);
};
@@ -0,0 +1,145 @@
import { useState } from 'react';
import type { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals';
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
import { CollapsibleToggle } from '../../../../components/collapsible-toggle';
import { SubHeading } from '../../../../components/heading';
import { useTranslation } from 'react-i18next';
import {
KeyValueTable,
KeyValueTableRow,
RoundedWrapper,
Tooltip,
} from '@vegaprotocol/ui-toolkit';
import { useNewTransferProposalDetails } from '@vegaprotocol/proposals';
import {
AccountTypeMapping,
DescriptionGovernanceTransferTypeMapping,
GovernanceTransferKindMapping,
GovernanceTransferTypeMapping,
} from '@vegaprotocol/types';
import {
addDecimalsFormatNumberQuantum,
formatDateWithLocalTimezone,
} from '@vegaprotocol/utils';
export const ProposalTransferDetails = ({
proposal,
}: {
proposal: ProposalFieldsFragment | ProposalQuery['proposal'];
}) => {
const { t } = useTranslation();
const [show, setShow] = useState(false);
const details = useNewTransferProposalDetails(proposal?.id);
if (!details) {
return null;
}
return (
<>
<CollapsibleToggle
toggleState={show}
setToggleState={setShow}
dataTestId="proposal-transfer-details"
>
<SubHeading title={t('proposalTransferDetails')} />
</CollapsibleToggle>
{show && (
<RoundedWrapper paddingBottom={true}>
<KeyValueTable data-testid="proposal-transfer-details-table">
{/* The source account */}
<KeyValueTableRow>
{t('Source')}
{details.source}
</KeyValueTableRow>
{/* The type of source account */}
<KeyValueTableRow>
{t('Source Type')}
{AccountTypeMapping[details.sourceType]}
</KeyValueTableRow>
{/* The destination account */}
<KeyValueTableRow>
{t('Destination')}
{details.destination}
</KeyValueTableRow>
{/* The type of destination account */}
<KeyValueTableRow>
{t('Destination Type')}
{AccountTypeMapping[details.destinationType]}
</KeyValueTableRow>
{/* The asset to transfer */}
<KeyValueTableRow>
{t('Asset')}
{details.asset.symbol}
</KeyValueTableRow>
{/*The fraction of the balance to be transfer */}
<KeyValueTableRow>
{t('Fraction Of Balance')}
{`${Number(details.fraction_of_balance) * 100}%`}
</KeyValueTableRow>
{/* The maximum amount to be transferred */}
<KeyValueTableRow>
{t('Amount')}
{addDecimalsFormatNumberQuantum(
details.amount,
details.asset.decimals,
details.asset.quantum
)}
</KeyValueTableRow>
{/* The type of the governance transfer */}
<KeyValueTableRow>
{t('Transfer Type')}
<Tooltip
description={
DescriptionGovernanceTransferTypeMapping[details.transferType]
}
>
<span>
{GovernanceTransferTypeMapping[details.transferType]}
</span>
</Tooltip>
</KeyValueTableRow>
{/* The type of governance transfer being made, i.e. a one-off or recurring trans */}
<KeyValueTableRow>
{t('Kind')}
{GovernanceTransferKindMapping[details.kind.__typename]}
</KeyValueTableRow>
{details.kind.__typename === 'OneOffGovernanceTransfer' &&
details.kind.deliverOn && (
<KeyValueTableRow noBorder={true}>
{t('Deliver On')}
{formatDateWithLocalTimezone(
new Date(details.kind.deliverOn)
)}
</KeyValueTableRow>
)}
{details.kind.__typename === 'RecurringGovernanceTransfer' && (
<>
<KeyValueTableRow noBorder={!details.kind.endEpoch}>
{t('Start On')}
<span>{details.kind.startEpoch}</span>
</KeyValueTableRow>
{details.kind.endEpoch && (
<KeyValueTableRow noBorder={true}>
{t('End on')}
{details.kind.endEpoch}
</KeyValueTableRow>
)}
</>
)}
</KeyValueTable>
</RoundedWrapper>
)}
</>
);
};
@@ -20,6 +20,11 @@ import { ProposalUpdateMarketState } from '../proposal-update-market-state';
import type { NetworkParamsResult } from '@vegaprotocol/network-parameters';
import { useVoteSubmit } from '@vegaprotocol/proposals';
import { useUserVote } from '../vote-details/use-user-vote';
import {
ProposalCancelTransferDetails,
ProposalTransferDetails,
} from '../proposal-transfer';
import { FLAGS } from '@vegaprotocol/environment';
export interface ProposalProps {
proposal: ProposalQuery['proposal'];
@@ -99,9 +104,37 @@ export const Proposal = ({
minVoterBalance =
networkParams.governance_proposal_freeform_minVoterBalance;
break;
case 'NewTransfer':
// TODO: check minVoterBalance for 'NewTransfer'
minVoterBalance =
networkParams.governance_proposal_freeform_minVoterBalance;
break;
case 'CancelTransfer':
// TODO: check minVoterBalance for 'CancelTransfer'
minVoterBalance =
networkParams.governance_proposal_freeform_minVoterBalance;
}
}
// Show governance transfer details only if the GOVERNANCE_TRANSFERS flag is on.
const governanceTransferDetails = FLAGS.GOVERNANCE_TRANSFERS && (
<>
{proposal.terms.change.__typename === 'NewTransfer' && (
/** Governance New Transfer Details */
<div className="mb-4">
<ProposalTransferDetails proposal={proposal} />
</div>
)}
{proposal.terms.change.__typename === 'CancelTransfer' && (
/** Governance Cancel Transfer Details */
<div className="mb-4">
<ProposalCancelTransferDetails proposal={proposal} />
</div>
)}
</>
);
return (
<section data-testid="proposal">
<div className="flex items-center gap-1 mb-6">
@@ -187,6 +220,8 @@ export const Proposal = ({
</div>
)}
{governanceTransferDetails}
<div className="mb-10">
<RoundedWrapper paddingBottom={true}>
<UserVote
@@ -64,48 +64,6 @@ describe('accounts', { tags: '@smoke' }, () => {
cy.getByTestId('Collateral').click({ force: true });
});
it('should open asset details dialog when clicked on symbol', () => {
// 7001-COLL-008
// 6501-ASSE-001
// 6501-ASSE-002
// 6501-ASSE-003
// 6501-ASSE-004
// 6501-ASSE-005
// 6501-ASSE-006
// 6501-ASSE-007
// 6501-ASSE-008
// 6501-ASSE-009
// 6501-ASSE-010
// 6501-ASSE-011
// 6501-ASSE-012
// 6501-ASSE-013
const titles = [
'ID',
'Type',
'Name',
'Symbol',
'Decimals',
'Quantum',
'Status',
'Contract address',
'Withdrawal threshold',
'Lifetime limit',
'Infrastructure fee account balance',
'Global reward pool account balance',
'Maker paid fees account balance',
'Maker received fees account balance',
'Liquidity provision fee reward account balance',
'Market proposer reward account balance',
];
cy.get('[col-id="asset.symbol"]').contains('tEURO').click();
cy.get('[data-testid$="_label"]').should('have.length', 16);
cy.get('[data-testid$="_label"]').each((element, index) => {
cy.wrap(element).should('have.text', titles[index]);
});
cy.getByTestId(dialogClose).click();
cy.getByTestId(dialogClose).should('not.exist');
});
it('should open usage breakdown dialog when clicked on used', () => {
// 7001-COLL-009
cy.get('[col-id="used"]').contains('1.01').click();
+1
View File
@@ -12,6 +12,7 @@ NX_VEGA_WALLET_URL=http://localhost:1789
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground
+1
View File
@@ -15,6 +15,7 @@ NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/annou
NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=true
@@ -0,0 +1,5 @@
import MarketPage from '../market';
export const ClosedMarketPage = () => {
return <MarketPage closed />;
};
@@ -0,0 +1 @@
export { ClosedMarketPage as default } from './closed-market';
+24 -6
View File
@@ -9,9 +9,10 @@ import { useGlobalStore, usePageTitleStore } from '../../stores';
import { TradeGrid } from './trade-grid';
import { TradePanels } from './trade-panels';
import { useNavigate, useParams } from 'react-router-dom';
import { Links } from '../../lib/links';
import { Links, Routes } from '../../lib/links';
import { ViewType, useSidebar } from '../../components/sidebar';
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
import { MarketState } from '@vegaprotocol/types';
const calculatePrice = (markPrice?: string, decimalPlaces?: number) => {
return markPrice && decimalPlaces
@@ -56,7 +57,7 @@ const TitleUpdater = ({
return null;
};
export const MarketPage = () => {
export const MarketPage = ({ closed }: { closed?: boolean }) => {
const { marketId } = useParams();
const navigate = useNavigate();
const currentRouteId = useGetCurrentRouteId();
@@ -70,16 +71,33 @@ export const MarketPage = () => {
const { data, error, loading } = useMarket(marketId);
useEffect(() => {
if (data?.id && data.id !== lastMarketId) {
if (
data?.state &&
[
MarketState.STATE_SETTLED,
MarketState.STATE_TRADING_TERMINATED,
].includes(data.state) &&
currentRouteId !== Routes.CLOSED_MARKETS &&
marketId
) {
navigate(Links.CLOSED_MARKETS(marketId));
}
}, [data?.state, currentRouteId, navigate, marketId]);
useEffect(() => {
if (data?.id && data.id !== lastMarketId && !closed) {
update({ marketId: data.id });
}
}, [update, lastMarketId, data?.id]);
}, [update, lastMarketId, data?.id, closed]);
useEffect(() => {
if (largeScreen && view === undefined) {
setViews({ type: ViewType.Order }, currentRouteId);
setViews(
{ type: closed ? ViewType.Info : ViewType.Order },
currentRouteId
);
}
}, [setViews, view, currentRouteId, largeScreen]);
}, [setViews, view, currentRouteId, largeScreen, closed]);
const pinnedAsset = data && getAsset(data);
@@ -1,4 +1,4 @@
import { act, render, screen, within } from '@testing-library/react';
import { act, render, screen, waitFor, within } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import { Closed } from './closed';
import { MarketStateMapping, PropertyKeyType } from '@vegaprotocol/types';
@@ -300,9 +300,11 @@ describe('Closed', () => {
].includes(m.node.state);
});
// check rows length is correct
const rows = container.getAllByRole('row');
expect(rows).toHaveLength(expectedRows.length);
await waitFor(() => {
// check rows length is correct
const rows = container.getAllByRole('row');
expect(rows).toHaveLength(expectedRows.length);
});
// check that only included ids are shown
const cells = screen
@@ -22,6 +22,8 @@ import { SettlementPriceCell } from './settlement-price-cell';
import { useDataProvider } from '@vegaprotocol/data-provider';
import { MarketCodeCell } from './market-code-cell';
import { MarketActionsDropdown } from './market-table-actions';
import type { CellClickedEvent } from 'ag-grid-community';
import { useClosedMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
type SettlementAsset = Pick<
Asset,
@@ -125,6 +127,7 @@ const ClosedMarketsDataGrid = ({
rowData: Row[];
error: Error | undefined;
}) => {
const handleOnSelect = useClosedMarketClickHandler();
const openAssetDialog = useAssetDetailsDialogStore((store) => store.open);
const colDefs = useMemo(() => {
@@ -281,6 +284,27 @@ const ClosedMarketsDataGrid = ({
overlayNoRowsTemplate={error ? error.message : t('No markets')}
components={components}
rowHeight={45}
onCellClicked={({ data, column, event }: CellClickedEvent<Row>) => {
if (!data) return;
// prevent navigating to the market page if any of the below cells are clicked
// event.preventDefault or event.stopPropagation dont seem to apply for aggird
const colId = column.getColId();
if (
[
'settlementDate',
'settlementDataOracleId',
'settlementAsset',
'market-actions',
].includes(colId)
) {
return;
}
// @ts-ignore metaKey exists
handleOnSelect(data.id, event ? event.metaKey : false);
}}
/>
);
};
@@ -23,6 +23,10 @@ export const LayoutWithSidebar = () => {
<div className="col-span-full">
<Routes>
<Route path="markets/:marketId" element={<MarketHeader />} />
<Route
path="markets/all/closed/:marketId"
element={<MarketHeader />}
/>
<Route path="liquidity/:marketId" element={<LiquidityHeader />} />
</Routes>
</div>
@@ -7,6 +7,8 @@ import * as Schema from '@vegaprotocol/types';
import { HeaderStat } from '../header';
import { useCallback, useRef, useState } from 'react';
import * as constants from '../constants';
import { DocsLinks } from '@vegaprotocol/environment';
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
export const MarketState = ({ market }: { market: Market | null }) => {
const [marketState, setMarketState] = useState<Schema.MarketState | null>(
@@ -90,5 +92,20 @@ const getMarketStateTooltip = (state: Schema.MarketState | null) => {
);
}
if (state === Schema.MarketState.STATE_SUSPENDED_VIA_GOVERNANCE) {
return (
<p>
{t(
`This market has been suspended via a governance vote and can be resumed or terminated by further votes.`
)}
{DocsLinks && (
<ExternalLink href={DocsLinks.MARKET_LIFECYCLE} className="ml-1">
{t('Find out more')}
</ExternalLink>
)}
</p>
);
}
return undefined;
};
@@ -135,6 +135,21 @@ export const Sidebar = () => {
</>
}
/>
<Route
path="markets/all/closed/:marketId"
element={
<>
<AssetSidebarButtons />
<SidebarDivider />
<SidebarButton
view={ViewType.Info}
icon={VegaIconNames.BREAKDOWN}
tooltip={t('Market specification')}
routeId={currentRouteId}
/>
</>
}
/>
</Routes>
</nav>
<nav className={classNames(navClasses, 'ml-auto lg:mt-auto lg:ml-0')}>
@@ -20,3 +20,16 @@ export const useMarketLiquidityClickHandler = () => {
window.open(`/#/liquidity/${selectedId}`, metaKey ? '_blank' : '_self');
}, []);
};
export const useClosedMarketClickHandler = (replace = false) => {
const navigate = useNavigate();
return (selectedId: string, metaKey?: boolean) => {
const link = Links.CLOSED_MARKETS(selectedId);
if (metaKey) {
window.open(`/#${link}`, '_blank');
} else {
navigate(link, { replace });
}
};
};
+3
View File
@@ -5,6 +5,7 @@ import trimEnd from 'lodash/trimEnd';
export const Routes = {
HOME: '/',
MARKETS: '/markets/all',
CLOSED_MARKETS: '/markets/all/closed/:marketId',
MARKET: '/markets/:marketId',
LIQUIDITY: '/liquidity/:marketId',
PORTFOLIO: '/portfolio',
@@ -28,6 +29,8 @@ export const Links: ConsoleLinks = {
MARKET: (marketId: string) =>
trimEnd(Routes.MARKET.replace(':marketId', marketId)),
MARKETS: () => Routes.MARKETS,
CLOSED_MARKETS: (marketId: string) =>
trimEnd(Routes.CLOSED_MARKETS.replace(':marketId', marketId)),
PORTFOLIO: () => Routes.PORTFOLIO,
LIQUIDITY: (marketId: string) =>
trimEnd(Routes.LIQUIDITY.replace(':marketId', marketId)),
+1
View File
@@ -5,6 +5,7 @@ const MARKET_TEMPLATE = [
MarketState.STATE_ACTIVE,
MarketState.STATE_SUSPENDED,
MarketState.STATE_PENDING,
MarketState.STATE_SUSPENDED_VIA_GOVERNANCE,
];
export const isMarketActive = (state: MarketState) => {
+6
View File
@@ -26,6 +26,7 @@ import { FLAGS } from '@vegaprotocol/environment';
// These must remain dynamically imported as pennant cannot be compiled by nextjs due to ESM
// Using dynamic imports is a workaround for this until pennant is published as ESM
const MarketPage = lazy(() => import('../client-pages/market'));
const ClosedMarketPage = lazy(() => import('../client-pages/closed-market'));
const Portfolio = lazy(() => import('../client-pages/portfolio'));
const NotFound = () => (
@@ -101,6 +102,11 @@ export const routerConfig: RouteObject[] = compact([
element: <MarketPage />,
id: Routes.MARKET,
},
{
path: 'all/closed/:marketId',
element: <ClosedMarketPage />,
id: Routes.CLOSED_MARKETS,
},
],
},
{
@@ -62,6 +62,20 @@ const WrappedAssetDetailsDialog = ({ assetId }: { assetId: string }) => (
);
describe('AssetDetailsDialog', () => {
// 7001-COLL-008
// 6501-ASSE-001
// 6501-ASSE-002
// 6501-ASSE-003
// 6501-ASSE-004
// 6501-ASSE-005
// 6501-ASSE-006
// 6501-ASSE-007
// 6501-ASSE-008
// 6501-ASSE-009
// 6501-ASSE-010
// 6501-ASSE-011
// 6501-ASSE-012
// 6501-ASSE-013
it('should show no data message given unknown asset symbol', async () => {
render(<WrappedAssetDetailsDialog assetId={'UNKNOWN_FOR_SURE'} />);
expect((await screen.findByTestId('splash')).textContent).toContain(
@@ -264,7 +264,11 @@ export const DealTicket = ({
orders,
collateralAvailable:
marginAccountBalance || generalAccountBalance ? balance : undefined,
skip: !normalizedOrder,
skip:
!normalizedOrder ||
(normalizedOrder.type !== Schema.OrderType.TYPE_MARKET &&
(!normalizedOrder.price || normalizedOrder.price === '0')) ||
normalizedOrder.size === '0',
});
const assetSymbol = getAsset(market).symbol;
@@ -114,6 +114,20 @@ export const TradingModeTooltip = ({
</section>
);
}
case Schema.MarketTradingMode.TRADING_MODE_SUSPENDED_VIA_GOVERNANCE: {
return (
<section data-testid="trading-mode-suspended-via-governance">
{t(
`This market has been suspended via a governance vote and can be resumed or terminated by further votes.`
)}
{DocsLinks && (
<ExternalLink href={DocsLinks.MARKET_LIFECYCLE} className="ml-1">
{t('Find out more')}
</ExternalLink>
)}
</section>
);
}
case Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION: {
switch (trigger) {
case Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET: {
@@ -30,9 +30,11 @@ export const usePositionEstimate = ({
fetchPolicy: 'no-cache',
});
useEffect(() => {
if (data) {
if (skip) {
setEstimates(undefined);
} else if (data) {
setEstimates(data);
}
}, [data]);
}, [data, skip]);
return estimates;
};
@@ -423,6 +423,12 @@ function compileFeatureFlags(): FeatureFlags {
process.env['NX_UPDATE_MARKET_STATE']
) as string
),
GOVERNANCE_TRANSFERS: TRUTHY.includes(
windowOrDefault(
'NX_GOVERNANCE_TRANSFERS',
process.env['NX_GOVERNANCE_TRANSFERS']
) as string
),
};
const EXPLORER_FLAGS = {
EXPLORER_ASSETS: TRUTHY.includes(
+1
View File
@@ -80,6 +80,7 @@ export const DocsLinks = VEGA_DOCS_URL
LIQUIDITY: `${VEGA_DOCS_URL}/concepts/liquidity/provision`,
WITHDRAWAL_LIMITS: `${VEGA_DOCS_URL}/concepts/assets/deposits-withdrawals#withdrawal-limits`,
VALIDATOR_SCORES_REWARDS: `${VEGA_DOCS_URL}/concepts/vega-chain/validator-scores-and-rewards`,
MARKET_LIFECYCLE: `${VEGA_DOCS_URL}/concepts/trading-on-vega/market-lifecycle`,
}
: undefined;
+1
View File
@@ -25,6 +25,7 @@ export type CosmicElevatorFlags = Pick<
| 'METAMASK_SNAPS'
| 'REFERRALS'
| 'UPDATE_MARKET_STATE'
| 'GOVERNANCE_TRANSFERS'
>;
export type Configuration = z.infer<typeof tomlConfigSchema>;
export const CUSTOM_NODE_KEY = 'custom' as const;
@@ -80,6 +80,7 @@ const COSMIC_ELEVATOR_FLAGS = {
METAMASK_SNAPS: z.optional(z.boolean()),
REFERRALS: z.optional(z.boolean()),
UPDATE_MARKET_STATE: z.optional(z.boolean()),
GOVERNANCE_TRANSFERS: z.optional(z.boolean()),
};
const EXPLORER_FLAGS = {
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -4,6 +4,10 @@ fragment DataSourceFilter on Filter {
type
numberDecimalPlaces
}
conditions {
value
operator
}
}
fragment DataSource on DataSourceSpec {
@@ -12,6 +16,37 @@ fragment DataSource on DataSourceSpec {
sourceType {
... on DataSourceDefinitionExternal {
sourceType {
... on EthCallSpec {
abi
address
args
method
requiredConfirmations
normalisers {
name
expression
}
trigger {
trigger {
... on EthTimeTrigger {
initial
every
until
}
}
}
filters {
key {
name
type
numberDecimalPlaces
}
conditions {
value
operator
}
}
}
... on DataSourceSpecConfiguration {
signers {
signer {
File diff suppressed because one or more lines are too long
@@ -6,13 +6,21 @@ import { t } from '@vegaprotocol/i18n';
import { marketDataProvider } from '../../market-data-provider';
import { totalFeesPercentage } from '../../market-utils';
import {
Accordion,
AccordionChevron,
AccordionPanel,
CopyWithTooltip,
ExternalLink,
Intent,
KeyValueTable,
KeyValueTableRow,
Lozenge,
Splash,
SyntaxHighlighter,
Tooltip,
VegaIcon,
VegaIconNames,
truncateMiddle,
} from '@vegaprotocol/ui-toolkit';
import {
addDecimalsFormatNumber,
@@ -31,6 +39,7 @@ import { Last24hVolume } from '../last-24h-volume';
import BigNumber from 'bignumber.js';
import type {
DataSourceDefinition,
EthCallSpec,
MarketTradingMode,
SignerKind,
} from '@vegaprotocol/types';
@@ -40,6 +49,7 @@ import {
} from '@vegaprotocol/types';
import {
DApp,
EtherscanLink,
FLAGS,
TOKEN_PROPOSAL,
useEnvironment,
@@ -65,6 +75,7 @@ import {
} from '@vegaprotocol/network-parameters';
import type { DataSourceFragment } from './__generated__/MarketInfo';
import { formatDuration } from 'date-fns';
import * as AccordionPrimitive from '@radix-ui/react-accordion';
type MarketInfoProps = {
market: MarketInfo;
@@ -659,6 +670,97 @@ export const LiquidityMonitoringParametersInfoPanel = ({
return <MarketInfoTable data={marketData} parentData={parentMarketData} />;
};
export const EthOraclePanel = ({ sourceType }: { sourceType: EthCallSpec }) => {
const abis = sourceType.abi?.map((abi) => JSON.parse(abi));
const header = 'uppercase my-1 text-left';
return (
<>
<h3 className={header}>{t('Ethereum Oracle')}</h3>
{sourceType.address && (
<>
<KeyValueTable>
<KeyValueTableRow noBorder>
<div>{t('Address')}</div>
<CopyWithTooltip text={sourceType.address}>
<button
data-testid="copy-eth-oracle-address"
className="uppercase text-right"
>
<span className="flex gap-1">
{truncateMiddle(sourceType.address)}
<VegaIcon name={VegaIconNames.COPY} size={16} />
</span>
</button>
</CopyWithTooltip>
</KeyValueTableRow>
</KeyValueTable>
<div className="my-2">
<EtherscanLink address={sourceType.address}>
{t('View on Etherscan')}
</EtherscanLink>
</div>
</>
)}
<MarketInfoTable
key="eth-call-spec"
data={{
method: sourceType.method,
requiredConfirmations: sourceType.requiredConfirmations,
}}
/>
<Accordion>
<AccordionPanel
itemId="abi"
trigger={
<AccordionPrimitive.Trigger
data-testid="accordion-toggle"
className={classNames(
'w-full pt-2',
'flex items-center gap-2',
'group'
)}
>
<div
data-testid={`abi-dropdown`}
key={'value-dropdown'}
className="flex items-center gap-2 w-full"
>
<div className="underline underline-offset-4 mb-1 uppercase">
{t('ABI specification')}
</div>
<AccordionChevron size={14} />
<div className="flex items-center gap-1"></div>
</div>
</AccordionPrimitive.Trigger>
}
>
<SyntaxHighlighter data={abis} />
</AccordionPanel>
</Accordion>
<h3 className={header}>{t('Normalisers')}</h3>
{sourceType.normalisers?.map((normaliser, i) => (
<MarketInfoTable key={i} data={normaliser} />
))}
<h3 className={header}>{t('Filters')}</h3>
<h3 className={header}>{t('Key')}</h3>
{sourceType.filters?.map((filter, i) => (
<>
<MarketInfoTable key={i} data={filter.key} />
<h3 className={header}>{t('Conditions')}</h3>
{filter.conditions?.map((condition, i) => (
<span>
{ConditionOperatorMapping[condition.operator]} {condition.value}
</span>
))}
</>
))}
</>
);
};
export const LiquidityPriceRangeInfoPanel = ({
market,
parentMarket,
@@ -782,7 +884,7 @@ export const LiquiditySLAParametersInfoPanel = ({
market.liquiditySLAParameters?.slaCompetitionFactor
).times(100)
),
commitmentMinimumTimeFraction:
commitmentMinTimeFraction:
market.liquiditySLAParameters?.commitmentMinTimeFraction &&
formatNumberPercentage(
new BigNumber(
@@ -797,7 +899,7 @@ export const LiquiditySLAParametersInfoPanel = ({
parentMarket.liquiditySLAParameters?.performanceHysteresisEpochs,
slaCompetitionFactor:
parentMarket.liquiditySLAParameters?.slaCompetitionFactor,
commitmentMinimumTimeFraction:
commitmentMinTimeFraction:
parentMarket.liquiditySLAParameters?.commitmentMinTimeFraction,
}
: undefined;
@@ -823,13 +925,13 @@ export const LiquiditySLAParametersInfoPanel = ({
networkParams['market_liquidity_nonPerformanceBondPenaltySlope'],
nonPerformanceBondPenaltyMax:
networkParams['market_liquidity_sla_nonPerformanceBondPenaltyMax'],
maximumLiquidityFeeFactorLevel:
maxLiquidityFeeFactorLevel:
networkParams['market_liquidity_maximumLiquidityFeeFactorLevel'],
stakeToCCYVolume: networkParams['market_liquidity_stakeToCcyVolume'],
earlyExitPenalty: networkParams['market_liquidity_earlyExitPenalty'],
probabilityOfTradingTauScaling:
networkParams['market_liquidity_probabilityOfTrading_tau_scaling'],
minimumProbabilityOfTradingLPOrders:
minProbabilityOfTradingLPOrders:
networkParams['market_liquidity_minimum_probabilityOfTrading_lpOrders'],
feeCalculationTimeStep:
networkParams['market_liquidity_feeCalculationTimeStep'] &&
@@ -931,6 +1033,10 @@ export const OracleInfoPanel = ({
</Lozenge>
)}
{dataSourceSpec?.sourceType.sourceType.__typename === 'EthCallSpec' && (
<EthOraclePanel sourceType={dataSourceSpec?.sourceType.sourceType} />
)}
<div className={wrapperClasses}>
{shouldShowParentData &&
parentDataSourceSpec &&
@@ -945,6 +1051,13 @@ export const OracleInfoPanel = ({
dataSourceSpecId={parentDataSourceSpecId}
/>
{parentDataSourceSpec?.sourceType.sourceType.__typename ===
'EthCallSpec' && (
<EthOraclePanel
sourceType={parentDataSourceSpec?.sourceType.sourceType}
/>
)}
{dataSourceSpecId && (
<ExternalLink
data-testid="oracle-spec-links"
@@ -106,7 +106,7 @@ export const tooltipMapping: Record<string, ReactNode> = {
insurancePoolFraction: t(
'The fraction of the insurance pool balance that is carried over from the parent market to the successor.'
),
commitmentMinimumTimeFraction: t(
commitmentMinTimeFraction: t(
`Specifies the minimum fraction of time LPs must spend 'on the book' providing their committed liquidity. This is a market parameter.`
),
feeCalculationTimeStep: t(
@@ -127,7 +127,7 @@ export const tooltipMapping: Record<string, ReactNode> = {
nonPerformanceBondPenaltyMax: t(
`The maximum amount, as a fraction, that an LP's bond can be slashed by if they fail to reach the minimum SLA. This is a network parameter.`
),
maximumLiquidityFeeFactorLevel: t(
maxLiquidityFeeFactorLevel: t(
'Maximum value that a proposed fee amount can be, which is submitted as part of the LP commitment transaction. Note that a value of 0.05 = 5%. This is a network parameter.'
),
stakeToCCYVolume: t(
@@ -137,12 +137,12 @@ export const tooltipMapping: Record<string, ReactNode> = {
'How long an epoch is. LP rewards from liquidity fees are paid out once per epoch. How much they receive depends on whether they met the liquidity SLA and their previous performance in recent epochs. This is a network parameter.'
),
earlyExitPenalty: t(
`How much an LP forfeits of their bond if they reduce their commitment while the market is below target stake, expressed as a factor. If set to 0 there is no penalty for early exit. If set to 1 an LP's entire bond is forfeited when an LP removes their full commitment. This is a network parameter.`
`The percentage of their bond an LP forfeits if they reduce their commitment while the market is below target stake. If 100%, an LP's entire bond is forfeited when they cancel their full commitment. This is a network parameter.`
),
probabilityOfTradingTauScaling: t(
`Determines how the probability of trading is scaled from the risk model, and is used to measure the relative competitiveness of an LP's supplied volume. This is a network parameter.`
),
minimumProbabilityOfTradingLPOrders: t(
minProbabilityOfTradingLPOrders: t(
'The lower bound for the probability of trading calculation, used to measure liquidity available on a market to determine if LPs are meeting their commitment. This is a network parameter.'
),
};
+2
View File
@@ -96,6 +96,7 @@ export const createMarketFragment = (
filters: [
{
__typename: 'Filter',
conditions: [],
key: {
__typename: 'PropertyKey',
name: 'settlement-data-property',
@@ -129,6 +130,7 @@ export const createMarketFragment = (
filters: [
{
__typename: 'Filter',
conditions: [],
key: {
__typename: 'PropertyKey',
name: 'settlement-data-property',
@@ -0,0 +1,39 @@
import { render, screen, fireEvent } from '@testing-library/react';
import { PositionsManager } from './positions-manager';
import { positionsMarketsProvider } from './positions-data-providers';
import { singleRow } from './positions.mock';
import { MockedProvider } from '@apollo/client/testing';
import { MAXGOINT64 } from '@vegaprotocol/utils';
const mockCreate = jest.fn();
jest.mock('@vegaprotocol/wallet', () => ({
...jest.requireActual('@vegaprotocol/wallet'),
useVegaWallet: jest.fn(() => ({ pubKey: 'partyId' })),
useVegaTransactionStore: jest.fn(() => mockCreate),
}));
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const mockUseDataProvider = (args: any) => {
if (args.dataProvider === positionsMarketsProvider) {
return { data: ['market-1', 'market-2'] };
}
return { data: [singleRow] };
};
jest.mock('@vegaprotocol/data-provider', () => ({
...jest.requireActual('@vegaprotocol/data-provider'),
useDataProvider: jest.fn((args) => mockUseDataProvider(args)),
}));
describe('PositionsManager', () => {
it('should close position with max uint64', async () => {
render(<PositionsManager partyIds={['partyId']} isReadOnly={false} />, {
wrapper: MockedProvider,
});
expect(await screen.getByTestId('close-position')).toBeInTheDocument();
fireEvent.click(screen.getByTestId('close-position'));
expect(
mockCreate.mock.lastCall[0].batchMarketInstructions.submissions[0].size
).toEqual(MAXGOINT64);
});
});
+3 -3
View File
@@ -1,7 +1,7 @@
import { useCallback } from 'react';
import { PositionsTable } from './positions-table';
import * as Schema from '@vegaprotocol/types';
import { useVegaTransactionStore } from '@vegaprotocol/wallet';
import { useVegaTransactionStore, useVegaWallet } from '@vegaprotocol/wallet';
import { t } from '@vegaprotocol/i18n';
import { useDataProvider } from '@vegaprotocol/data-provider';
import {
@@ -9,7 +9,7 @@ import {
positionsMarketsProvider,
} from './positions-data-providers';
import type { useDataGridEvents } from '@vegaprotocol/datagrid';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { MAXGOINT64 } from '@vegaprotocol/utils';
interface PositionsManagerProps {
partyIds: string[];
@@ -46,7 +46,7 @@ export const PositionsManager = ({
side: openVolume.startsWith('-')
? Schema.Side.SIDE_BUY
: Schema.Side.SIDE_SELL,
size: openVolume.replace('-', ''),
size: MAXGOINT64, // improvement for avoiding leftovers filled in the meantime when close request has been sent
reduceOnly: true,
},
],
@@ -6,6 +6,7 @@ import * as Schema from '@vegaprotocol/types';
import { PositionStatus } from '@vegaprotocol/types';
import type { ICellRendererParams } from 'ag-grid-community';
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
import { singleRow } from './positions.mock';
jest.mock('./liquidation-price', () => ({
LiquidationPrice: () => (
@@ -13,33 +14,6 @@ jest.mock('./liquidation-price', () => ({
),
}));
const singleRow: Position = {
partyId: 'partyId',
assetId: 'asset-id',
assetSymbol: 'BTC',
averageEntryPrice: '133',
currentLeverage: 1.1,
assetDecimals: 2, // this is settlementAsset.decimals
quantum: '0.1',
lossSocializationAmount: '0',
marginAccountBalance: '12345600',
marketDecimalPlaces: 1,
marketId: 'string',
marketCode: 'ETHBTC.QM21',
marketTradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
marketState: Schema.MarketState.STATE_ACTIVE,
markPrice: '123',
notional: '12300',
openVolume: '100',
positionDecimalPlaces: 0,
realisedPNL: '123',
status: PositionStatus.POSITION_STATUS_UNSPECIFIED,
totalBalance: '123456',
unrealisedPNL: '456',
updatedAt: '2022-07-27T15:02:58.400Z',
productType: 'Future',
};
describe('Positions', () => {
const renderComponent = async (rowData: Position) => {
await act(async () => {
+29
View File
@@ -10,6 +10,8 @@ import type {
MarginsQuery,
MarginFieldsFragment,
} from '@vegaprotocol/accounts';
import type { Position } from './positions-data-providers';
import * as Schema from '@vegaprotocol/types';
export const positionsQuery = (
override?: PartialDeep<PositionsQuery>
@@ -168,3 +170,30 @@ const marginsFields: MarginFieldsFragment[] = [
},
},
];
export const singleRow: Position = {
partyId: 'partyId',
assetId: 'asset-id',
assetSymbol: 'BTC',
averageEntryPrice: '133',
currentLeverage: 1.1,
assetDecimals: 2, // this is settlementAsset.decimals
quantum: '0.1',
lossSocializationAmount: '0',
marginAccountBalance: '12345600',
marketDecimalPlaces: 1,
marketId: 'string',
marketCode: 'ETHBTC.QM21',
marketTradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
marketState: Schema.MarketState.STATE_ACTIVE,
markPrice: '123',
notional: '12300',
openVolume: '100',
positionDecimalPlaces: 0,
realisedPNL: '123',
status: PositionStatus.POSITION_STATUS_UNSPECIFIED,
totalBalance: '123456',
unrealisedPNL: '456',
updatedAt: '2022-07-27T15:02:58.400Z',
productType: 'Future',
};
@@ -334,6 +334,36 @@ fragment UpdateNetworkParameterFields on UpdateNetworkParameter {
}
}
fragment NewTransferFields on NewTransfer {
source
sourceType
destination
destinationType
asset {
id
symbol
decimals
quantum
}
fraction_of_balance
amount
transferType
kind {
__typename
... on OneOffGovernanceTransfer {
deliverOn
}
... on RecurringGovernanceTransfer {
startEpoch
endEpoch
}
}
}
fragment CancelTransferFields on CancelTransfer {
transferId
}
fragment ProposalListFields on Proposal {
id
rationale {
File diff suppressed because one or more lines are too long
@@ -67,3 +67,29 @@ query InstrumentDetails($marketId: ID!) {
}
}
}
query NewTransferDetails($proposalId: ID!) {
proposal(id: $proposalId) {
id
terms {
change {
... on NewTransfer {
...NewTransferFields
}
}
}
}
}
query CancelTransferDetails($proposalId: ID!) {
proposal(id: $proposalId) {
id
terms {
change {
... on CancelTransfer {
...CancelTransferFields
}
}
}
}
}
@@ -1,7 +1,7 @@
import * as Types from '@vegaprotocol/types';
import { gql } from '@apollo/client';
import { UpdateNetworkParameterFieldsFragmentDoc } from '../../proposals-data-provider/__generated__/Proposals';
import { UpdateNetworkParameterFieldsFragmentDoc, NewTransferFieldsFragmentDoc, CancelTransferFieldsFragmentDoc } from '../../proposals-data-provider/__generated__/Proposals';
import * as Apollo from '@apollo/client';
const defaultOptions = {} as const;
export type ProposalEventFieldsFragment = { __typename?: 'Proposal', id?: string | null, reference: string, state: Types.ProposalState, rejectionReason?: Types.ProposalRejectionReason | null, errorDetails?: string | null };
@@ -41,6 +41,20 @@ export type InstrumentDetailsQueryVariables = Types.Exact<{
export type InstrumentDetailsQuery = { __typename?: 'Query', market?: { __typename?: 'Market', tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', code: string, name: string } } } | null };
export type NewTransferDetailsQueryVariables = Types.Exact<{
proposalId: Types.Scalars['ID'];
}>;
export type NewTransferDetailsQuery = { __typename?: 'Query', proposal?: { __typename?: 'Proposal', id?: string | null, terms: { __typename?: 'ProposalTerms', change: { __typename?: 'CancelTransfer' } | { __typename?: 'NewAsset' } | { __typename?: 'NewFreeform' } | { __typename?: 'NewMarket' } | { __typename?: 'NewSpotMarket' } | { __typename?: 'NewTransfer', source: string, sourceType: Types.AccountType, destination: string, destinationType: Types.AccountType, fraction_of_balance: string, amount: string, transferType: Types.GovernanceTransferType, asset: { __typename?: 'Asset', id: string, symbol: string, decimals: number, quantum: string }, kind: { __typename: 'OneOffGovernanceTransfer', deliverOn?: any | null } | { __typename: 'RecurringGovernanceTransfer', startEpoch: number, endEpoch?: number | null } } | { __typename?: 'UpdateAsset' } | { __typename?: 'UpdateMarket' } | { __typename?: 'UpdateMarketState' } | { __typename?: 'UpdateNetworkParameter' } | { __typename?: 'UpdateReferralProgram' } | { __typename?: 'UpdateSpotMarket' } | { __typename?: 'UpdateVolumeDiscountProgram' } } } | null };
export type CancelTransferDetailsQueryVariables = Types.Exact<{
proposalId: Types.Scalars['ID'];
}>;
export type CancelTransferDetailsQuery = { __typename?: 'Query', proposal?: { __typename?: 'Proposal', id?: string | null, terms: { __typename?: 'ProposalTerms', change: { __typename?: 'CancelTransfer', transferId: string } | { __typename?: 'NewAsset' } | { __typename?: 'NewFreeform' } | { __typename?: 'NewMarket' } | { __typename?: 'NewSpotMarket' } | { __typename?: 'NewTransfer' } | { __typename?: 'UpdateAsset' } | { __typename?: 'UpdateMarket' } | { __typename?: 'UpdateMarketState' } | { __typename?: 'UpdateNetworkParameter' } | { __typename?: 'UpdateReferralProgram' } | { __typename?: 'UpdateSpotMarket' } | { __typename?: 'UpdateVolumeDiscountProgram' } } } | null };
export const ProposalEventFieldsFragmentDoc = gql`
fragment ProposalEventFields on Proposal {
id
@@ -246,4 +260,88 @@ export function useInstrumentDetailsLazyQuery(baseOptions?: Apollo.LazyQueryHook
}
export type InstrumentDetailsQueryHookResult = ReturnType<typeof useInstrumentDetailsQuery>;
export type InstrumentDetailsLazyQueryHookResult = ReturnType<typeof useInstrumentDetailsLazyQuery>;
export type InstrumentDetailsQueryResult = Apollo.QueryResult<InstrumentDetailsQuery, InstrumentDetailsQueryVariables>;
export type InstrumentDetailsQueryResult = Apollo.QueryResult<InstrumentDetailsQuery, InstrumentDetailsQueryVariables>;
export const NewTransferDetailsDocument = gql`
query NewTransferDetails($proposalId: ID!) {
proposal(id: $proposalId) {
id
terms {
change {
... on NewTransfer {
...NewTransferFields
}
}
}
}
}
${NewTransferFieldsFragmentDoc}`;
/**
* __useNewTransferDetailsQuery__
*
* To run a query within a React component, call `useNewTransferDetailsQuery` and pass it any options that fit your needs.
* When your component renders, `useNewTransferDetailsQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useNewTransferDetailsQuery({
* variables: {
* proposalId: // value for 'proposalId'
* },
* });
*/
export function useNewTransferDetailsQuery(baseOptions: Apollo.QueryHookOptions<NewTransferDetailsQuery, NewTransferDetailsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<NewTransferDetailsQuery, NewTransferDetailsQueryVariables>(NewTransferDetailsDocument, options);
}
export function useNewTransferDetailsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<NewTransferDetailsQuery, NewTransferDetailsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<NewTransferDetailsQuery, NewTransferDetailsQueryVariables>(NewTransferDetailsDocument, options);
}
export type NewTransferDetailsQueryHookResult = ReturnType<typeof useNewTransferDetailsQuery>;
export type NewTransferDetailsLazyQueryHookResult = ReturnType<typeof useNewTransferDetailsLazyQuery>;
export type NewTransferDetailsQueryResult = Apollo.QueryResult<NewTransferDetailsQuery, NewTransferDetailsQueryVariables>;
export const CancelTransferDetailsDocument = gql`
query CancelTransferDetails($proposalId: ID!) {
proposal(id: $proposalId) {
id
terms {
change {
... on CancelTransfer {
...CancelTransferFields
}
}
}
}
}
${CancelTransferFieldsFragmentDoc}`;
/**
* __useCancelTransferDetailsQuery__
*
* To run a query within a React component, call `useCancelTransferDetailsQuery` and pass it any options that fit your needs.
* When your component renders, `useCancelTransferDetailsQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useCancelTransferDetailsQuery({
* variables: {
* proposalId: // value for 'proposalId'
* },
* });
*/
export function useCancelTransferDetailsQuery(baseOptions: Apollo.QueryHookOptions<CancelTransferDetailsQuery, CancelTransferDetailsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<CancelTransferDetailsQuery, CancelTransferDetailsQueryVariables>(CancelTransferDetailsDocument, options);
}
export function useCancelTransferDetailsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<CancelTransferDetailsQuery, CancelTransferDetailsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<CancelTransferDetailsQuery, CancelTransferDetailsQueryVariables>(CancelTransferDetailsDocument, options);
}
export type CancelTransferDetailsQueryHookResult = ReturnType<typeof useCancelTransferDetailsQuery>;
export type CancelTransferDetailsLazyQueryHookResult = ReturnType<typeof useCancelTransferDetailsLazyQuery>;
export type CancelTransferDetailsQueryResult = Apollo.QueryResult<CancelTransferDetailsQuery, CancelTransferDetailsQueryVariables>;
@@ -4,3 +4,5 @@ export * from './use-proposal-submit';
export * from './use-update-proposal';
export * from './use-update-network-paramaters-toasts';
export * from './use-successor-market-proposal-details';
export * from './use-new-transfer-proposal-details';
export * from './use-cancel-transfer-proposal-details';
@@ -0,0 +1,19 @@
import type { CancelTransferFieldsFragment } from '../proposals-data-provider';
import { useCancelTransferDetailsQuery } from './__generated__/Proposal';
export const useCancelTransferProposalDetails = (
proposalId?: string | null
) => {
const { data } = useCancelTransferDetailsQuery({
variables: {
proposalId: proposalId || '',
},
skip: !proposalId || proposalId.length === 0,
});
if (data?.proposal?.terms.change.__typename === 'CancelTransfer') {
return data?.proposal?.terms.change as CancelTransferFieldsFragment;
}
return undefined;
};
@@ -0,0 +1,17 @@
import type { NewTransferFieldsFragment } from '../proposals-data-provider';
import { useNewTransferDetailsQuery } from './__generated__/Proposal';
export const useNewTransferProposalDetails = (proposalId?: string | null) => {
const { data } = useNewTransferDetailsQuery({
variables: {
proposalId: proposalId || '',
},
skip: !proposalId || proposalId.length === 0,
});
if (data?.proposal?.terms.change.__typename === 'NewTransfer') {
return data?.proposal?.terms.change as NewTransferFieldsFragment;
}
return undefined;
};
+146 -20
View File
@@ -505,6 +505,29 @@ export type CoreSnapshotEdge = {
node: CoreSnapshotData;
};
/** Referral program information reported by data node with additional endedAt timestamp. */
export type CurrentReferralProgram = {
__typename?: 'CurrentReferralProgram';
/** Defined tiers in increasing order. First element will give Tier 1, second element will give Tier 2, etc. */
benefitTiers: Array<BenefitTier>;
/** Timestamp as RFC3339Nano, after which when the current epoch ends, the program will end and benefits will be disabled. */
endOfProgramTimestamp: Scalars['Timestamp'];
/** Timestamp as RFC3339Nano when the program ended. If present, the current program has ended and no program is currently running. */
endedAt?: Maybe<Scalars['Timestamp']>;
/** Unique ID generated from the proposal that created this program. */
id: Scalars['ID'];
/**
* Defined staking tiers in increasing order. First element will give Tier 1,
* second element will give Tier 2, and so on. Determines the level of
* benefit a party can expect based on their staking.
*/
stakingTiers: Array<StakingTier>;
/** Incremental version of the program. It is incremented each time the referral program is edited. */
version: Scalars['Int'];
/** Number of epochs over which to evaluate a referral set's running volume. */
windowLength: Scalars['Int'];
};
/** A data source contains the data sent by a data source */
export type Data = {
__typename?: 'Data';
@@ -1607,6 +1630,8 @@ export type LiquidityProvider = {
marketId: Scalars['ID'];
/** Party ID of the liquidity provider */
partyId: Scalars['ID'];
/** SLA performance statistics */
sla?: Maybe<LiquidityProviderSLA>;
};
/** Connection type for retrieving cursor-based paginated liquidity provider information */
@@ -1642,6 +1667,29 @@ export type LiquidityProviderFeeShare = {
virtualStake: Scalars['String'];
};
/** The SLA statistics for each liquidity provider */
export type LiquidityProviderSLA = {
__typename?: 'LiquidityProviderSLA';
/** Indicates how often LP meets the commitment during the current epoch. */
currentEpochFractionOfTimeOnBook: Scalars['String'];
/** Determines how the fee penalties from past epochs affect future fee revenue. */
hysteresisPeriodFeePenalties?: Maybe<Array<Scalars['String']>>;
/** Indicates the bond penalty amount applied in the previous epoch. */
lastEpochBondPenalty: Scalars['String'];
/** Indicates the fee penalty amount applied in the previous epoch. */
lastEpochFeePenalty: Scalars['String'];
/** Indicates how often LP met the commitment in the previous epoch. */
lastEpochFractionOfTimeOnBook: Scalars['String'];
/** Notional volume of orders within the range provided on the buy side of the book. */
notionalVolumeBuys: Scalars['String'];
/** Notional volume of orders within the range provided on the sell side of the book. */
notionalVolumeSells: Scalars['String'];
/** The liquidity provider party ID */
party: Party;
/** Represents the total amount of funds LP must supply. The amount to be supplied is in the markets settlement currency, spread on both buy and sell sides of the order book within a defined range. */
requiredLiquidity: Scalars['String'];
};
/** The command to be sent to the chain for a liquidity provision submission */
export type LiquidityProvision = {
__typename?: 'LiquidityProvision';
@@ -2030,6 +2078,8 @@ export type MarketData = {
lastTradedPrice: Scalars['String'];
/** The equity like share of liquidity fee for each liquidity provider */
liquidityProviderFeeShare?: Maybe<Array<LiquidityProviderFeeShare>>;
/** SLA performance statistics */
liquidityProviderSla?: Maybe<Array<LiquidityProviderSLA>>;
/** The mark price (an unsigned integer) */
markPrice: Scalars['String'];
/** Market of the associated mark price */
@@ -2562,6 +2612,29 @@ export type ObservableLiquidityProviderFeeShare = {
partyId: Scalars['ID'];
};
/** The SLA statistics for each liquidity provider */
export type ObservableLiquidityProviderSLA = {
__typename?: 'ObservableLiquidityProviderSLA';
/** Indicates how often LP meets the commitment during the current epoch. */
currentEpochFractionOfTimeOnBook: Scalars['String'];
/** Determines how the fee penalties from past epochs affect future fee revenue. */
hysteresisPeriodFeePenalties?: Maybe<Array<Scalars['String']>>;
/** Indicates the bond penalty amount applied in the previous epoch. */
lastEpochBondPenalty: Scalars['String'];
/** Indicates the fee penalty amount applied in the previous epoch. */
lastEpochFeePenalty: Scalars['String'];
/** Indicates how often LP meets the commitment during last epoch. */
lastEpochFractionOfTimeOnBook: Scalars['String'];
/** Notional volume of orders within the range provided on the buy side of the book. */
notionalVolumeBuys: Scalars['String'];
/** Notional volume of orders within the range provided on the sell side of the book. */
notionalVolumeSells: Scalars['String'];
/** The liquidity provider party ID */
party: Scalars['ID'];
/** Represents the total amount of funds LP must supply. The amount to be supplied is in the markets settlement currency, spread on both buy and sell sides of the order book within a defined range. */
requiredLiquidity: Scalars['String'];
};
/** Live data of a Market */
export type ObservableMarketData = {
__typename?: 'ObservableMarketData';
@@ -2595,6 +2668,8 @@ export type ObservableMarketData = {
lastTradedPrice: Scalars['String'];
/** The equity like share of liquidity fee for each liquidity provider */
liquidityProviderFeeShare?: Maybe<Array<ObservableLiquidityProviderFeeShare>>;
/** SLA performance statistics */
liquidityProviderSla?: Maybe<Array<ObservableLiquidityProviderSLA>>;
/** The mark price (an unsigned integer) */
markPrice: Scalars['String'];
/** The market growth factor for the last market time window */
@@ -3289,6 +3364,15 @@ export type PartyActivityStreak = {
tradedVolume: Scalars['String'];
};
/** An amount received by a party as a reward or a discount */
export type PartyAmount = {
__typename?: 'PartyAmount';
/** Amount received by the party */
amount: Scalars['String'];
/** Id of the party that received the payment */
partyId: Scalars['String'];
};
/** Connection type for retrieving cursor-based paginated party information */
export type PartyConnection = {
__typename?: 'PartyConnection';
@@ -3861,6 +3945,8 @@ export type ProposalTerms = {
/** Various proposal types that are supported by Vega */
export enum ProposalType {
/** Proposal to cancel a transfer */
TYPE_CANCEL_TRANSFER = 'TYPE_CANCEL_TRANSFER',
/** Proposal to change Vega network parameters */
TYPE_NETWORK_PARAMETERS = 'TYPE_NETWORK_PARAMETERS',
/** Proposal to add a new asset */
@@ -3869,10 +3955,22 @@ export enum ProposalType {
TYPE_NEW_FREE_FORM = 'TYPE_NEW_FREE_FORM',
/** Propose a new market */
TYPE_NEW_MARKET = 'TYPE_NEW_MARKET',
/** Propose a new spot market */
TYPE_NEW_SPOT_MARKET = 'TYPE_NEW_SPOT_MARKET',
/** Propose a new transfer */
TYPE_NEW_TRANSFER = 'TYPE_NEW_TRANSFER',
/** Proposal to update an existing asset */
TYPE_UPDATE_ASSET = 'TYPE_UPDATE_ASSET',
/** Update an existing market */
TYPE_UPDATE_MARKET = 'TYPE_UPDATE_MARKET'
TYPE_UPDATE_MARKET = 'TYPE_UPDATE_MARKET',
/** Proposal for updating the state of a market */
TYPE_UPDATE_MARKET_STATE = 'TYPE_UPDATE_MARKET_STATE',
/** Proposal to update the referral program */
TYPE_UPDATE_REFERRAL_PROGRAM = 'TYPE_UPDATE_REFERRAL_PROGRAM',
/** Update an existing spot market */
TYPE_UPDATE_SPOT_MARKET = 'TYPE_UPDATE_SPOT_MARKET',
/** Proposal to update the volume discount program */
TYPE_UPDATE_VOLUME_DISCOUNT_PROGRAM = 'TYPE_UPDATE_VOLUME_DISCOUNT_PROGRAM'
}
export type ProposalVote = {
@@ -3998,7 +4096,7 @@ export type Query = {
/** List core snapshots */
coreSnapshots?: Maybe<CoreSnapshotConnection>;
/** Get the current referral program */
currentReferralProgram?: Maybe<ReferralProgram>;
currentReferralProgram?: Maybe<CurrentReferralProgram>;
/** Find a deposit using its ID */
deposit?: Maybe<Deposit>;
/** Fetch all deposits */
@@ -4095,6 +4193,8 @@ export type Query = {
protocolUpgradeProposals?: Maybe<ProtocolUpgradeProposalConnection>;
/** Flag indicating whether the data-node is ready to begin the protocol upgrade */
protocolUpgradeStatus?: Maybe<ProtocolUpgradeStatus>;
/** Get referrer fee and discount stats */
referralFeeStats?: Maybe<ReferralSetFeeStats>;
referralSetReferees: ReferralSetRefereeConnection;
/** List referral sets */
referralSets: ReferralSetConnection;
@@ -4259,6 +4359,7 @@ export type QueryestimatePositionArgs = {
marketId: Scalars['ID'];
openVolume: Scalars['String'];
orders?: InputMaybe<Array<OrderInfo>>;
scaleLiquidationPriceToMarketDecimals?: InputMaybe<Scalars['Boolean']>;
};
@@ -4450,6 +4551,14 @@ export type QueryprotocolUpgradeProposalsArgs = {
};
/** Queries allow a caller to read data and filter data via GraphQL. */
export type QueryreferralFeeStatsArgs = {
assetId?: InputMaybe<Scalars['ID']>;
epoch?: InputMaybe<Scalars['Int']>;
marketId?: InputMaybe<Scalars['ID']>;
};
/** Queries allow a caller to read data and filter data via GraphQL. */
export type QueryreferralSetRefereesArgs = {
id?: InputMaybe<Scalars['ID']>;
@@ -4595,6 +4704,8 @@ export type RefereeStats = {
__typename?: 'RefereeStats';
/** Discount factor applied to the party. */
discountFactor: Scalars['String'];
/** Current referee notional taker volume */
epochNotionalTakerVolume: Scalars['String'];
/** Unique ID of the party. */
partyId: Scalars['ID'];
/** Reward factor applied to the party. */
@@ -4606,10 +4717,8 @@ export type ReferralProgram = {
__typename?: 'ReferralProgram';
/** Defined tiers in increasing order. First element will give Tier 1, second element will give Tier 2, etc. */
benefitTiers: Array<BenefitTier>;
/** Timestamp as RFC3339Nano, after which when the current epoch ends, the programs status will become STATE_CLOSED and benefits will be disabled. */
endOfProgramTimestamp: Scalars['Timestamp'];
/** Timestamp as RFC3339Nano when the program ended. If present, the current program has ended and no program is currently running. */
endedAt?: Maybe<Scalars['Timestamp']>;
/** Timestamp as RFC3339, after which when the current epoch ends, the programs will end and benefits will be disabled. */
endOfProgramTimestamp: Scalars['String'];
/** Unique ID generated from the proposal that created this program. */
id: Scalars['ID'];
/**
@@ -4667,6 +4776,25 @@ export type ReferralSetEdge = {
node: ReferralSet;
};
/** Referral rewards and discounts that have been applied on a specific market/asset up to the given epoch. */
export type ReferralSetFeeStats = {
__typename?: 'ReferralSetFeeStats';
/** The settlement asset of the market. */
assetId: Scalars['String'];
/** The epoch for which these stats were valid. */
epoch: Scalars['Int'];
/** The market the fees were paid in */
marketId: Scalars['String'];
/** The total referral discounts applied to all referee taker fees */
refereesDiscountApplied: Array<PartyAmount>;
/** The total referral rewards generated by all referee taker fees. */
referrerRewardsGenerated: Array<ReferrerRewardsGenerated>;
/** The total referral rewards paid to the referrer of the referral set. */
totalRewardsPaid: Array<PartyAmount>;
/** The total volume discounts applied to all referee taker fees */
volumeDiscountApplied: Array<PartyAmount>;
};
/** Data relating to referees that have joined a referral set */
export type ReferralSetReferee = {
__typename?: 'ReferralSetReferee';
@@ -4710,6 +4838,15 @@ export type ReferralSetStats = {
setId: Scalars['ID'];
};
/** Rewards generated for referrers by each of their referees */
export type ReferrerRewardsGenerated = {
__typename?: 'ReferrerRewardsGenerated';
/** The amount of rewards generated per party */
generatedReward: Array<PartyAmount>;
/** ID of the referral set's referrer */
referrerId: Scalars['String'];
};
/** Reward information for a single party */
export type Reward = {
__typename?: 'Reward';
@@ -5152,10 +5289,10 @@ export enum StopOrderRejectionReason {
REJECTION_REASON_MAX_STOP_ORDERS_PER_PARTY_REACHED = 'REJECTION_REASON_MAX_STOP_ORDERS_PER_PARTY_REACHED',
/** Stop orders submission must be reduce only */
REJECTION_REASON_MUST_BE_REDUCE_ONLY = 'REJECTION_REASON_MUST_BE_REDUCE_ONLY',
/** This stop order does not close the position */
REJECTION_REASON_STOP_ORDER_DOES_NOT_CLOSE_POSITION = 'REJECTION_REASON_STOP_ORDER_DOES_NOT_CLOSE_POSITION',
/** Stop orders are not allowed without a position */
REJECTION_REASON_STOP_ORDER_NOT_ALLOWED_WITHOUT_A_POSITION = 'REJECTION_REASON_STOP_ORDER_NOT_ALLOWED_WITHOUT_A_POSITION',
/** This stop order does not close the position */
REJECTION_REASON_STOP_ORDER_NOT_CLOSING_THE_POSITION = 'REJECTION_REASON_STOP_ORDER_NOT_CLOSING_THE_POSITION',
/** Trading is not allowed yet */
REJECTION_REASON_TRADING_NOT_ALLOWED = 'REJECTION_REASON_TRADING_NOT_ALLOWED'
}
@@ -5942,18 +6079,7 @@ export type UpdateProductConfiguration = UpdateFutureProduct | UpdatePerpetualPr
export type UpdateReferralProgram = {
__typename?: 'UpdateReferralProgram';
/** Benefit tiers for the program */
benefitTiers: Array<BenefitTier>;
/** The end time of the program */
endOfProgramTimestamp: Scalars['Timestamp'];
/** ID of the proposal that created the referral program */
id: Scalars['ID'];
/** Determines the level of benefit a party can expect based on their staking */
stakingTiers: Array<StakingTier>;
/** Current version of the referral program */
version: Scalars['Int'];
/** The window legnth to consider for the referral program */
windowLength: Scalars['Int'];
changes: ReferralProgram;
};
/** Update an existing spot market on Vega */
+34 -1
View File
@@ -1,4 +1,9 @@
import type { ConditionOperator, PeggedReference } from './__generated__/types';
import type {
ConditionOperator,
GovernanceTransferKind,
GovernanceTransferType,
PeggedReference,
} from './__generated__/types';
import type { AccountType } from './__generated__/types';
import type {
AuctionTrigger,
@@ -519,6 +524,34 @@ export const DescriptionTransferTypeMapping: TransferTypeMap = {
TRANSFER_TYPE_SUCCESSOR_INSURANCE_FRACTION: 'Successor insurance fraction',
};
/**
* Governance transfers
*/
type GovernanceTransferTypeMap = {
[T in GovernanceTransferType]: string;
};
export const GovernanceTransferTypeMapping: GovernanceTransferTypeMap = {
GOVERNANCE_TRANSFER_TYPE_ALL_OR_NOTHING: 'All or nothing',
GOVERNANCE_TRANSFER_TYPE_BEST_EFFORT: 'Best effort',
GOVERNANCE_TRANSFER_TYPE_UNSPECIFIED: 'Unspecified',
};
export const DescriptionGovernanceTransferTypeMapping: GovernanceTransferTypeMap =
{
GOVERNANCE_TRANSFER_TYPE_ALL_OR_NOTHING:
'Transfers the specified amount or does not transfer anything',
GOVERNANCE_TRANSFER_TYPE_BEST_EFFORT:
'Transfers the specified amount or the max allowable amount if this is less than the specified amount',
GOVERNANCE_TRANSFER_TYPE_UNSPECIFIED: 'Default value, always invalid',
};
type GovernanceTransferKindMap = {
[T in NonNullable<GovernanceTransferKind['__typename']>]: string;
};
export const GovernanceTransferKindMapping: GovernanceTransferKindMap = {
OneOffGovernanceTransfer: 'One off',
RecurringGovernanceTransfer: 'Recurring',
};
type DispatchMetricLabel = {
[T in DispatchMetric]: string;
};
@@ -15,7 +15,7 @@ export function CopyWithTooltip({ children, text }: CopyWithTooltipProps) {
return (
<CopyToClipboard text={text} onCopy={() => setCopied(true)}>
{/* Needs this wrapping div as tooltip component interfers with element used to capture click for copy */}
{/* Needs this wrapping div as tooltip component interferes with element used to capture click for copy */}
<span>
<Tooltip description="Copied" open={copied} align="center">
{children}
+1
View File
@@ -15,3 +15,4 @@ export * from './lib/time';
export * from './lib/validate';
export * from './lib/resolve-network-name';
export * from './lib/is-test-env';
export * from './lib/constants';
+1
View File
@@ -0,0 +1 @@
export const MAXGOINT64 = '9223372036854775807';