Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5287744729 | ||
|
|
110fddde21 | ||
|
|
f08db503d5 | ||
|
|
e0e0a6e6bd | ||
|
|
af9d2c3437 | ||
|
|
13caceec4a |
@@ -4,7 +4,7 @@ The front-end monorepo provides a toolkit for building apps that interact with V
|
||||
|
||||
This repository is managed using [Nx](https://nx.dev).
|
||||
|
||||
## 🔎 Applications in this repo
|
||||
# 🔎 Applications in this repo
|
||||
|
||||
### [Block explorer](./apps/explorer)
|
||||
|
||||
@@ -30,7 +30,7 @@ Hosting for static content being shared across apps, for example fonts.
|
||||
|
||||
The utility dApp for validators wishing to add or remove themselves as a signer of the multisig contract.
|
||||
|
||||
## 🧱 Libraries in this repo
|
||||
# 🧱 Libraries in this repo
|
||||
|
||||
### [UI toolkit](./libs/ui-toolkit)
|
||||
|
||||
@@ -53,7 +53,7 @@ A utility library for connecting to the Ethereum network and interacting with Ve
|
||||
|
||||
Generic react helpers that can be used across multiple applications, along with other utilities.
|
||||
|
||||
## 💻 Develop
|
||||
# 💻 Develop
|
||||
|
||||
### Set up
|
||||
|
||||
@@ -103,7 +103,7 @@ In CI linting, formatting and also run. These checks can be seen in the [CI work
|
||||
|
||||
Visit the [Nx Documentation](https://nx.dev/getting-started/intro) to learn more.
|
||||
|
||||
## 🐋 Hosting a console
|
||||
# 🐋 Hosting a console
|
||||
|
||||
To host a console there are two possible build scenarios for running the frontends: nx performed **outside** or **inside** docker build. For specific build instructions follow [build instructions](#build-instructions).
|
||||
|
||||
@@ -226,6 +226,6 @@ Note: The script is only needed if capsule was built for first time or fresh. To
|
||||
vega wallet service run -n DV --load-tokens --tokens-passphrase-file passphrase --no-version-check --automatic-consent --home ~/.vegacapsule/testnet/wallet
|
||||
```
|
||||
|
||||
## 📑 License
|
||||
# 📑 License
|
||||
|
||||
[MIT](./LICENSE)
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
import type { ApolloError } from '@apollo/client';
|
||||
import {
|
||||
PARTY_NOT_FOUND,
|
||||
filterAcceptableGraphqlErrors,
|
||||
isPartyNotFoundError,
|
||||
} from './party';
|
||||
import type { GraphQLError } from 'graphql';
|
||||
|
||||
/**
|
||||
*
|
||||
* @param message
|
||||
* @returns GraphQLError
|
||||
*/
|
||||
function createMockApolloErrors(message: string): GraphQLError {
|
||||
return {
|
||||
message,
|
||||
extensions: {
|
||||
code: message.toUpperCase().replace(/ /g, '_'),
|
||||
},
|
||||
locations: [],
|
||||
originalError: new Error(message),
|
||||
path: [],
|
||||
nodes: [],
|
||||
positions: [1],
|
||||
name: message,
|
||||
source: {
|
||||
body: message,
|
||||
name: message,
|
||||
locationOffset: {
|
||||
line: 1,
|
||||
column: 1,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
describe('filterAcceptableGraphqlErrors', () => {
|
||||
it('should return undefined if the error is a party not found error', () => {
|
||||
const error: Partial<ApolloError> = {
|
||||
graphQLErrors: [createMockApolloErrors('failed to get party for ID')],
|
||||
};
|
||||
|
||||
const result = filterAcceptableGraphqlErrors(error as ApolloError);
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should return the error if it is not a party not found error', () => {
|
||||
const error: Partial<ApolloError> = {
|
||||
graphQLErrors: [createMockApolloErrors('Some other error')],
|
||||
};
|
||||
|
||||
const result = filterAcceptableGraphqlErrors(error as ApolloError);
|
||||
|
||||
expect(result).toEqual(error);
|
||||
});
|
||||
|
||||
it('should return the error if there are multiple errors', () => {
|
||||
const error: Partial<ApolloError> = {
|
||||
graphQLErrors: [
|
||||
createMockApolloErrors('failed to get party for ID'),
|
||||
createMockApolloErrors('Some other error'),
|
||||
],
|
||||
};
|
||||
|
||||
const result = filterAcceptableGraphqlErrors(error as ApolloError);
|
||||
|
||||
expect(result).toEqual(error);
|
||||
});
|
||||
|
||||
it('should return the error if there are no errors', () => {
|
||||
const error: Partial<ApolloError> = {
|
||||
graphQLErrors: [],
|
||||
};
|
||||
|
||||
const result = filterAcceptableGraphqlErrors(error as ApolloError);
|
||||
|
||||
expect(result).toEqual(error);
|
||||
});
|
||||
|
||||
it('should return undefined if the error is undefined', () => {
|
||||
const result = filterAcceptableGraphqlErrors(undefined);
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('isPartyNotFoundError', () => {
|
||||
it('should return true if the error message includes PARTY_NOT_FOUND', () => {
|
||||
const error = { message: 'failed to get party for ID' };
|
||||
|
||||
const result = isPartyNotFoundError(error);
|
||||
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false if the error message does not include PARTY_NOT_FOUND', () => {
|
||||
const error = { message: 'Some other error' };
|
||||
|
||||
const result = isPartyNotFoundError(error);
|
||||
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
// Will trip if the error message changes, which should not be a problem, but there
|
||||
// might be logic that depends on it
|
||||
it('expects party not found error to remain consistent', () => {
|
||||
const error = 'failed to get party for ID';
|
||||
|
||||
expect(PARTY_NOT_FOUND).toStrictEqual(error);
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,3 @@
|
||||
import type { ApolloError } from '@apollo/client';
|
||||
|
||||
export const PARTY_NOT_FOUND = 'failed to get party for ID';
|
||||
|
||||
export const isPartyNotFoundError = (error: { message: string }) => {
|
||||
@@ -8,23 +6,3 @@ export const isPartyNotFoundError = (error: { message: string }) => {
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* If a party has no accounts or data, then this GraphQL query believes it does not exist
|
||||
* Not having any rewards is a valid state, so in some cases we can filter this error out.
|
||||
*
|
||||
* @param error ApolloError | undefined
|
||||
* @returns ApolloError | undefined
|
||||
*/
|
||||
export function filterAcceptableGraphqlErrors(
|
||||
error?: ApolloError
|
||||
): ApolloError | undefined {
|
||||
// Currently the only error we expect is when a party has no accounts
|
||||
if (error && error.graphQLErrors.length === 1) {
|
||||
if (isPartyNotFoundError(error.graphQLErrors[0])) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ import { ProposalMinRequirements, ProposalUserAction } from '../shared';
|
||||
import { VoteTransactionDialog } from './vote-transaction-dialog';
|
||||
import { useVoteButtonsQuery } from './__generated__/Stake';
|
||||
import type { DialogProps, VegaTxState } from '@vegaprotocol/proposals';
|
||||
import { filterAcceptableGraphqlErrors } from '../../../../lib/party';
|
||||
|
||||
interface VoteButtonsContainerProps {
|
||||
voteState: VoteState | null;
|
||||
@@ -43,10 +42,8 @@ export const VoteButtonsContainer = (props: VoteButtonsContainerProps) => {
|
||||
skip: !pubKey,
|
||||
});
|
||||
|
||||
const filteredErrors = filterAcceptableGraphqlErrors(error);
|
||||
|
||||
return (
|
||||
<AsyncRenderer loading={loading} error={filteredErrors} data={data}>
|
||||
<AsyncRenderer loading={loading} error={error} data={data}>
|
||||
<VoteButtons
|
||||
{...props}
|
||||
currentStakeAvailable={toBigNum(
|
||||
|
||||
+13
-23
@@ -10,7 +10,6 @@ import { EpochIndividualRewardsTable } from './epoch-individual-rewards-table';
|
||||
import { generateEpochIndividualRewardsList } from './generate-epoch-individual-rewards-list';
|
||||
import { calculateEpochOffset } from '../../../lib/epoch-pagination';
|
||||
import { useNetworkParam } from '@vegaprotocol/network-parameters';
|
||||
import { filterAcceptableGraphqlErrors } from '../../../lib/party';
|
||||
|
||||
const EPOCHS_PAGE_SIZE = 10;
|
||||
|
||||
@@ -100,24 +99,17 @@ export const EpochIndividualRewards = ({
|
||||
prevEpochIdRef.current = epochId;
|
||||
}, [epochId, refetchData]);
|
||||
|
||||
// Workarounds for the error handling of AsyncRenderer
|
||||
const filteredErrors = filterAcceptableGraphqlErrors(error);
|
||||
const filteredData = data || [];
|
||||
|
||||
return (
|
||||
<AsyncRenderer
|
||||
loading={loading}
|
||||
error={filteredErrors}
|
||||
data={filteredData}
|
||||
error={error}
|
||||
data={data}
|
||||
render={() => (
|
||||
<div>
|
||||
<p data-testid="connected-vega-key" className="mb-10">
|
||||
{t('Connected Vega key')}:{' '}
|
||||
<span className="text-white">{pubKey}</span>
|
||||
</p>
|
||||
{epochIndividualRewardSummaries.length === 0 && (
|
||||
<p>{t('No rewards for key')}</p>
|
||||
)}
|
||||
{epochIndividualRewardSummaries.map(
|
||||
(epochIndividualRewardSummary) => (
|
||||
<EpochIndividualRewardsTable
|
||||
@@ -126,19 +118,17 @@ export const EpochIndividualRewards = ({
|
||||
/>
|
||||
)
|
||||
)}
|
||||
{epochIndividualRewardSummaries.length > 0 && (
|
||||
<Pagination
|
||||
isLoading={loading}
|
||||
hasPrevPage={page > 1}
|
||||
hasNextPage={page < totalPages}
|
||||
onBack={() => refetchData(page - 1)}
|
||||
onNext={() => refetchData(page + 1)}
|
||||
onFirst={() => refetchData(1)}
|
||||
onLast={() => refetchData(totalPages)}
|
||||
>
|
||||
{t('Page')} {page}
|
||||
</Pagination>
|
||||
)}
|
||||
<Pagination
|
||||
isLoading={loading}
|
||||
hasPrevPage={page > 1}
|
||||
hasNextPage={page < totalPages}
|
||||
onBack={() => refetchData(page - 1)}
|
||||
onNext={() => refetchData(page + 1)}
|
||||
onFirst={() => refetchData(1)}
|
||||
onLast={() => refetchData(totalPages)}
|
||||
>
|
||||
{t('Page')} {page}
|
||||
</Pagination>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
|
||||
+2
-2
@@ -29,5 +29,5 @@ NX_REFERRALS=true
|
||||
NX_TENDERMINT_URL=https://be.vega.community
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.vega.community/websocket
|
||||
|
||||
# NX_CHARTING_LIBRARY_PATH=https://assets.vega.community/trading-view-bundle/v0.0.1/
|
||||
# NX_CHARTING_LIBRARY_HASH=PDjWaqPFndDp+LCvqbKvntWriaqNzNpZ5i9R/BULzCg=
|
||||
NX_CHARTING_LIBRARY_PATH=https://assets.vega.community/trading-view-bundle/v0.0.1/
|
||||
NX_CHARTING_LIBRARY_HASH=PDjWaqPFndDp+LCvqbKvntWriaqNzNpZ5i9R/BULzCg=
|
||||
|
||||
@@ -29,5 +29,5 @@ NX_REFERRALS=true
|
||||
NX_TENDERMINT_URL=https://be.vega.community
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.vega.community/websocket
|
||||
|
||||
# NX_CHARTING_LIBRARY_PATH=https://assets.vega.community/trading-view-bundle/v0.0.1/
|
||||
# NX_CHARTING_LIBRARY_HASH=PDjWaqPFndDp+LCvqbKvntWriaqNzNpZ5i9R/BULzCg=
|
||||
NX_CHARTING_LIBRARY_PATH=https://assets.vega.community/trading-view-bundle/v0.0.1/
|
||||
NX_CHARTING_LIBRARY_HASH=PDjWaqPFndDp+LCvqbKvntWriaqNzNpZ5i9R/BULzCg=
|
||||
|
||||
@@ -309,29 +309,49 @@ export const ActiveRewardCard = ({
|
||||
].includes(m.state)
|
||||
);
|
||||
|
||||
if (marketSettled) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const assetInActiveMarket =
|
||||
const assetInSettledMarket =
|
||||
allMarkets &&
|
||||
Object.values(allMarkets).some((m: MarketFieldsFragment | null) => {
|
||||
if (m && getAsset(m).id === dispatchStrategy.dispatchMetricAssetId) {
|
||||
return m?.state && MarketState.STATE_ACTIVE === m.state;
|
||||
return (
|
||||
m?.state &&
|
||||
[
|
||||
MarketState.STATE_TRADING_TERMINATED,
|
||||
MarketState.STATE_SETTLED,
|
||||
MarketState.STATE_CANCELLED,
|
||||
MarketState.STATE_CLOSED,
|
||||
].includes(m.state)
|
||||
);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
const marketSuspended = transferNode.markets?.some(
|
||||
if (marketSettled) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Gray out the cards that are related to suspended markets
|
||||
const suspended = transferNode.markets?.some(
|
||||
(m) =>
|
||||
m?.state === MarketState.STATE_SUSPENDED ||
|
||||
m?.state === MarketState.STATE_SUSPENDED_VIA_GOVERNANCE
|
||||
);
|
||||
|
||||
const assetInSuspendedMarket =
|
||||
allMarkets &&
|
||||
Object.values(allMarkets).some((m: MarketFieldsFragment | null) => {
|
||||
if (m && getAsset(m).id === dispatchStrategy.dispatchMetricAssetId) {
|
||||
return (
|
||||
m?.state === MarketState.STATE_SUSPENDED ||
|
||||
m?.state === MarketState.STATE_SUSPENDED_VIA_GOVERNANCE
|
||||
);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
// Gray out the cards that are related to suspended markets
|
||||
// Or settlement assets in markets that are not active and eligible for rewards
|
||||
const { gradientClassName, mainClassName } =
|
||||
marketSuspended || !assetInActiveMarket
|
||||
suspended || assetInSuspendedMarket || assetInSettledMarket
|
||||
? {
|
||||
gradientClassName: 'from-vega-cdark-500 to-vega-clight-400',
|
||||
mainClassName: 'from-vega-cdark-400 dark:from-vega-cdark-600 to-20%',
|
||||
@@ -417,12 +437,12 @@ export const ActiveRewardCard = ({
|
||||
<span>
|
||||
{DispatchMetricLabels[dispatchStrategy.dispatchMetric]} •{' '}
|
||||
<Tooltip
|
||||
underline={marketSuspended}
|
||||
underline={suspended}
|
||||
description={
|
||||
(marketSuspended || !assetInActiveMarket) &&
|
||||
(suspended || assetInSuspendedMarket) &&
|
||||
(specificMarkets
|
||||
? t('Eligible market(s) currently suspended')
|
||||
: !assetInActiveMarket
|
||||
: assetInSuspendedMarket
|
||||
? t('Currently no markets eligible for reward')
|
||||
: '')
|
||||
}
|
||||
|
||||
@@ -81,7 +81,6 @@ export const Settings = () => {
|
||||
intent={Intent.Primary}
|
||||
onClick={() => {
|
||||
localStorage.clear();
|
||||
sessionStorage.clear();
|
||||
window.location.reload();
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -10,15 +10,18 @@ import logging
|
||||
|
||||
logger = logging.getLogger()
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def vega():
|
||||
with init_vega() as vega:
|
||||
yield vega
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def simple_market(vega: VegaServiceNull):
|
||||
return setup_simple_market(vega)
|
||||
|
||||
|
||||
class TestGetStarted:
|
||||
def test_get_started_interactive(self, vega: VegaServiceNull, page: Page):
|
||||
page.goto("/")
|
||||
@@ -30,7 +33,8 @@ class TestGetStarted:
|
||||
expect(page.locator(".list-none")).to_contain_text(
|
||||
"1.Connect2.Deposit funds3.Open a position"
|
||||
)
|
||||
DEFAULT_WALLET_NAME = "MarketSim" # This is the default wallet name within VegaServiceNull and CANNOT be changed
|
||||
# This is the default wallet name within VegaServiceNull and CANNOT be changed
|
||||
DEFAULT_WALLET_NAME = "MarketSim"
|
||||
|
||||
# Calling get_keypairs will internally call _load_tokens for the given wallet
|
||||
keypairs = vega.wallet.get_keypairs(DEFAULT_WALLET_NAME)
|
||||
@@ -137,7 +141,8 @@ class TestGetStarted:
|
||||
def test_get_started_seen_already(self, simple_market, page: Page):
|
||||
page.goto(f"/#/markets/{simple_market}")
|
||||
get_started_locator = page.get_by_test_id("connect-vega-wallet")
|
||||
page.wait_for_selector('[data-testid="connect-vega-wallet"]', state="attached")
|
||||
page.wait_for_selector(
|
||||
'[data-testid="connect-vega-wallet"]', state="attached")
|
||||
expect(get_started_locator).to_be_enabled
|
||||
expect(get_started_locator).to_be_visible
|
||||
# 0007-FUGS-015
|
||||
|
||||
@@ -36,16 +36,19 @@ def validate_info_section(page: Page, fields: [[str, str]]):
|
||||
for rowNumber, field in enumerate(fields):
|
||||
name, value = field
|
||||
expect(
|
||||
page.get_by_test_id("key-value-table-row").nth(rowNumber).locator("dt")
|
||||
page.get_by_test_id(
|
||||
"key-value-table-row").nth(rowNumber).locator("dt")
|
||||
).to_contain_text(name)
|
||||
expect(
|
||||
page.get_by_test_id("key-value-table-row").nth(rowNumber).locator("dd")
|
||||
page.get_by_test_id(
|
||||
"key-value-table-row").nth(rowNumber).locator("dd")
|
||||
).to_contain_text(value)
|
||||
|
||||
@pytest.mark.skip("tbd-market-sim")
|
||||
|
||||
def test_market_info_current_fees(page: Page):
|
||||
# 6002-MDET-101
|
||||
page.get_by_test_id(market_title_test_id).get_by_text("Current fees").click()
|
||||
page.get_by_test_id(market_title_test_id).get_by_text(
|
||||
"Current fees").click()
|
||||
fields = [
|
||||
["Maker Fee", "10%"],
|
||||
["Infrastructure Fee", "0.05%"],
|
||||
@@ -54,10 +57,11 @@ def test_market_info_current_fees(page: Page):
|
||||
]
|
||||
validate_info_section(page, fields)
|
||||
|
||||
@pytest.mark.skip("tbd-market-sim")
|
||||
|
||||
def test_market_info_market_price(page: Page):
|
||||
# 6002-MDET-102
|
||||
page.get_by_test_id(market_title_test_id).get_by_text("Market price").click()
|
||||
page.get_by_test_id(market_title_test_id).get_by_text(
|
||||
"Market price").click()
|
||||
fields = [
|
||||
["Mark Price", "107.50"],
|
||||
["Best Bid Price", "101.50"],
|
||||
@@ -66,10 +70,11 @@ def test_market_info_market_price(page: Page):
|
||||
]
|
||||
validate_info_section(page, fields)
|
||||
|
||||
@pytest.mark.skip("tbd-market-sim")
|
||||
|
||||
def test_market_info_market_volume(page: Page):
|
||||
# 6002-MDET-103
|
||||
page.get_by_test_id(market_title_test_id).get_by_text("Market volume").click()
|
||||
page.get_by_test_id(market_title_test_id).get_by_text(
|
||||
"Market volume").click()
|
||||
fields = [
|
||||
["24 Hour Volume", "-"],
|
||||
["Open Interest", "1"],
|
||||
@@ -80,17 +85,19 @@ def test_market_info_market_volume(page: Page):
|
||||
]
|
||||
validate_info_section(page, fields)
|
||||
|
||||
@pytest.mark.skip("tbd-market-sim")
|
||||
|
||||
def test_market_info_insurance_pool(page: Page):
|
||||
# 6002-MDET-104
|
||||
page.get_by_test_id(market_title_test_id).get_by_text("Insurance pool").click()
|
||||
page.get_by_test_id(market_title_test_id).get_by_text(
|
||||
"Insurance pool").click()
|
||||
fields = [["Balance", "0.00 tDAI"]]
|
||||
validate_info_section(page, fields)
|
||||
|
||||
@pytest.mark.skip("tbd-market-sim")
|
||||
|
||||
def test_market_info_key_details(page: Page, vega: VegaServiceNull):
|
||||
# 6002-MDET-201
|
||||
page.get_by_test_id(market_title_test_id).get_by_text("Key details").click()
|
||||
page.get_by_test_id(market_title_test_id).get_by_text(
|
||||
"Key details").click()
|
||||
market_id = vega.find_market_id("BTC:DAI_2023")
|
||||
short_market_id = market_id[:6] + "…" + market_id[-4:]
|
||||
fields = [
|
||||
@@ -106,7 +113,7 @@ def test_market_info_key_details(page: Page, vega: VegaServiceNull):
|
||||
]
|
||||
validate_info_section(page, fields)
|
||||
|
||||
@pytest.mark.skip("tbd-market-sim")
|
||||
|
||||
def test_market_info_instrument(page: Page):
|
||||
# 6002-MDET-202
|
||||
page.get_by_test_id(market_title_test_id).get_by_text("Instrument").click()
|
||||
@@ -121,7 +128,7 @@ def test_market_info_instrument(page: Page):
|
||||
|
||||
# @pytest.mark.skip("oracle test to be fixed")
|
||||
|
||||
@pytest.mark.skip("tbd-market-sim")
|
||||
|
||||
def test_market_info_oracle(page: Page):
|
||||
# 6002-MDET-203
|
||||
page.get_by_test_id(market_title_test_id).get_by_text("Oracle").click()
|
||||
@@ -135,10 +142,11 @@ def test_market_info_oracle(page: Page):
|
||||
# "href", re.compile(rf'(\/oracles\/{vega.find_market_id("BTC:DAI_2023")})')
|
||||
# )
|
||||
|
||||
@pytest.mark.skip("tbd-market-sim")
|
||||
|
||||
def test_market_info_settlement_asset(page: Page, vega: VegaServiceNull):
|
||||
# 6002-MDET-206
|
||||
page.get_by_test_id(market_title_test_id).get_by_text("Settlement asset").click()
|
||||
page.get_by_test_id(market_title_test_id).get_by_text(
|
||||
"Settlement asset").click()
|
||||
tdai_id = vega.find_asset_id("tDAI")
|
||||
tdai_id_short = tdai_id[:6] + "…" + tdai_id[-4:]
|
||||
fields = [
|
||||
@@ -155,7 +163,7 @@ def test_market_info_settlement_asset(page: Page, vega: VegaServiceNull):
|
||||
]
|
||||
validate_info_section(page, fields)
|
||||
|
||||
@pytest.mark.skip("tbd-market-sim")
|
||||
|
||||
def test_market_info_metadata(page: Page):
|
||||
# 6002-MDET-207
|
||||
page.get_by_test_id(market_title_test_id).get_by_text("Metadata").click()
|
||||
@@ -164,7 +172,7 @@ def test_market_info_metadata(page: Page):
|
||||
]
|
||||
validate_info_section(page, fields)
|
||||
|
||||
@pytest.mark.skip("tbd-market-sim")
|
||||
|
||||
def test_market_info_risk_model(page: Page):
|
||||
# 6002-MDET-208
|
||||
page.get_by_test_id(market_title_test_id).get_by_text("Risk model").click()
|
||||
@@ -175,7 +183,7 @@ def test_market_info_risk_model(page: Page):
|
||||
]
|
||||
validate_info_section(page, fields)
|
||||
|
||||
@pytest.mark.skip("tbd-market-sim")
|
||||
|
||||
def test_market_info_margin_scaling_factors(page: Page):
|
||||
# 6002-MDET-209
|
||||
page.get_by_test_id(market_title_test_id).get_by_text(
|
||||
@@ -183,17 +191,17 @@ def test_market_info_margin_scaling_factors(page: Page):
|
||||
).click()
|
||||
fields = [
|
||||
["Linear Slippage Factor", "0.001"],
|
||||
["Quadratic Slippage Factor", "0"],
|
||||
["Search Level", "1.1"],
|
||||
["Initial Margin", "1.5"],
|
||||
["Collateral Release", "1.7"],
|
||||
]
|
||||
validate_info_section(page, fields)
|
||||
|
||||
@pytest.mark.skip("tbd-market-sim")
|
||||
|
||||
def test_market_info_risk_factors(page: Page):
|
||||
# 6002-MDET-210
|
||||
page.get_by_test_id(market_title_test_id).get_by_text("Risk factors").click()
|
||||
page.get_by_test_id(market_title_test_id).get_by_text(
|
||||
"Risk factors").click()
|
||||
fields = [
|
||||
["Long", "0.05153"],
|
||||
["Short", "0.05422"],
|
||||
@@ -204,7 +212,7 @@ def test_market_info_risk_factors(page: Page):
|
||||
]
|
||||
validate_info_section(page, fields)
|
||||
|
||||
@pytest.mark.skip("tbd-market-sim")
|
||||
|
||||
def test_market_info_price_monitoring_bounds(page: Page):
|
||||
# 6002-MDET-211
|
||||
page.get_by_test_id(market_title_test_id).get_by_text(
|
||||
@@ -213,27 +221,27 @@ def test_market_info_price_monitoring_bounds(page: Page):
|
||||
expect(page.locator("p.col-span-1").nth(0)).to_contain_text(
|
||||
"99.9999% probability price bounds"
|
||||
)
|
||||
expect(page.locator("p.col-span-1").nth(1)).to_contain_text("Within 86,400 seconds")
|
||||
expect(page.locator("p.col-span-1").nth(1)
|
||||
).to_contain_text("Within 86,400 seconds")
|
||||
fields = [
|
||||
["Highest Price", "138.66685 BTC"],
|
||||
["Lowest Price", "83.11038 BTC"],
|
||||
]
|
||||
validate_info_section(page, fields)
|
||||
|
||||
@pytest.mark.skip("tbd-market-sim")
|
||||
|
||||
def test_market_info_liquidity_monitoring_parameters(page: Page):
|
||||
# 6002-MDET-212
|
||||
page.get_by_test_id(market_title_test_id).get_by_text(
|
||||
"Liquidity monitoring parameters"
|
||||
).click()
|
||||
fields = [
|
||||
["Triggering Ratio", "0.7"],
|
||||
["Time Window", "3,600"],
|
||||
["Scaling Factor", "1"],
|
||||
]
|
||||
validate_info_section(page, fields)
|
||||
|
||||
@pytest.mark.skip("tbd-market-sim")
|
||||
|
||||
# Liquidity resolves to 3 results
|
||||
def test_market_info_liquidit(page: Page):
|
||||
# 6002-MDET-213
|
||||
@@ -246,7 +254,7 @@ def test_market_info_liquidit(page: Page):
|
||||
]
|
||||
validate_info_section(page, fields)
|
||||
|
||||
@pytest.mark.skip("tbd-market-sim")
|
||||
|
||||
def test_market_info_liquidity_price_range(page: Page):
|
||||
# 6002-MDET-214
|
||||
page.get_by_test_id(market_title_test_id).get_by_text(
|
||||
@@ -259,19 +267,22 @@ def test_market_info_liquidity_price_range(page: Page):
|
||||
]
|
||||
validate_info_section(page, fields)
|
||||
|
||||
@pytest.mark.skip("tbd-market-sim")
|
||||
|
||||
def test_market_info_proposal(page: Page, vega: VegaServiceNull):
|
||||
# 6002-MDET-301
|
||||
page.get_by_test_id(market_title_test_id).get_by_text("Proposal").click()
|
||||
first_link = (
|
||||
page.get_by_test_id("accordion-content").get_by_test_id("external-link").first
|
||||
page.get_by_test_id(
|
||||
"accordion-content").get_by_test_id("external-link").first
|
||||
)
|
||||
second_link = (
|
||||
page.get_by_test_id("accordion-content").get_by_test_id("external-link").nth(1)
|
||||
page.get_by_test_id(
|
||||
"accordion-content").get_by_test_id("external-link").nth(1)
|
||||
)
|
||||
expect(first_link).to_have_text("View governance proposal")
|
||||
expect(first_link).to_have_attribute(
|
||||
"href", re.compile(rf'(\/proposals\/{vega.find_market_id("BTC:DAI_2023")})')
|
||||
"href", re.compile(
|
||||
rf'(\/proposals\/{vega.find_market_id("BTC:DAI_2023")})')
|
||||
)
|
||||
expect(second_link).to_have_text("Propose a change to market")
|
||||
|
||||
@@ -280,13 +291,14 @@ def test_market_info_proposal(page: Page, vega: VegaServiceNull):
|
||||
"href", re.compile(r"(\/proposals\/propose\/update-market)")
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.skip("tbd-market-sim")
|
||||
|
||||
def test_market_info_succession_line(page: Page, vega: VegaServiceNull):
|
||||
page.get_by_test_id(market_title_test_id).get_by_text("Succession line").click()
|
||||
page.get_by_test_id(market_title_test_id).get_by_text(
|
||||
"Succession line").click()
|
||||
market_id = vega.find_market_id("BTC:DAI_2023")
|
||||
succession_line = page.get_by_test_id("succession-line-item")
|
||||
expect(succession_line.get_by_test_id("external-link")).to_have_text("BTC:DAI_2023")
|
||||
expect(succession_line.get_by_test_id(
|
||||
"external-link")).to_have_text("BTC:DAI_2023")
|
||||
expect(succession_line.get_by_test_id("external-link")).to_have_attribute(
|
||||
"href", re.compile(rf"(\/proposals\/{market_id})")
|
||||
)
|
||||
|
||||
@@ -8,7 +8,7 @@ from actions.utils import next_epoch
|
||||
|
||||
market_banner = "market-banner"
|
||||
|
||||
@pytest.mark.skip("tbd")
|
||||
|
||||
@pytest.mark.usefixtures("risk_accepted")
|
||||
def test_succession_line(vega: VegaServiceNull, page: Page):
|
||||
parent_market_id = setup_continuous_market(vega)
|
||||
@@ -20,12 +20,14 @@ def test_succession_line(vega: VegaServiceNull, page: Page):
|
||||
expect(page.get_by_test_id(market_banner)).not_to_be_attached()
|
||||
|
||||
successor_name = "successor market name"
|
||||
successor_id = propose_successor(vega, parent_market_id, tdai_id, successor_name)
|
||||
successor_id = propose_successor(
|
||||
vega, parent_market_id, tdai_id, successor_name)
|
||||
|
||||
# Check that the banner notifying about the successor proposal is shown
|
||||
banner = page.get_by_test_id(market_banner)
|
||||
expect(banner).to_be_attached()
|
||||
expect(banner.get_by_text("A successor to this market has been proposed")).to_be_visible()
|
||||
expect(banner.get_by_text(
|
||||
"A successor to this market has been proposed")).to_be_visible()
|
||||
|
||||
next_epoch(vega)
|
||||
|
||||
@@ -45,7 +47,6 @@ def test_succession_line(vega: VegaServiceNull, page: Page):
|
||||
# the succession line
|
||||
page.reload()
|
||||
|
||||
#tbd issue - 5546
|
||||
page.get_by_test_id("Info").click()
|
||||
|
||||
page.get_by_role("button", name="Succession line").click()
|
||||
@@ -78,6 +79,7 @@ def test_succession_line(vega: VegaServiceNull, page: Page):
|
||||
page.wait_for_selector('[data-testid="market-banner"]', state="attached")
|
||||
expect(banner.get_by_text("This market has been succeeded")).to_be_visible()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("risk_accepted")
|
||||
def test_banners(vega: VegaServiceNull, page: Page):
|
||||
|
||||
@@ -91,9 +93,9 @@ def test_banners(vega: VegaServiceNull, page: Page):
|
||||
expect(page.get_by_test_id(market_banner)).not_to_be_attached()
|
||||
|
||||
vega.submit_termination_and_settlement_data(
|
||||
settlement_key=GOVERNANCE_WALLET.name,
|
||||
settlement_price=100,
|
||||
market_id=parent_market_id,
|
||||
settlement_key=GOVERNANCE_WALLET.name,
|
||||
settlement_price=100,
|
||||
market_id=parent_market_id,
|
||||
)
|
||||
|
||||
successor_name = "successor market name"
|
||||
@@ -108,7 +110,7 @@ def test_banners(vega: VegaServiceNull, page: Page):
|
||||
# Check that the banner notifying about the successor proposal and market has been settled are shown still after reload
|
||||
page.reload()
|
||||
expect(banner.get_by_text(banner_successor_text)).to_be_visible()
|
||||
expect(banner.get_by_text("1/2")).to_be_visible()
|
||||
expect(banner.get_by_text("1/2")).to_be_visible()
|
||||
# Check that the banner notifying about the successor proposal is not visible after close those banners
|
||||
banner.get_by_test_id("icon-cross").click()
|
||||
expect(banner.get_by_text("This market has been settled")).to_be_visible()
|
||||
@@ -119,7 +121,8 @@ def test_banners(vega: VegaServiceNull, page: Page):
|
||||
expect(page.get_by_test_id(market_banner)).not_to_be_attached()
|
||||
page.reload()
|
||||
expect(banner).to_be_attached()
|
||||
expect(banner.get_by_text(banner_successor_text)).to_be_visible()
|
||||
expect(banner.get_by_text(banner_successor_text)).to_be_visible()
|
||||
|
||||
|
||||
def propose_successor(
|
||||
vega: VegaServiceNull, parent_market_id, tdai_id, market_name
|
||||
@@ -137,6 +140,7 @@ def propose_successor(
|
||||
)
|
||||
return market_id
|
||||
|
||||
|
||||
def provide_successor_liquidity(
|
||||
vega: VegaServiceNull, market_id
|
||||
):
|
||||
|
||||
@@ -96,6 +96,11 @@ describe('TransferForm', () => {
|
||||
});
|
||||
|
||||
it.each([
|
||||
{
|
||||
targetText: 'Include transfer fee',
|
||||
tooltipText:
|
||||
'The fee will be taken from the amount you are transferring.',
|
||||
},
|
||||
{
|
||||
targetText: 'Transfer fee',
|
||||
tooltipText: /transfer\.fee\.factor/,
|
||||
@@ -271,6 +276,9 @@ describe('TransferForm', () => {
|
||||
|
||||
const amountInput = screen.getByLabelText('Amount');
|
||||
|
||||
const checkbox = screen.getByTestId('include-transfer-fee');
|
||||
expect(checkbox).not.toBeChecked();
|
||||
|
||||
await userEvent.clear(amountInput);
|
||||
await userEvent.type(amountInput, '50');
|
||||
|
||||
@@ -280,7 +288,10 @@ describe('TransferForm', () => {
|
||||
await userEvent.click(screen.getByRole('button', { name: 'Use max' }));
|
||||
expect(amountInput).toHaveValue('100.00');
|
||||
|
||||
// If transfering from a vested account fees should be 0
|
||||
// If transfering from a vested account 'include fees' checkbox should
|
||||
// be disabled and fees should be 0
|
||||
expect(checkbox).not.toBeChecked();
|
||||
expect(checkbox).toBeDisabled();
|
||||
const expectedFee = '0';
|
||||
const total = new BigNumber(amount).plus(expectedFee).toFixed();
|
||||
|
||||
@@ -385,7 +396,78 @@ describe('TransferForm', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('IncludeFeesCheckbox', () => {
|
||||
it('validates fields and submits when checkbox is checked', async () => {
|
||||
const mockSubmit = jest.fn();
|
||||
renderComponent({ ...props, submitTransfer: mockSubmit });
|
||||
|
||||
// check current pubkey not shown
|
||||
const keySelect = screen.getByLabelText<HTMLSelectElement>('To Vega key');
|
||||
const pubKeyOptions = ['', pubKey, props.pubKeys[1]];
|
||||
expect(keySelect.children).toHaveLength(pubKeyOptions.length);
|
||||
expect(Array.from(keySelect.options).map((o) => o.value)).toEqual(
|
||||
pubKeyOptions
|
||||
);
|
||||
|
||||
await submit();
|
||||
expect(await screen.findAllByText('Required')).toHaveLength(2); // pubkey set as default value
|
||||
|
||||
// Select a pubkey
|
||||
await userEvent.selectOptions(
|
||||
screen.getByLabelText('To Vega key'),
|
||||
props.pubKeys[1]
|
||||
);
|
||||
|
||||
// Select asset
|
||||
await selectAsset(asset);
|
||||
|
||||
await userEvent.selectOptions(
|
||||
screen.getByLabelText('From account'),
|
||||
`${AccountType.ACCOUNT_TYPE_GENERAL}-${asset.id}`
|
||||
);
|
||||
|
||||
const amountInput = screen.getByLabelText('Amount');
|
||||
const checkbox = screen.getByTestId('include-transfer-fee');
|
||||
|
||||
// 1003-TRAN-022
|
||||
expect(checkbox).not.toBeChecked();
|
||||
|
||||
await userEvent.clear(amountInput);
|
||||
await userEvent.type(amountInput, amount);
|
||||
await userEvent.click(checkbox);
|
||||
|
||||
expect(checkbox).toBeChecked();
|
||||
const expectedFee = new BigNumber(amount)
|
||||
.times(props.feeFactor)
|
||||
.toFixed();
|
||||
const expectedAmount = new BigNumber(amount).minus(expectedFee).toFixed();
|
||||
|
||||
// 1003-TRAN-020
|
||||
expect(screen.getByTestId('transfer-fee')).toHaveTextContent(expectedFee);
|
||||
expect(screen.getByTestId('transfer-amount')).toHaveTextContent(
|
||||
expectedAmount
|
||||
);
|
||||
expect(screen.getByTestId('total-transfer-fee')).toHaveTextContent(
|
||||
amount
|
||||
);
|
||||
|
||||
await submit();
|
||||
|
||||
await waitFor(() => {
|
||||
// 1003-TRAN-023
|
||||
expect(mockSubmit).toHaveBeenCalledTimes(1);
|
||||
expect(mockSubmit).toHaveBeenCalledWith({
|
||||
fromAccountType: AccountType.ACCOUNT_TYPE_GENERAL,
|
||||
toAccountType: AccountType.ACCOUNT_TYPE_GENERAL,
|
||||
to: props.pubKeys[1],
|
||||
asset: asset.id,
|
||||
amount: removeDecimal(expectedAmount, asset.decimals),
|
||||
oneOff: {},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('validates fields when checkbox is not checked', async () => {
|
||||
renderComponent(props);
|
||||
|
||||
@@ -415,8 +497,11 @@ describe('TransferForm', () => {
|
||||
);
|
||||
|
||||
const amountInput = screen.getByLabelText('Amount');
|
||||
const checkbox = screen.getByTestId('include-transfer-fee');
|
||||
expect(checkbox).not.toBeChecked();
|
||||
|
||||
await userEvent.type(amountInput, amount);
|
||||
expect(checkbox).not.toBeChecked();
|
||||
const expectedFee = new BigNumber(amount)
|
||||
.times(props.feeFactor)
|
||||
.toFixed();
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
TradingRichSelect,
|
||||
TradingSelect,
|
||||
Tooltip,
|
||||
TradingCheckbox,
|
||||
TradingButton,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import type { Transfer } from '@vegaprotocol/wallet';
|
||||
@@ -134,17 +135,32 @@ export const TransferForm = ({
|
||||
const accountBalance =
|
||||
account && addDecimal(account.balance, account.asset.decimals);
|
||||
|
||||
const [includeFee, setIncludeFee] = useState(false);
|
||||
|
||||
// Max amount given selected asset and from account
|
||||
const max = accountBalance ? new BigNumber(accountBalance) : new BigNumber(0);
|
||||
|
||||
const fee = useMemo(
|
||||
() => feeFactor && new BigNumber(feeFactor).times(amount).toString(),
|
||||
[amount, feeFactor]
|
||||
);
|
||||
const transferAmount = useMemo(() => {
|
||||
if (!amount) return undefined;
|
||||
if (includeFee && feeFactor) {
|
||||
return new BigNumber(1).minus(feeFactor).times(amount).toString();
|
||||
}
|
||||
return amount;
|
||||
}, [amount, includeFee, feeFactor]);
|
||||
|
||||
const fee = useMemo(() => {
|
||||
if (!transferAmount) return undefined;
|
||||
if (includeFee) {
|
||||
return new BigNumber(amount).minus(transferAmount).toString();
|
||||
}
|
||||
return (
|
||||
feeFactor && new BigNumber(feeFactor).times(transferAmount).toString()
|
||||
);
|
||||
}, [amount, includeFee, transferAmount, feeFactor]);
|
||||
|
||||
const onSubmit = useCallback(
|
||||
(fields: FormFields) => {
|
||||
if (!amount) {
|
||||
if (!transferAmount) {
|
||||
throw new Error('Submitted transfer with no amount selected');
|
||||
}
|
||||
|
||||
@@ -157,7 +173,7 @@ export const TransferForm = ({
|
||||
|
||||
const transfer = normalizeTransfer(
|
||||
fields.toVegaKey,
|
||||
amount,
|
||||
transferAmount,
|
||||
type,
|
||||
AccountType.ACCOUNT_TYPE_GENERAL, // field is readonly in the form
|
||||
{
|
||||
@@ -167,7 +183,7 @@ export const TransferForm = ({
|
||||
);
|
||||
submitTransfer(transfer);
|
||||
},
|
||||
[submitTransfer, amount, assets]
|
||||
[submitTransfer, transferAmount, assets]
|
||||
);
|
||||
|
||||
// reset for placeholder workaround https://github.com/radix-ui/primitives/issues/1569
|
||||
@@ -263,6 +279,7 @@ export const TransferForm = ({
|
||||
) {
|
||||
setValue('toVegaKey', pubKey);
|
||||
setToVegaKeyMode('select');
|
||||
setIncludeFee(false);
|
||||
}
|
||||
}}
|
||||
>
|
||||
@@ -432,9 +449,27 @@ export const TransferForm = ({
|
||||
</TradingInputError>
|
||||
)}
|
||||
</TradingFormGroup>
|
||||
{amount && fee && (
|
||||
<div className="mb-4">
|
||||
<Tooltip
|
||||
description={t(
|
||||
`The fee will be taken from the amount you are transferring.`
|
||||
)}
|
||||
>
|
||||
<div>
|
||||
<TradingCheckbox
|
||||
name="include-transfer-fee"
|
||||
disabled={!transferAmount || fromVested}
|
||||
label={t('Include transfer fee')}
|
||||
checked={includeFee}
|
||||
onCheckedChange={() => setIncludeFee((x) => !x)}
|
||||
/>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
{transferAmount && fee && (
|
||||
<TransferFee
|
||||
amount={amount}
|
||||
amount={transferAmount}
|
||||
transferAmount={transferAmount}
|
||||
feeFactor={feeFactor}
|
||||
fee={fromVested ? '0' : fee}
|
||||
decimals={asset?.decimals}
|
||||
@@ -449,22 +484,29 @@ export const TransferForm = ({
|
||||
|
||||
export const TransferFee = ({
|
||||
amount,
|
||||
transferAmount,
|
||||
feeFactor,
|
||||
fee,
|
||||
decimals,
|
||||
}: {
|
||||
amount: string;
|
||||
transferAmount: string;
|
||||
feeFactor: string | null;
|
||||
fee?: string;
|
||||
decimals?: number;
|
||||
}) => {
|
||||
const t = useT();
|
||||
if (!feeFactor || !amount || !fee) return null;
|
||||
if (isNaN(Number(feeFactor)) || isNaN(Number(amount)) || isNaN(Number(fee))) {
|
||||
if (!feeFactor || !amount || !transferAmount || !fee) return null;
|
||||
if (
|
||||
isNaN(Number(feeFactor)) ||
|
||||
isNaN(Number(amount)) ||
|
||||
isNaN(Number(transferAmount)) ||
|
||||
isNaN(Number(fee))
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const totalValue = new BigNumber(amount).plus(fee).toString();
|
||||
const totalValue = new BigNumber(transferAmount).plus(fee).toString();
|
||||
|
||||
return (
|
||||
<div className="mb-4 flex flex-col gap-2 text-xs">
|
||||
|
||||
@@ -29,6 +29,7 @@ export const assetsProvider = makeDataProvider<
|
||||
>({
|
||||
query: AssetsDocument,
|
||||
getData,
|
||||
errorPolicy: 'all',
|
||||
});
|
||||
|
||||
export const assetsMapProvider = makeDerivedDataProvider<
|
||||
|
||||
@@ -22,11 +22,9 @@ import {
|
||||
type QueryOptions,
|
||||
type ApolloClient,
|
||||
} from '@apollo/client';
|
||||
import { ApolloError } from '@apollo/client';
|
||||
import type { GraphQLErrors } from '@apollo/client/errors';
|
||||
import { type ApolloError } from '@apollo/client';
|
||||
import { GraphQLError } from 'graphql';
|
||||
import { type Subscription, type Observable } from 'zen-observable-ts';
|
||||
import { waitFor } from '@testing-library/react';
|
||||
|
||||
type Item = {
|
||||
cursor: string;
|
||||
@@ -117,24 +115,6 @@ const paginatedSubscribe = makeDataProvider<
|
||||
},
|
||||
});
|
||||
|
||||
const mockErrorPolicyGuard: (errors: GraphQLErrors) => boolean = jest
|
||||
.fn()
|
||||
.mockImplementation(() => true);
|
||||
const errorGuardedSubscribe = makeDataProvider<
|
||||
QueryData,
|
||||
Data,
|
||||
SubscriptionData,
|
||||
Delta,
|
||||
Variables
|
||||
>({
|
||||
query,
|
||||
subscriptionQuery,
|
||||
update,
|
||||
getData,
|
||||
getDelta,
|
||||
errorPolicyGuard: mockErrorPolicyGuard,
|
||||
});
|
||||
|
||||
const derivedSubscribe = makeDerivedDataProvider(
|
||||
[paginatedSubscribe, subscribe],
|
||||
combineData,
|
||||
@@ -404,34 +384,6 @@ describe('data provider', () => {
|
||||
|
||||
subscription.unsubscribe();
|
||||
});
|
||||
|
||||
it('should retry with ignore error policy if errorPolicyGuard returns true', async () => {
|
||||
const subscription = errorGuardedSubscribe(callback, client, variables);
|
||||
const graphQLError = new GraphQLError(
|
||||
'',
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
['market', 'data'],
|
||||
undefined,
|
||||
{
|
||||
type: 'Internal',
|
||||
}
|
||||
);
|
||||
const graphQLErrors = [graphQLError];
|
||||
const error = new ApolloError({ graphQLErrors });
|
||||
|
||||
await rejectQuery(error);
|
||||
const data = generateData(0, 5);
|
||||
await resolveQuery({
|
||||
data,
|
||||
});
|
||||
expect(mockErrorPolicyGuard).toHaveBeenNthCalledWith(1, graphQLErrors);
|
||||
await waitFor(() =>
|
||||
expect(getData).toHaveBeenCalledWith({ data }, variables)
|
||||
);
|
||||
subscription.unsubscribe();
|
||||
});
|
||||
});
|
||||
|
||||
describe('derived data provider', () => {
|
||||
|
||||
@@ -9,7 +9,6 @@ import type {
|
||||
ApolloQueryResult,
|
||||
QueryOptions,
|
||||
} from '@apollo/client';
|
||||
import type { GraphQLErrors } from '@apollo/client/errors';
|
||||
import type { Subscription } from 'zen-observable-ts';
|
||||
import isEqualWith from 'lodash/isEqualWith';
|
||||
import { isNotFoundGraphQLError } from './helpers';
|
||||
@@ -161,7 +160,7 @@ interface DataProviderParams<
|
||||
resetDelay?: number;
|
||||
pollInterval?: number;
|
||||
additionalContext?: Record<string, unknown>;
|
||||
errorPolicyGuard?: (graphqlErrors: GraphQLErrors) => boolean;
|
||||
errorPolicy?: ErrorPolicy;
|
||||
getQueryVariables?: (variables: Variables) => QueryVariables;
|
||||
getSubscriptionVariables?: (
|
||||
variables: Variables
|
||||
@@ -176,7 +175,7 @@ interface DataProviderParams<
|
||||
* @param fetchPolicy
|
||||
* @param resetDelay
|
||||
* @param additionalContext add property to the context of the query, ie. 'isEnlargedTimeout'
|
||||
* @param errorPolicyGuard indicate which gql errors can be tolerate
|
||||
* @param errorPolicy Apollos error policy, will be used when querying
|
||||
* @returns subscribe function
|
||||
*/
|
||||
function makeDataProviderInternal<
|
||||
@@ -197,7 +196,7 @@ function makeDataProviderInternal<
|
||||
fetchPolicy,
|
||||
resetDelay,
|
||||
additionalContext,
|
||||
errorPolicyGuard,
|
||||
errorPolicy = 'none',
|
||||
getQueryVariables,
|
||||
getSubscriptionVariables,
|
||||
pollInterval,
|
||||
@@ -331,20 +330,10 @@ function makeDataProviderInternal<
|
||||
const callQuery = (
|
||||
pagination?: Pagination,
|
||||
policy?: ErrorPolicy
|
||||
): Promise<ApolloQueryResult<QueryData>> =>
|
||||
client
|
||||
.query<QueryData>(getQueryOptions(pagination, policy))
|
||||
.catch((err) => {
|
||||
if (
|
||||
err.graphQLErrors &&
|
||||
errorPolicyGuard &&
|
||||
errorPolicyGuard(err.graphQLErrors)
|
||||
) {
|
||||
return callQuery(pagination, 'ignore');
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
): Promise<ApolloQueryResult<QueryData>> => {
|
||||
const options = getQueryOptions(pagination, policy);
|
||||
return client.query<QueryData>(options);
|
||||
};
|
||||
|
||||
const load = async () => {
|
||||
if (!pagination) {
|
||||
@@ -364,7 +353,7 @@ function makeDataProviderInternal<
|
||||
}
|
||||
}
|
||||
|
||||
const res = await callQuery(paginationVariables);
|
||||
const res = await callQuery(paginationVariables, errorPolicy);
|
||||
|
||||
const insertionData = getData(res.data, variables);
|
||||
const insertionPageInfo = pagination.getPageInfo(res.data);
|
||||
@@ -417,12 +406,14 @@ function makeDataProviderInternal<
|
||||
const paginationVariables = pagination
|
||||
? { first: pagination.first }
|
||||
: undefined;
|
||||
|
||||
if (pollInterval) {
|
||||
callWatchQuery();
|
||||
callWatchQuery(paginationVariables, errorPolicy);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
onNext(await callQuery(paginationVariables));
|
||||
onNext(await callQuery(paginationVariables, errorPolicy));
|
||||
} catch (e) {
|
||||
onError(e as Error);
|
||||
} finally {
|
||||
|
||||
@@ -27,10 +27,3 @@ const hasNotFoundGraphQLErrors = (errors: GraphQLErrors, path?: string[]) => {
|
||||
(!path || path.every((item, i) => item === e?.path?.[i]))
|
||||
);
|
||||
};
|
||||
|
||||
export const marketDataErrorPolicyGuard = (errors: GraphQLErrors) =>
|
||||
errors.every(
|
||||
(e) =>
|
||||
e.message.match(/no market data for market:/i) ||
|
||||
e.message.match(/Conditions list is empty/)
|
||||
);
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
"Deposited on the network, but not allocated to a market. Free to use for placing orders or providing liquidity.": "Deposited on the network, but not allocated to a market. Free to use for placing orders or providing liquidity.",
|
||||
"Enter manually": "Enter manually",
|
||||
"From account": "From account",
|
||||
"Include transfer fee": "Include transfer fee",
|
||||
"initial level": "initial level",
|
||||
"maintenance level": "maintenance level",
|
||||
"Margin health": "Margin health",
|
||||
@@ -32,6 +33,7 @@
|
||||
"release level": "release level",
|
||||
"search level": "search level",
|
||||
"Select from wallet": "Select from wallet",
|
||||
"The fee will be taken from the amount you are transferring.": "The fee will be taken from the amount you are transferring.",
|
||||
"The total amount of each asset on this key. Includes used and available collateral.": "The total amount of each asset on this key. Includes used and available collateral.",
|
||||
"The total amount taken from your account. The amount to be transferred plus the fee.": "The total amount taken from your account. The amount to be transferred plus the fee.",
|
||||
"The total amount to be transferred (without the fee)": "The total amount to be transferred (without the fee)",
|
||||
|
||||
@@ -300,7 +300,7 @@
|
||||
"Unknown": "Unknown",
|
||||
"Unknown settlement date": "Unknown settlement date",
|
||||
"Vega Reward pot": "Vega Reward pot",
|
||||
"Vega Wallet <0>full featured</0>": "Vega Wallet <0>full featured</0>",
|
||||
"Vega Wallet <0>full featured<0>": "Vega Wallet <0>full featured<0>",
|
||||
"Vega chart": "Vega chart",
|
||||
"Vesting": "Vesting",
|
||||
"Vesting multiplier": "Vesting multiplier",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import {
|
||||
makeDataProvider,
|
||||
makeDerivedDataProvider,
|
||||
marketDataErrorPolicyGuard,
|
||||
} from '@vegaprotocol/data-provider';
|
||||
import {
|
||||
MarketInfoDocument,
|
||||
@@ -33,7 +32,7 @@ export const marketInfoProvider = makeDataProvider<
|
||||
>({
|
||||
query: MarketInfoDocument,
|
||||
getData,
|
||||
errorPolicyGuard: marketDataErrorPolicyGuard,
|
||||
errorPolicy: 'all',
|
||||
pollInterval: 5000,
|
||||
});
|
||||
|
||||
|
||||
@@ -113,8 +113,6 @@ export const filterAndSortClosedMarkets = (markets: MarketMaybeWithData[]) => {
|
||||
return [
|
||||
MarketState.STATE_SETTLED,
|
||||
MarketState.STATE_TRADING_TERMINATED,
|
||||
MarketState.STATE_CLOSED,
|
||||
MarketState.STATE_CANCELLED,
|
||||
].includes(m.data?.marketState || m.state);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { marketDataErrorPolicyGuard } from '@vegaprotocol/data-provider';
|
||||
import { makeDataProvider } from '@vegaprotocol/data-provider';
|
||||
import {
|
||||
MarketsDataDocument,
|
||||
@@ -54,7 +53,7 @@ export const marketsDataProvider = makeDataProvider<
|
||||
>({
|
||||
query: MarketsDataDocument,
|
||||
getData,
|
||||
errorPolicyGuard: marketDataErrorPolicyGuard,
|
||||
errorPolicy: 'all',
|
||||
});
|
||||
|
||||
type Variables = { marketIds: string[] };
|
||||
@@ -73,7 +72,7 @@ export const marketsLiveDataProvider = makeDataProvider<
|
||||
getData,
|
||||
getDelta,
|
||||
update,
|
||||
errorPolicyGuard: marketDataErrorPolicyGuard,
|
||||
errorPolicy: 'all',
|
||||
getQueryVariables: () => ({}),
|
||||
getSubscriptionVariables: ({ marketIds }: Variables) =>
|
||||
marketIds.map((marketId) => ({ marketId })),
|
||||
|
||||
@@ -2,7 +2,6 @@ import { useYesterday } from '@vegaprotocol/react-helpers';
|
||||
import {
|
||||
makeDataProvider,
|
||||
makeDerivedDataProvider,
|
||||
marketDataErrorPolicyGuard,
|
||||
useDataProvider,
|
||||
} from '@vegaprotocol/data-provider';
|
||||
import {
|
||||
@@ -45,7 +44,7 @@ export const marketsProvider = makeDataProvider<
|
||||
query: MarketsDocument,
|
||||
getData,
|
||||
fetchPolicy: 'cache-first',
|
||||
errorPolicyGuard: marketDataErrorPolicyGuard,
|
||||
errorPolicy: 'all',
|
||||
});
|
||||
|
||||
export const marketsMapProvider = makeDerivedDataProvider<
|
||||
|
||||
@@ -39,8 +39,7 @@ export const proposalsDataProvider = makeDataProvider<
|
||||
*
|
||||
* GQL Path: `terms.change.instrument.futureProduct.settlementAsset`
|
||||
*/
|
||||
errorPolicyGuard: (errors) =>
|
||||
errors.every((e) => e.message.match(/failed to get asset for ID/)),
|
||||
errorPolicy: 'all',
|
||||
});
|
||||
|
||||
const ProposalTypeMap: Record<
|
||||
|
||||
@@ -11,9 +11,7 @@
|
||||
"echo $NX_VEGA_URL",
|
||||
"echo $NX_TENDERMINT_URL",
|
||||
"echo $NX_TENDERMINT_WEBSOCKET_URL",
|
||||
"echo $NX_ETHEREUM_PROVIDER_URL",
|
||||
"echo $NX_CHARTING_LIBRARY_PATH",
|
||||
"echo $NX_CHARTING_LIBRARY_HASH"
|
||||
"echo $NX_ETHEREUM_PROVIDER_URL"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,12 +40,22 @@
|
||||
|
||||
## Transfer
|
||||
|
||||
- **Must** can select include transfer fee (<a name="1003-TRAN-015" href="#1003-TRAN-015">1003-TRAN-015</a>)
|
||||
|
||||
- **Must** display tooltip for "Include transfer fee" when hovered over.(<a name="1003-TRAN-016" href="#1003-TRAN-016">1003-TRAN-016</a>)
|
||||
|
||||
- **Must** display tooltip for "Transfer fee when hovered over.(<a name="1003-TRAN-017" href="#1003-TRAN-017">1003-TRAN-017</a>)
|
||||
|
||||
- **Must** display tooltip for "Amount to be transferred" when hovered over.(<a name="1003-TRAN-018" href="#1003-TRAN-018">1003-TRAN-018</a>)
|
||||
|
||||
- **Must** display tooltip for "Total amount (with fee)" when hovered over.(<a name="1003-TRAN-019" href="#1003-TRAN-019">1003-TRAN-019</a>)
|
||||
|
||||
- **Must** amount to be transferred and transfer fee update correctly when include transfer fee is selected (<a name="1003-TRAN-020" href="#1003-TRAN-020">1003-TRAN-020</a>)
|
||||
|
||||
- **Must** total amount with fee is correct with and without "Include transfer fee" selected (<a name="1003-TRAN-021" href="#1003-TRAN-021">1003-TRAN-021</a>)
|
||||
|
||||
- **Must** i cannot select include transfer fee unless amount is entered (<a name="1003-TRAN-022" href="#1003-TRAN-022">1003-TRAN-022</a>)
|
||||
|
||||
- **Must** With all fields entered correctly, clicking "confirm transfer" button will start transaction(<a name="1003-TRAN-023" href="#1003-TRAN-023">1003-TRAN-023</a>)
|
||||
|
||||
### Transfer page
|
||||
|
||||
Reference in New Issue
Block a user