Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
91806e51e8 |
@@ -23,13 +23,10 @@ export const Heading = ({
|
||||
})}
|
||||
>
|
||||
<h1
|
||||
className={classNames(
|
||||
'font-alpha calt text-5xl [word-break:break-word]',
|
||||
{
|
||||
'mt-0': !marginTop,
|
||||
'mb-0': !marginBottom,
|
||||
}
|
||||
)}
|
||||
className={classNames('font-alpha calt text-5xl break-words', {
|
||||
'mt-0': !marginTop,
|
||||
'mb-0': !marginBottom,
|
||||
})}
|
||||
>
|
||||
{title}
|
||||
</h1>
|
||||
|
||||
-3
@@ -7,10 +7,8 @@ import type { AssetFieldsFragment } from '@vegaprotocol/assets';
|
||||
|
||||
export const ProposalAssetDetails = ({
|
||||
asset,
|
||||
originalAsset,
|
||||
}: {
|
||||
asset: AssetFieldsFragment;
|
||||
originalAsset?: AssetFieldsFragment;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const [showAssetDetails, setShowAssetDetails] = useState(false);
|
||||
@@ -29,7 +27,6 @@ export const ProposalAssetDetails = ({
|
||||
<div className="mb-10 pb-4">
|
||||
<AssetDetailsTable
|
||||
asset={asset}
|
||||
originalAsset={originalAsset}
|
||||
omitRows={[
|
||||
AssetDetail.STATUS,
|
||||
AssetDetail.INFRASTRUCTURE_FEE_ACCOUNT_BALANCE,
|
||||
|
||||
@@ -65,13 +65,10 @@ export const Proposal = ({
|
||||
? removePaginationWrapper(assetData.assetsConnection?.edges)[0]
|
||||
: undefined;
|
||||
|
||||
const originalAsset = asset;
|
||||
|
||||
if (proposal.terms.change.__typename === 'UpdateAsset' && asset) {
|
||||
asset = {
|
||||
...asset,
|
||||
quantum: proposal.terms.change.quantum,
|
||||
source: { ...asset.source },
|
||||
};
|
||||
|
||||
if (asset.source.__typename === 'ERC20') {
|
||||
@@ -231,7 +228,7 @@ export const Proposal = ({
|
||||
proposal.terms.change.__typename === 'UpdateAsset') &&
|
||||
asset && (
|
||||
<div className="mb-4">
|
||||
<ProposalAssetDetails asset={asset} originalAsset={originalAsset} />
|
||||
<ProposalAssetDetails asset={asset} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { act, render, screen, waitFor, within } from '@testing-library/react';
|
||||
// import userEvent from '@testing-library/user-event';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { Closed } from './closed';
|
||||
import { MarketStateMapping, PropertyKeyType } from '@vegaprotocol/types';
|
||||
@@ -27,7 +26,6 @@ import {
|
||||
marketsDataQuery,
|
||||
createMarketsDataFragment,
|
||||
} from '@vegaprotocol/mock';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
describe('Closed', () => {
|
||||
let originalNow: typeof Date.now;
|
||||
@@ -170,11 +168,14 @@ describe('Closed', () => {
|
||||
Date.now = originalNow;
|
||||
});
|
||||
|
||||
const renderComponent = async (mocks: MockedResponse[]) => {
|
||||
// eslint-disable-next-line jest/no-disabled-tests
|
||||
it.skip('renders correctly formatted and filtered rows', async () => {
|
||||
await act(async () => {
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<MockedProvider mocks={mocks}>
|
||||
<MockedProvider
|
||||
mocks={[marketsMock, marketsDataMock, oracleDataMock]}
|
||||
>
|
||||
<VegaWalletContext.Provider
|
||||
value={{ pubKey } as VegaWalletContextShape}
|
||||
>
|
||||
@@ -184,10 +185,6 @@ describe('Closed', () => {
|
||||
</MemoryRouter>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
it('renders correct headers', async () => {
|
||||
await renderComponent([marketsMock, marketsDataMock, oracleDataMock]);
|
||||
|
||||
const headers = screen.getAllByRole('columnheader');
|
||||
const expectedHeaders = [
|
||||
@@ -203,10 +200,6 @@ describe('Closed', () => {
|
||||
];
|
||||
expect(headers).toHaveLength(expectedHeaders.length);
|
||||
expect(headers.map((h) => h.textContent?.trim())).toEqual(expectedHeaders);
|
||||
});
|
||||
|
||||
it('renders correctly formatted and filtered rows', async () => {
|
||||
await renderComponent([marketsMock, marketsDataMock, oracleDataMock]);
|
||||
|
||||
const assetSymbol = getAsset(market).symbol;
|
||||
|
||||
@@ -280,8 +273,21 @@ describe('Closed', () => {
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
await renderComponent([mixedMarketsMock, marketsDataMock, oracleDataMock]);
|
||||
await act(async () => {
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<MockedProvider
|
||||
mocks={[mixedMarketsMock, marketsDataMock, oracleDataMock]}
|
||||
>
|
||||
<VegaWalletContext.Provider
|
||||
value={{ pubKey } as VegaWalletContextShape}
|
||||
>
|
||||
<Closed />
|
||||
</VegaWalletContext.Provider>
|
||||
</MockedProvider>
|
||||
</MemoryRouter>
|
||||
);
|
||||
});
|
||||
|
||||
// check that the number of rows in datagrid is 2
|
||||
const container = within(
|
||||
@@ -313,67 +319,8 @@ describe('Closed', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('display market actions', async () => {
|
||||
// Use market with a succcessor Id as the actions dropdown will optionally
|
||||
// show a link to the successor market
|
||||
const marketsWithSuccessorAndParent = [
|
||||
{
|
||||
__typename: 'MarketEdge' as const,
|
||||
node: createMarketFragment({
|
||||
id: 'include-0',
|
||||
state: MarketState.STATE_SETTLED,
|
||||
successorMarketID: 'successor',
|
||||
parentMarketID: 'parent',
|
||||
}),
|
||||
},
|
||||
];
|
||||
const mockWithSuccessorAndParent: MockedResponse<MarketsQuery> = {
|
||||
request: {
|
||||
query: MarketsDocument,
|
||||
},
|
||||
result: {
|
||||
data: {
|
||||
marketsConnection: {
|
||||
__typename: 'MarketConnection',
|
||||
edges: marketsWithSuccessorAndParent,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
await renderComponent([
|
||||
mockWithSuccessorAndParent,
|
||||
marketsDataMock,
|
||||
oracleDataMock,
|
||||
]);
|
||||
|
||||
const actionCell = screen
|
||||
.getAllByRole('gridcell')
|
||||
.find((el) => el.getAttribute('col-id') === 'market-actions');
|
||||
|
||||
await userEvent.click(
|
||||
within(actionCell as HTMLElement).getByTestId('dropdown-menu')
|
||||
);
|
||||
|
||||
expect(screen.getByRole('menu')).toBeInTheDocument();
|
||||
|
||||
expect(
|
||||
screen.getByRole('menuitem', { name: 'Copy Market ID' })
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByRole('menuitem', { name: 'View on Explorer' })
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByRole('menuitem', { name: 'View settlement asset details' })
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByRole('menuitem', { name: 'View parent market' })
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByRole('menuitem', { name: 'View successor market' })
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('successor market should be visible', async () => {
|
||||
// eslint-disable-next-line jest/no-disabled-tests
|
||||
it.skip('successor marked should be visible', async () => {
|
||||
const marketsWithSuccessorID = [
|
||||
{
|
||||
__typename: 'MarketEdge' as const,
|
||||
@@ -398,11 +345,21 @@ describe('Closed', () => {
|
||||
},
|
||||
};
|
||||
|
||||
await renderComponent([
|
||||
mockWithSuccessors,
|
||||
marketsDataMock,
|
||||
oracleDataMock,
|
||||
]);
|
||||
await act(async () => {
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<MockedProvider
|
||||
mocks={[mockWithSuccessors, marketsDataMock, oracleDataMock]}
|
||||
>
|
||||
<VegaWalletContext.Provider
|
||||
value={{ pubKey } as VegaWalletContextShape}
|
||||
>
|
||||
<Closed />
|
||||
</VegaWalletContext.Provider>
|
||||
</MockedProvider>
|
||||
</MemoryRouter>
|
||||
);
|
||||
});
|
||||
|
||||
const container = within(
|
||||
document.querySelector('.ag-center-cols-container') as HTMLElement
|
||||
|
||||
@@ -1,145 +0,0 @@
|
||||
import { act, render, screen, within } from '@testing-library/react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { OpenMarkets } from './open-markets';
|
||||
import { Interval } from '@vegaprotocol/types';
|
||||
import type { MockedResponse } from '@apollo/client/testing';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import type {
|
||||
MarketsDataQuery,
|
||||
MarketsQuery,
|
||||
MarketCandlesQuery,
|
||||
MarketFieldsFragment,
|
||||
} from '@vegaprotocol/markets';
|
||||
import {
|
||||
MarketsDataDocument,
|
||||
MarketsDocument,
|
||||
MarketsCandlesDocument,
|
||||
} from '@vegaprotocol/markets';
|
||||
import type { VegaWalletContextShape } from '@vegaprotocol/wallet';
|
||||
import { VegaWalletContext } from '@vegaprotocol/wallet';
|
||||
import {
|
||||
marketsQuery,
|
||||
marketsDataQuery,
|
||||
marketsCandlesQuery,
|
||||
} from '@vegaprotocol/mock';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
describe('Open', () => {
|
||||
let originalNow: typeof Date.now;
|
||||
const mockNowTimestamp = 1672531200000;
|
||||
const pubKey = 'pubKey';
|
||||
|
||||
const marketsQueryData = marketsQuery();
|
||||
const marketsMock: MockedResponse<MarketsQuery> = {
|
||||
request: {
|
||||
query: MarketsDocument,
|
||||
},
|
||||
result: {
|
||||
data: marketsQueryData,
|
||||
},
|
||||
};
|
||||
|
||||
const marketsCandlesQueryData = marketsCandlesQuery();
|
||||
const marketsCandlesMock: MockedResponse<MarketCandlesQuery> = {
|
||||
request: {
|
||||
query: MarketsCandlesDocument,
|
||||
variables: {
|
||||
interval: Interval.INTERVAL_I1H,
|
||||
since: '2022-12-31T00:00:00.000Z',
|
||||
},
|
||||
},
|
||||
result: {
|
||||
data: marketsCandlesQueryData,
|
||||
},
|
||||
};
|
||||
|
||||
const marketsDataQueryData = marketsDataQuery();
|
||||
|
||||
const marketsDataMock: MockedResponse<MarketsDataQuery> = {
|
||||
request: {
|
||||
query: MarketsDataDocument,
|
||||
},
|
||||
result: {
|
||||
data: marketsDataQueryData,
|
||||
},
|
||||
};
|
||||
|
||||
beforeAll(() => {
|
||||
originalNow = Date.now;
|
||||
Date.now = jest.fn().mockReturnValue(mockNowTimestamp);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
Date.now = originalNow;
|
||||
});
|
||||
|
||||
const renderComponent = async () => {
|
||||
await act(async () => {
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<MockedProvider
|
||||
mocks={[marketsMock, marketsCandlesMock, marketsDataMock]}
|
||||
>
|
||||
<VegaWalletContext.Provider
|
||||
value={{ pubKey } as VegaWalletContextShape}
|
||||
>
|
||||
<OpenMarkets />
|
||||
</VegaWalletContext.Provider>
|
||||
</MockedProvider>
|
||||
</MemoryRouter>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
it('renders correct headers', async () => {
|
||||
await renderComponent();
|
||||
|
||||
const headers = screen.getAllByRole('columnheader');
|
||||
const expectedHeaders = [
|
||||
'Market',
|
||||
'Description',
|
||||
'Settlement asset',
|
||||
'Trading mode',
|
||||
'Status',
|
||||
'Mark price',
|
||||
'24h volume',
|
||||
'Open Interest',
|
||||
'Spread',
|
||||
'', // Action row
|
||||
];
|
||||
expect(headers).toHaveLength(expectedHeaders.length);
|
||||
expect(headers.map((h) => h.textContent?.trim())).toEqual(expectedHeaders);
|
||||
});
|
||||
|
||||
it('sort columns', async () => {
|
||||
await renderComponent();
|
||||
|
||||
const headers = screen.getAllByRole('columnheader');
|
||||
const marketHeader = headers.find(
|
||||
(h) => h.getAttribute('col-id') === 'tradableInstrument.instrument.code'
|
||||
);
|
||||
if (!marketHeader) {
|
||||
throw new Error('No market header found');
|
||||
}
|
||||
expect(marketHeader).toHaveAttribute('aria-sort', 'none');
|
||||
await userEvent.click(within(marketHeader).getByText(/market/i));
|
||||
// 6001-MARK-064
|
||||
expect(marketHeader).toHaveAttribute('aria-sort', 'ascending');
|
||||
});
|
||||
|
||||
// eslint-disable-next-line jest/no-disabled-tests, jest/expect-expect
|
||||
it('renders row', async () => {
|
||||
await renderComponent();
|
||||
|
||||
const container = within(
|
||||
document.querySelector('.ag-center-cols-container') as HTMLElement
|
||||
);
|
||||
|
||||
const markets = marketsQueryData.marketsConnection?.edges.map(
|
||||
(e) => e.node
|
||||
) as MarketFieldsFragment[];
|
||||
|
||||
const rows = container.getAllByRole('row');
|
||||
expect(rows).toHaveLength(markets.length);
|
||||
});
|
||||
});
|
||||
@@ -310,25 +310,16 @@ export const CurrentVolume = ({
|
||||
const t = useT();
|
||||
const nextTier = tiers[tierIndex + 1];
|
||||
const requiredForNextTier = nextTier
|
||||
? new BigNumber(nextTier.minimumRunningNotionalTakerVolume).minus(
|
||||
windowLengthVolume
|
||||
)
|
||||
: new BigNumber(0);
|
||||
const currentVolume = new BigNumber(windowLengthVolume);
|
||||
? Number(nextTier.minimumRunningNotionalTakerVolume) - windowLengthVolume
|
||||
: 0;
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-3 pt-4">
|
||||
<CardStat
|
||||
value={
|
||||
currentVolume.isZero()
|
||||
? `<${formatNumberRounded(requiredForNextTier)}`
|
||||
: formatNumberRounded(currentVolume)
|
||||
}
|
||||
text={t('pastEpochs', 'Past {{count}} epochs', {
|
||||
count: windowLength,
|
||||
})}
|
||||
value={formatNumberRounded(new BigNumber(windowLengthVolume))}
|
||||
text={t('pastEpochs', 'Past {{count}} epochs', { count: windowLength })}
|
||||
/>
|
||||
{requiredForNextTier.isGreaterThan(0) && (
|
||||
{requiredForNextTier > 0 && (
|
||||
<CardStat
|
||||
value={formatNumber(requiredForNextTier)}
|
||||
text={t('Required for next tier')}
|
||||
|
||||
@@ -12,7 +12,6 @@ from contextlib import contextmanager
|
||||
from vega_sim.null_service import VegaServiceNull
|
||||
from playwright.sync_api import Browser, Page
|
||||
from config import console_image_name, vega_version
|
||||
from datetime import datetime, timedelta
|
||||
from fixtures.market import (
|
||||
setup_simple_market,
|
||||
setup_opening_auction_market,
|
||||
@@ -79,7 +78,6 @@ def init_vega(request=None):
|
||||
store_transactions=True,
|
||||
transactions_per_block=1000,
|
||||
seconds_per_block=seconds_per_block,
|
||||
genesis_time= datetime.now() - timedelta(days=1),
|
||||
) as vega:
|
||||
try:
|
||||
container = docker_client.containers.run(
|
||||
|
||||
Generated
+1
-1
@@ -1161,7 +1161,7 @@ profile = ["pytest-profiling", "snakeviz"]
|
||||
type = "git"
|
||||
url = "https://github.com/vegaprotocol/vega-market-sim.git"
|
||||
reference = "HEAD"
|
||||
resolved_reference = "fbcb974b2055bbc80169cdfd69987f087f9969fb"
|
||||
resolved_reference = "e93f7dfa8463c59cfd0e299362b845511cebeef6"
|
||||
|
||||
[[package]]
|
||||
name = "websocket-client"
|
||||
|
||||
@@ -9,7 +9,7 @@ packages = [{include = "trading market-sim e2e"}]
|
||||
[tool.poetry.dependencies]
|
||||
python = ">=3.9,<3.11"
|
||||
psutil = "^5.9.5"
|
||||
vega-sim = {git = "https://github.com/vegaprotocol/vega-market-sim.git/", branch = "fix/genesis_panic"}
|
||||
vega-sim = {git = "https://github.com/vegaprotocol/vega-market-sim.git"}
|
||||
pytest-playwright = "^0.4.2"
|
||||
docker = "^6.1.3"
|
||||
pytest-xdist = "^3.3.1"
|
||||
|
||||
@@ -58,6 +58,7 @@ class TestSettledMarket:
|
||||
def test_settled_rows(self, page: Page, create_settled_market):
|
||||
page.goto(f"/#/markets/all")
|
||||
page.get_by_test_id("Closed markets").click()
|
||||
|
||||
row_selector = page.locator(
|
||||
'[data-testid="tab-closed-markets"] .ag-center-cols-container .ag-row'
|
||||
).first
|
||||
@@ -71,7 +72,7 @@ class TestSettledMarket:
|
||||
# 6001-MARK-009
|
||||
# 6001-MARK-008
|
||||
# 6001-MARK-010
|
||||
pattern = r"(\d+)\s+(months|hours|days)\s+ago"
|
||||
pattern = r"(\d+)\s+months\s+ago"
|
||||
date_text = row_selector.locator('[col-id="settlementDate"]').inner_text()
|
||||
assert re.match(pattern, date_text), f"Expected text to match pattern but got {date_text}"
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ import pytest
|
||||
from playwright.sync_api import Page, expect
|
||||
from vega_sim.service import VegaService
|
||||
from actions.vega import submit_order
|
||||
from actions.utils import change_keys
|
||||
from wallet_config import MM_WALLET, MM_WALLET2
|
||||
import logging
|
||||
|
||||
@@ -197,17 +196,3 @@ def test_price_monitoring(simple_market, vega: VegaService, page: Page):
|
||||
expect(
|
||||
page.get_by_test_id(liquidity_supplied).get_by_test_id(item_value)
|
||||
).to_have_text("50.00 (>100%)")
|
||||
|
||||
COL_ID_FEE = ".ag-center-cols-container [col-id='fee'] .ag-cell-value"
|
||||
|
||||
@pytest.mark.usefixtures("vega", "page", "continuous_market", "risk_accepted", "auth")
|
||||
def test_auction_uncross_fees(continuous_market, vega: VegaService, page: Page):
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
page.get_by_test_id("Fills").click()
|
||||
expect(page.locator(COL_ID_FEE)).to_have_text("0.00 tDAI")
|
||||
page.locator(COL_ID_FEE).hover()
|
||||
expect(page.get_by_test_id("fee-breakdown-tooltip")).to_have_text("If the market was suspendedIf the market is in monitoring auction, half of the infrastructure and liquidity fees will be paid.Infrastructure fee0.00 tDAILiquidity fee0.00 tDAIMaker fee0.00 tDAITotal fees0.00 tDAI")
|
||||
change_keys(page,vega, "market_maker")
|
||||
expect(page.locator(COL_ID_FEE)).to_have_text("0.00 tDAI")
|
||||
page.locator(COL_ID_FEE).hover()
|
||||
expect(page.get_by_test_id("fee-breakdown-tooltip")).to_have_text("If the market was suspendedIf the market is in monitoring auction, half of the infrastructure and liquidity fees will be paid.Infrastructure fee0.00 tDAILiquidity fee0.00 tDAIMaker fee0.00 tDAITotal fees0.00 tDAI")
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
import pytest
|
||||
from playwright.sync_api import Page, expect
|
||||
from fixtures.market import setup_continuous_market
|
||||
|
||||
from conftest import init_vega
|
||||
|
||||
market_names = ["ETHBTC.QM21", "BTCUSD.MF21", "SOLUSD", "AAPL.MF21"]
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def vega():
|
||||
with init_vega() as vega:
|
||||
yield vega
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def create_markets(vega):
|
||||
for market_name in market_names:
|
||||
setup_continuous_market(vega, custom_market_name=market_name)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("risk_accepted")
|
||||
def test_table_headers(page: Page, create_markets):
|
||||
page.goto(f"/#/markets/all")
|
||||
headers = [
|
||||
"Market",
|
||||
"Description",
|
||||
"Settlement asset",
|
||||
"Trading mode",
|
||||
"Status",
|
||||
"Mark price",
|
||||
"24h volume",
|
||||
"Open Interest",
|
||||
"Spread",
|
||||
"",
|
||||
]
|
||||
page.wait_for_selector('[data-testid="tab-open-markets"]', state="visible")
|
||||
page_headers = (
|
||||
page.get_by_test_id("tab-open-markets").locator(".ag-header-cell-text").all()
|
||||
)
|
||||
for i, header in enumerate(headers):
|
||||
expect(page_headers[i]).to_have_text(header)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("risk_accepted")
|
||||
def test_markets_tab(page: Page, create_markets):
|
||||
page.goto(f"/#/markets/all")
|
||||
expect(page.get_by_test_id("Open markets")).to_have_attribute(
|
||||
"data-state", "active"
|
||||
)
|
||||
expect(page.get_by_test_id("Proposed markets")).to_have_attribute(
|
||||
"data-state", "inactive"
|
||||
)
|
||||
expect(page.get_by_test_id("Closed markets")).to_have_attribute(
|
||||
"data-state", "inactive"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("risk_accepted")
|
||||
def test_markets_content(page: Page, create_markets):
|
||||
page.goto(f"/#/markets/all")
|
||||
row_selector = page.locator(
|
||||
'[data-testid="tab-open-markets"] .ag-center-cols-container .ag-row'
|
||||
).first
|
||||
instrument_code_locator = '[col-id="tradableInstrument.instrument.code"] [data-testid="stack-cell-primary"]'
|
||||
# 6001-MARK-035
|
||||
expect(row_selector.locator(instrument_code_locator)).to_have_text("ETHBTC.QM21")
|
||||
|
||||
# 6001-MARK-073
|
||||
expect(row_selector.locator('[title="Future"]')).to_have_text("Futr")
|
||||
|
||||
# 6001-MARK-036
|
||||
expect(
|
||||
row_selector.locator('[col-id="tradableInstrument.instrument.name"]')
|
||||
).to_have_text("ETHBTC.QM21")
|
||||
|
||||
# 6001-MARK-037
|
||||
expect(row_selector.locator('[col-id="tradingMode"]')).to_have_text("Continuous")
|
||||
|
||||
# 6001-MARK-038
|
||||
expect(row_selector.locator('[col-id="state"]')).to_have_text("Active")
|
||||
|
||||
# 6001-MARK-039
|
||||
expect(row_selector.locator('[col-id="data.markPrice"]')).to_have_text("107.50")
|
||||
|
||||
# 6001-MARK-040
|
||||
expect(row_selector.locator('[col-id="data.candles"]')).to_have_text("0.00")
|
||||
|
||||
# 6001-MARK-042
|
||||
expect(
|
||||
row_selector.locator(
|
||||
'[col-id="tradableInstrument.instrument.product.settlementAsset.symbol"]'
|
||||
)
|
||||
).to_have_text("tDAI")
|
||||
|
||||
expect(row_selector.locator('[col-id="data.bestBidPrice"]')).to_have_text("2")
|
||||
|
||||
# 6001-MARK-043
|
||||
row_selector.locator(
|
||||
'[col-id="tradableInstrument.instrument.product.settlementAsset.symbol"] button'
|
||||
).click()
|
||||
expect(page.get_by_test_id("dialog-title")).to_have_text("Asset details - tDAI")
|
||||
# 6001-MARK-019
|
||||
page.get_by_test_id("close-asset-details-dialog").click()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("risk_accepted")
|
||||
def test_market_actions(page: Page, create_markets):
|
||||
# 6001-MARK-044
|
||||
# 6001-MARK-045
|
||||
# 6001-MARK-046
|
||||
# 6001-MARK-047
|
||||
page.goto(f"/#/markets/all")
|
||||
page.locator(
|
||||
'.ag-pinned-right-cols-container [col-id="market-actions"]'
|
||||
).first.locator("button").click()
|
||||
|
||||
actions = [
|
||||
"Copy Market ID",
|
||||
"View on Explorer",
|
||||
"View settlement asset details",
|
||||
]
|
||||
action_elements = (
|
||||
page.get_by_test_id("market-actions-content").get_by_role("menuitem").all()
|
||||
)
|
||||
|
||||
for i, action in enumerate(actions):
|
||||
expect(action_elements[i]).to_have_text(action)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("risk_accepted")
|
||||
def test_sort_markets(page: Page, create_markets):
|
||||
# 6001-MARK-064
|
||||
|
||||
page.goto(f"/#/markets/all")
|
||||
sorted_market_names = [
|
||||
"AAPL.MF21",
|
||||
"BTCUSD.MF21",
|
||||
"ETHBTC.QM21",
|
||||
"SOLUSD",
|
||||
]
|
||||
page.locator('.ag-header-row [col-id="tradableInstrument.instrument.code"]').click()
|
||||
for i, market_name in enumerate(sorted_market_names):
|
||||
expect(
|
||||
page.locator(
|
||||
f'[row-index="{i}"] [col-id="tradableInstrument.instrument.name"]'
|
||||
)
|
||||
).to_have_text(market_name)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("risk_accepted")
|
||||
def test_drag_and_drop_column(page: Page, create_markets):
|
||||
# 6001-MARK-065
|
||||
page.goto(f"/#/markets/all")
|
||||
col_instrument_code = '.ag-header-row [col-id="tradableInstrument.instrument.code"]'
|
||||
|
||||
page.locator(col_instrument_code).drag_to(
|
||||
page.locator('.ag-header-row [col-id="data.bestBidPrice"]')
|
||||
)
|
||||
expect(page.locator(col_instrument_code)).to_have_attribute("aria-colindex", "9")
|
||||
@@ -5,7 +5,6 @@ from playwright.sync_api import Page, expect
|
||||
from vega_sim.service import VegaService, PeggedOrder
|
||||
import vega_sim.api.governance as governance
|
||||
from actions.vega import submit_order
|
||||
from actions.utils import next_epoch
|
||||
from wallet_config import MM_WALLET, MM_WALLET2, GOVERNANCE_WALLET
|
||||
|
||||
|
||||
@@ -59,9 +58,9 @@ def test_market_lifecycle(proposed_market, vega: VegaService, page: Page):
|
||||
|
||||
# "wait" for market to be approved and enacted
|
||||
vega.forward("60s")
|
||||
vega.wait_fn(10)
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
next_epoch(vega=vega)
|
||||
|
||||
# check that market is in pending state
|
||||
expect(trading_mode).to_have_text("Opening auction")
|
||||
expect(market_state).to_have_text("Pending")
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
import pytest
|
||||
import re
|
||||
from playwright.sync_api import Page, expect
|
||||
from vega_sim.service import VegaService
|
||||
from vega_sim.service import MarketStateUpdateType
|
||||
from datetime import datetime, timedelta
|
||||
from conftest import init_vega
|
||||
from actions.utils import change_keys
|
||||
from actions.vega import submit_multiple_orders
|
||||
from fixtures.market import setup_perps_market
|
||||
from wallet_config import MM_WALLET, MM_WALLET2, TERMINATE_WALLET
|
||||
|
||||
row_selector = '[data-testid="tab-funding-payments"] .ag-center-cols-container .ag-row'
|
||||
col_amount = '[col-id="amount"]'
|
||||
|
||||
class TestPerpetuals:
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def vega(self, request):
|
||||
with init_vega(request) as vega:
|
||||
yield vega
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def perps_market(self, vega: VegaService):
|
||||
perps_market = setup_perps_market(vega)
|
||||
submit_multiple_orders(
|
||||
vega, MM_WALLET.name, perps_market, "SIDE_SELL", [[1, 110], [1, 105]]
|
||||
)
|
||||
submit_multiple_orders(
|
||||
vega, MM_WALLET2.name, perps_market, "SIDE_BUY", [[1, 90], [1, 95]]
|
||||
)
|
||||
vega.submit_settlement_data(
|
||||
settlement_key=TERMINATE_WALLET.name,
|
||||
settlement_price=110,
|
||||
market_id=perps_market,
|
||||
)
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
submit_multiple_orders(
|
||||
vega, MM_WALLET.name, perps_market, "SIDE_SELL", [[1, 110], [1, 105]]
|
||||
)
|
||||
submit_multiple_orders(
|
||||
vega, MM_WALLET2.name, perps_market, "SIDE_BUY", [[1, 112], [1, 115]]
|
||||
)
|
||||
vega.submit_settlement_data(
|
||||
settlement_key=TERMINATE_WALLET.name,
|
||||
settlement_price=110,
|
||||
market_id=perps_market,
|
||||
)
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
return perps_market
|
||||
|
||||
@pytest.mark.usefixtures("page","risk_accepted", "auth")
|
||||
def test_funding_payment_profit(self, perps_market, page: Page):
|
||||
page.goto(f"/#/markets/{perps_market}")
|
||||
page.get_by_test_id("Funding payments").click()
|
||||
row = page.locator(row_selector)
|
||||
expect(row.locator(col_amount)).to_have_text("9.00 tDAI")
|
||||
|
||||
@pytest.mark.usefixtures("page","risk_accepted", "auth")
|
||||
def test_funding_payment_loss(self, perps_market, page: Page, vega):
|
||||
page.goto(f"/#/markets/{perps_market}")
|
||||
change_keys(page, vega, "market_maker")
|
||||
page.get_by_test_id("Funding payments").click()
|
||||
row = page.locator(row_selector)
|
||||
expect(row.locator(col_amount)).to_have_text("-27.00 tDAI")
|
||||
|
||||
@pytest.mark.usefixtures("page","risk_accepted", "auth")
|
||||
def test_funding_header(self, perps_market, page: Page):
|
||||
page.goto(f"/#/markets/{perps_market}")
|
||||
expect(page.get_by_test_id("market-funding")).to_contain_text("Funding Rate / Countdown-8.1818%")
|
||||
expect(page.get_by_test_id("index-price")).to_have_text("Index Price110.00")
|
||||
|
||||
@pytest.mark.skip("Skipped due to issue #5421")
|
||||
@pytest.mark.usefixtures("page","risk_accepted", "auth")
|
||||
def test_funding_payment_history(perps_market, page: Page, vega):
|
||||
page.goto(f"/#/markets/{perps_market}")
|
||||
change_keys(page, vega, "market_maker")
|
||||
page.get_by_test_id("Funding history").click()
|
||||
element = page.get_by_test_id("tab-funding-history")
|
||||
# Get the bounding box of the element
|
||||
bounding_box = element.bounding_box()
|
||||
if bounding_box:
|
||||
bottom_right_x = bounding_box["x"] + bounding_box["width"]
|
||||
bottom_right_y = bounding_box["y"] + bounding_box["height"]
|
||||
|
||||
# Hover over the bottom-right corner of the element
|
||||
element.hover(position={"x": bottom_right_x, "y": bottom_right_y})
|
||||
else:
|
||||
print("Bounding box not found for the element")
|
||||
|
||||
@pytest.mark.usefixtures("page","risk_accepted", "auth")
|
||||
def test_perps_market_termination_proposed(page: Page, vega: VegaService):
|
||||
perpetual_market = setup_perps_market(vega)
|
||||
page.goto(f"/#/markets/{perpetual_market}")
|
||||
vega.update_market_state(
|
||||
proposal_key=MM_WALLET.name,
|
||||
market_id=perpetual_market,
|
||||
market_state=MarketStateUpdateType.Terminate,
|
||||
price=100,
|
||||
vote_closing_time = datetime.now() + timedelta(seconds=15),
|
||||
vote_enactment_time = datetime.now() + timedelta(seconds=60),
|
||||
approve_proposal = True,
|
||||
forward_time_to_enactment = False,
|
||||
)
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
banner_text = page.get_by_test_id(f"termination-warning-banner-{perpetual_market}").text_content()
|
||||
pattern = re.compile(
|
||||
r"Trading on Market BTC:DAI_Perpetual may stop on \d{2} [A-Za-z]+\. There is open proposal to close this market\.Proposed final price is 100\.00 BTC\.View proposal"
|
||||
)
|
||||
assert pattern.search(banner_text), f"Text did not match pattern. Text was: {banner_text}"
|
||||
|
||||
@pytest.mark.usefixtures("page","risk_accepted", "auth" )
|
||||
def test_perps_market_terminated(page: Page, vega: VegaService):
|
||||
perpetual_market = setup_perps_market(vega)
|
||||
vega.update_market_state(
|
||||
proposal_key=MM_WALLET.name,
|
||||
market_id=perpetual_market,
|
||||
market_state=MarketStateUpdateType.Terminate,
|
||||
price=100,
|
||||
approve_proposal = True,
|
||||
forward_time_to_enactment = True,
|
||||
)
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
|
||||
page.goto(f"/#/markets/{perpetual_market}")
|
||||
expect(page.get_by_test_id("market-price")).to_have_text("Mark Price100.00")
|
||||
expect(page.get_by_test_id("market-change")).to_have_text("Change (24h)-")
|
||||
expect(page.get_by_test_id("market-volume")).to_have_text("Volume (24h)-")
|
||||
expect(page.get_by_test_id("market-trading-mode")).to_have_text("Trading modeNo trading")
|
||||
expect(page.get_by_test_id("market-state")).to_have_text("StatusClosed")
|
||||
expect(page.get_by_test_id("liquidity-supplied")).to_have_text("Liquidity supplied 0.00 (0.00%)")
|
||||
expect(page.get_by_test_id("market-funding")).to_have_text("Funding Rate / Countdown-Unknown")
|
||||
expect(page.get_by_test_id("index-price")).to_have_text("Index Price-")
|
||||
expect(page.get_by_test_id("deal-ticket-error-message-summary")).to_have_text("This market is closed and not accepting orders")
|
||||
@@ -18,7 +18,7 @@ type Rows = {
|
||||
key: AssetDetail;
|
||||
label: string;
|
||||
tooltip: string;
|
||||
value: (asset: Asset, orignalAsset?: Asset) => ReactNode | undefined;
|
||||
value: (asset: Asset) => ReactNode | undefined;
|
||||
valueTooltip?: (asset: Asset) => string | null | undefined;
|
||||
}[];
|
||||
|
||||
@@ -52,21 +52,6 @@ const num = (asset: Asset, n: string | undefined | null) => {
|
||||
return addDecimalsFormatNumber(n, asset.decimals);
|
||||
};
|
||||
|
||||
const Diff = ({
|
||||
oldValue,
|
||||
newValue,
|
||||
}: {
|
||||
oldValue: ReactNode;
|
||||
newValue: ReactNode;
|
||||
}) => (
|
||||
<span className="flex gap-1">
|
||||
<span className="line-through bg-vega-red-300 dark:bg-vega-red-600">
|
||||
{oldValue}
|
||||
</span>
|
||||
<span className="bg-vega-green-300 dark:bg-vega-green-600">{newValue}</span>
|
||||
</span>
|
||||
);
|
||||
|
||||
export const useRows = () => {
|
||||
const t = useT();
|
||||
const AssetTypeMapping = useAssetTypeMapping();
|
||||
@@ -118,14 +103,7 @@ export const useRows = () => {
|
||||
key: AssetDetail.QUANTUM,
|
||||
label: t('Quantum'),
|
||||
tooltip: t('The minimum economically meaningful amount of the asset'),
|
||||
value: (asset, originalAsset) => {
|
||||
const value = num(asset, asset.quantum);
|
||||
if (originalAsset && originalAsset.quantum !== asset.quantum) {
|
||||
const original = num(originalAsset, originalAsset.quantum);
|
||||
return <Diff oldValue={original} newValue={value} />;
|
||||
}
|
||||
return value;
|
||||
},
|
||||
value: (asset) => num(asset, asset.quantum),
|
||||
},
|
||||
{
|
||||
key: AssetDetail.STATUS,
|
||||
@@ -165,24 +143,8 @@ export const useRows = () => {
|
||||
tooltip: t('WITHDRAW_THRESHOLD_TOOLTIP_TEXT', {
|
||||
defaultValue: WITHDRAW_THRESHOLD_TOOLTIP_TEXT,
|
||||
}),
|
||||
value: (asset, originalAsset) => {
|
||||
const value = num(
|
||||
asset,
|
||||
(asset.source as Schema.ERC20).withdrawThreshold
|
||||
);
|
||||
if (
|
||||
originalAsset &&
|
||||
(originalAsset.source as Schema.ERC20).withdrawThreshold !==
|
||||
(asset.source as Schema.ERC20).withdrawThreshold
|
||||
) {
|
||||
const original = num(
|
||||
asset,
|
||||
(originalAsset.source as Schema.ERC20).withdrawThreshold
|
||||
);
|
||||
return <Diff oldValue={original} newValue={value} />;
|
||||
}
|
||||
return value;
|
||||
},
|
||||
value: (asset) =>
|
||||
num(asset, (asset.source as Schema.ERC20).withdrawThreshold),
|
||||
},
|
||||
{
|
||||
key: AssetDetail.LIFETIME_LIMIT,
|
||||
@@ -190,26 +152,8 @@ export const useRows = () => {
|
||||
tooltip: t(
|
||||
'The lifetime deposit limit per address. Note: this is a temporary measure that can be changed or removed through governance'
|
||||
),
|
||||
value: (asset, originalAsset) => {
|
||||
const value = num(
|
||||
asset,
|
||||
(asset.source as Schema.ERC20).lifetimeLimit
|
||||
);
|
||||
|
||||
if (
|
||||
originalAsset &&
|
||||
(originalAsset.source as Schema.ERC20).lifetimeLimit !==
|
||||
(asset.source as Schema.ERC20).lifetimeLimit
|
||||
) {
|
||||
const original = num(
|
||||
asset,
|
||||
(originalAsset.source as Schema.ERC20).lifetimeLimit
|
||||
);
|
||||
return <Diff oldValue={original} newValue={value} />;
|
||||
}
|
||||
|
||||
return value;
|
||||
},
|
||||
value: (asset) =>
|
||||
num(asset, (asset.source as Schema.ERC20).lifetimeLimit),
|
||||
},
|
||||
{
|
||||
key: AssetDetail.MAX_FAUCET_AMOUNT_MINT,
|
||||
@@ -317,13 +261,10 @@ export const testId = (detail: AssetDetail, field: 'label' | 'value') =>
|
||||
|
||||
export type AssetDetailsTableProps = {
|
||||
asset: Asset;
|
||||
originalAsset?: Asset;
|
||||
|
||||
omitRows?: AssetDetail[];
|
||||
} & Omit<KeyValueTableRowProps, 'children'>;
|
||||
export const AssetDetailsTable = ({
|
||||
asset,
|
||||
originalAsset,
|
||||
omitRows = [],
|
||||
...props
|
||||
}: AssetDetailsTableProps) => {
|
||||
@@ -334,7 +275,7 @@ export const AssetDetailsTable = ({
|
||||
|
||||
const details = useRows().map((r) => ({
|
||||
...r,
|
||||
value: r.value(asset, originalAsset),
|
||||
value: r.value(asset),
|
||||
valueTooltip: r.valueTooltip?.(asset),
|
||||
}));
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"Adjusted stake share": "Adjusted stake share",
|
||||
"Adjusted stake": "Adjusted stake",
|
||||
"Commitment ({{symbol}})": "Commitment ({{symbol}})",
|
||||
"Commitment details": "Commitment details",
|
||||
"Created": "Created",
|
||||
@@ -8,13 +8,13 @@
|
||||
"Fees accrued this epoch": "Fees accrued this epoch",
|
||||
"Last bond penalty": "Last bond penalty",
|
||||
"Last epoch bond penalty.": "Last epoch bond penalty.",
|
||||
"Last epoch fee penalty.": "Last epoch fee penalty.",
|
||||
"Last epoch fraction of time on the book.": "Last epoch fraction of time on the book.",
|
||||
"Fee penalty applied at the end of the last epoch.": "Fee penalty applied at the end of the last epoch.",
|
||||
"Fraction of time on book at the end of the last epoch.": "Fraction of time on book at the end of the last epoch.",
|
||||
"Last epoch SLA details": "Last epoch SLA details",
|
||||
"Last fee penalty": "Last fee penalty",
|
||||
"Last time on the book": "Last time on the book",
|
||||
"Last time on book": "Last time on book",
|
||||
"Live liquidity data": "Live liquidity data",
|
||||
"Live liquidity quality score (%)": "Live liquidity quality score (%)",
|
||||
"Live liquidity score (%)": "Live liquidity score (%)",
|
||||
"Live supplied liquidity": "Live supplied liquidity",
|
||||
"Live time on book": "Live time on book",
|
||||
"No liquidity provisions": "No liquidity provisions",
|
||||
@@ -24,7 +24,7 @@
|
||||
"Status": "Status",
|
||||
"The amount committed to the market by this liquidity provider.": "The amount committed to the market by this liquidity provider.",
|
||||
"The amount of liquidity volume supplied by the LP order in order to meet the obligation. If the obligation is already met in full by other limit orders from the same Vega key the LP order is not required and this value will be zero. Also note if the target stake for the market is less than the obligation the full value of the obligation may not be required.": "The amount of liquidity volume supplied by the LP order in order to meet the obligation. If the obligation is already met in full by other limit orders from the same Vega key the LP order is not required and this value will be zero. Also note if the target stake for the market is less than the obligation the full value of the obligation may not be required.",
|
||||
"The average score of the liquidity provider.": "The average score of the liquidity provider.",
|
||||
"The liquidity score of the provider used to determine reallocation of fees to better performing LPs. Posting volume closer to the mid on both sides of the book will improve this score.": "The liquidity score of the provider used to determine reallocation of fees to better performing LPs. Posting volume closer to the mid on both sides of the book will improve this score.",
|
||||
"The current status of this liquidity provision.": "The current status of this liquidity provision.",
|
||||
"The date and time this liquidity provision was created.": "The date and time this liquidity provision was created.",
|
||||
"The date and time this liquidity provision was last updated.": "The date and time this liquidity provision was last updated.",
|
||||
|
||||
@@ -119,8 +119,6 @@ describe('getLiquidityProvision', () => {
|
||||
createdAt: '2022-12-16T09:28:29.071781Z',
|
||||
id: 'dde288688af2aeb5feb349dd72d3679a7a9be34c7375f6a4a48ef2f6140e7e59',
|
||||
fee: '0.001',
|
||||
partyId:
|
||||
'dde288688af2aeb5feb349dd72d3679a7a9be34c7375f6a4a48ef2f6140e7e59',
|
||||
party: {
|
||||
__typename: 'Party',
|
||||
accountsConnection: {
|
||||
|
||||
@@ -159,14 +159,7 @@ export const getLiquidityProvision = (
|
||||
const liquidityProvider = liquidityProviders.find(
|
||||
(f) => liquidityProvision.party.id === f.partyId
|
||||
);
|
||||
|
||||
if (!liquidityProvider) {
|
||||
return {
|
||||
...liquidityProvision,
|
||||
partyId: liquidityProvision.party.id,
|
||||
};
|
||||
}
|
||||
|
||||
if (!liquidityProvider) return liquidityProvision;
|
||||
const accounts = compact(
|
||||
liquidityProvision.party.accountsConnection?.edges
|
||||
).map((e) => e.node);
|
||||
|
||||
@@ -93,13 +93,13 @@ describe('LiquidityTable', () => {
|
||||
'Commitment ()',
|
||||
'Obligation',
|
||||
'Fee',
|
||||
'Adjusted stake share',
|
||||
'Adjusted stake',
|
||||
'Share',
|
||||
'Live supplied liquidity',
|
||||
'Fees accrued this epoch',
|
||||
'Live time on book',
|
||||
'Live liquidity quality score (%)',
|
||||
'Last time on the book',
|
||||
'Live liquidity score (%)',
|
||||
'Last time on book',
|
||||
'Last fee penalty',
|
||||
'Last bond penalty',
|
||||
'Created',
|
||||
|
||||
@@ -357,11 +357,12 @@ export const LiquidityTable = ({
|
||||
},
|
||||
},
|
||||
{
|
||||
headerName: t('Adjusted stake share'),
|
||||
headerName: t('Adjusted stake'),
|
||||
field: 'feeShare.virtualStake',
|
||||
type: 'rightAligned',
|
||||
headerTooltip: t('The virtual stake of the liquidity provider.'),
|
||||
|
||||
headerTooltip: t(
|
||||
'The effective stake of the liquidity provider, adjusted for length of commitment and impact on equity like share.'
|
||||
),
|
||||
valueFormatter: assetDecimalsQuantumFormatter,
|
||||
tooltipValueGetter: assetDecimalsFormatter,
|
||||
},
|
||||
@@ -427,10 +428,12 @@ export const LiquidityTable = ({
|
||||
valueFormatter: percentageFormatter,
|
||||
},
|
||||
{
|
||||
headerName: t('Live liquidity quality score (%)'),
|
||||
headerName: t('Live liquidity score (%)'),
|
||||
field: 'feeShare.averageScore',
|
||||
type: 'rightAligned',
|
||||
headerTooltip: t('The average score of the liquidity provider.'),
|
||||
headerTooltip: t(
|
||||
'The liquidity score of the provider used to determine reallocation of fees to better performing LPs. Posting volume closer to the mid on both sides of the book will improve this score.'
|
||||
),
|
||||
valueFormatter: percentageFormatter,
|
||||
},
|
||||
],
|
||||
@@ -440,17 +443,21 @@ export const LiquidityTable = ({
|
||||
marryChildren: true,
|
||||
children: [
|
||||
{
|
||||
headerName: t(`Last time on the book`),
|
||||
headerName: t(`Last time on book`),
|
||||
field: 'sla.lastEpochFractionOfTimeOnBook',
|
||||
type: 'rightAligned',
|
||||
headerTooltip: t('Last epoch fraction of time on the book.'),
|
||||
headerTooltip: t(
|
||||
'Fraction of time on book at the end of the last epoch.'
|
||||
),
|
||||
valueFormatter: percentageFormatter,
|
||||
},
|
||||
{
|
||||
headerName: t(`Last fee penalty`),
|
||||
field: 'sla.lastEpochFeePenalty',
|
||||
type: 'rightAligned',
|
||||
headerTooltip: t('Last epoch fee penalty.'),
|
||||
headerTooltip: t(
|
||||
'Fee penalty applied at the end of the last epoch.'
|
||||
),
|
||||
valueFormatter: percentageFormatter,
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user