Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5287744729 | ||
|
|
110fddde21 | ||
|
|
f08db503d5 | ||
|
|
e0e0a6e6bd | ||
|
|
af9d2c3437 | ||
|
|
13caceec4a |
@@ -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>
|
||||
)}
|
||||
/>
|
||||
|
||||
@@ -21,7 +21,6 @@ NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
|
||||
# Cosmic elevator flags
|
||||
NX_SUCCESSOR_MARKETS=true
|
||||
NX_STOP_ORDERS=true
|
||||
NX_ISOLATED_MARGIN=true
|
||||
NX_ICEBERG_ORDERS=true
|
||||
NX_METAMASK_SNAPS=true
|
||||
NX_REFERRALS=true
|
||||
|
||||
@@ -21,7 +21,6 @@ NX_ETH_WALLET_MNEMONIC="ozone access unlock valid olympic save include omit supp
|
||||
# Cosmic elevator flags
|
||||
NX_SUCCESSOR_MARKETS=false
|
||||
NX_STOP_ORDERS=false
|
||||
NX_ISOLATED_MARGIN=true
|
||||
# NX_ICEBERG_ORDERS
|
||||
# NX_PRODUCT_PERPETUALS
|
||||
NX_METAMASK_SNAPS=false
|
||||
|
||||
@@ -20,7 +20,6 @@ NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/m
|
||||
# Cosmic elevator flags
|
||||
NX_SUCCESSOR_MARKETS=true
|
||||
NX_STOP_ORDERS=true
|
||||
NX_ISOLATED_MARGIN=true
|
||||
# NX_ICEBERG_ORDERS
|
||||
# NX_PRODUCT_PERPETUALS
|
||||
NX_METAMASK_SNAPS=true
|
||||
|
||||
@@ -21,7 +21,6 @@ NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
|
||||
# Cosmic elevator flags
|
||||
NX_SUCCESSOR_MARKETS=true
|
||||
NX_STOP_ORDERS=true
|
||||
NX_ISOLATED_MARGIN=false
|
||||
NX_ICEBERG_ORDERS=true
|
||||
NX_METAMASK_SNAPS=true
|
||||
NX_REFERRALS=true
|
||||
|
||||
@@ -21,7 +21,6 @@ NX_APP_VERSION=v0.20.19-core-0.71.6
|
||||
# Cosmic elevator flags
|
||||
NX_SUCCESSOR_MARKETS=true
|
||||
NX_STOP_ORDERS=true
|
||||
NX_ISOLATED_MARGIN=false
|
||||
NX_ICEBERG_ORDERS=true
|
||||
# NX_PRODUCT_PERPETUALS
|
||||
NX_METAMASK_SNAPS=false
|
||||
|
||||
@@ -21,7 +21,6 @@ NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
|
||||
# Cosmic elevator flags
|
||||
NX_SUCCESSOR_MARKETS=true
|
||||
NX_STOP_ORDERS=true
|
||||
NX_ISOLATED_MARGIN=true
|
||||
NX_ICEBERG_ORDERS=true
|
||||
# NX_PRODUCT_PERPETUALS
|
||||
NX_METAMASK_SNAPS=true
|
||||
|
||||
@@ -22,7 +22,6 @@ NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
|
||||
# Cosmic elevator flags
|
||||
NX_SUCCESSOR_MARKETS=true
|
||||
NX_STOP_ORDERS=true
|
||||
NX_ISOLATED_MARGIN=true
|
||||
NX_ICEBERG_ORDERS=true
|
||||
NX_METAMASK_SNAPS=true
|
||||
NX_REFERRALS=true
|
||||
|
||||
@@ -22,7 +22,6 @@ NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/m
|
||||
# Cosmic elevator flags
|
||||
NX_SUCCESSOR_MARKETS=true
|
||||
NX_STOP_ORDERS=true
|
||||
NX_ISOLATED_MARGIN=true
|
||||
NX_ICEBERG_ORDERS=true
|
||||
# NX_PRODUCT_PERPETUALS
|
||||
NX_METAMASK_SNAPS=false
|
||||
|
||||
Generated
+2
-2
@@ -1,4 +1,4 @@
|
||||
# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand.
|
||||
# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
@@ -1161,7 +1161,7 @@ profile = ["pytest-profiling", "snakeviz"]
|
||||
type = "git"
|
||||
url = "https://github.com/vegaprotocol/vega-market-sim.git/"
|
||||
reference = "HEAD"
|
||||
resolved_reference = "4440abbb6ce0d3e80beba5cd01f20cd21983cbf8"
|
||||
resolved_reference = "2aed8c94b25d8fa2e376d3b63ca1f9193d28cdfd"
|
||||
|
||||
[[package]]
|
||||
name = "websocket-client"
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
import pytest
|
||||
from playwright.sync_api import Page, expect
|
||||
from vega_sim.null_service import VegaServiceNull
|
||||
from actions.vega import submit_order
|
||||
from actions.utils import next_epoch, wait_for_toast_confirmation
|
||||
|
||||
tooltip_content = "tooltip-content"
|
||||
leverage_input = "#leverage-input"
|
||||
tab_positions = "tab-positions"
|
||||
margin_row = '[col-id="margin"]'
|
||||
|
||||
|
||||
def create_position(vega: VegaServiceNull, market_id):
|
||||
submit_order(vega, "Key 1", market_id, "SIDE_SELL", 100, 110)
|
||||
submit_order(vega, "Key 1", market_id, "SIDE_BUY", 100, 110)
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("auth", "risk_accepted")
|
||||
def test_switch_cross_isolated_margin(
|
||||
continuous_market, vega: VegaServiceNull, page: Page):
|
||||
create_position(vega, continuous_market)
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
expect(page.locator(margin_row).nth(1)).to_have_text("874.21992Cross1.0x")
|
||||
# tbd - tooltip is not visible without this wait
|
||||
page.wait_for_timeout(1000)
|
||||
page.get_by_test_id(tab_positions).get_by_text("Cross").hover()
|
||||
expect(page.get_by_test_id(tooltip_content).nth(0)).to_have_text(
|
||||
"Liquidation: 582.81328Margin: 874.21992General account: 998,084.95183"
|
||||
)
|
||||
page.get_by_role("button", name="Isolated 10x").click()
|
||||
page.locator(leverage_input).clear()
|
||||
page.locator(leverage_input).type("1")
|
||||
page.get_by_role("button", name="Confirm").click()
|
||||
wait_for_toast_confirmation(page)
|
||||
next_epoch(vega=vega)
|
||||
expect(page.get_by_test_id("toast-content")).to_have_text(
|
||||
"ConfirmedYour transaction has been confirmedView in block explorerUpdate margin modeBTC:DAI_2023Isolated margin mode, leverage: 1.0x")
|
||||
expect(page.locator(margin_row).nth(1)
|
||||
).to_have_text("11,109.99996Isolated1.0x")
|
||||
# tbd - tooltip is not visible without this wait
|
||||
page.wait_for_timeout(1000)
|
||||
page.get_by_test_id(tab_positions).get_by_text("Isolated").hover()
|
||||
expect(page.get_by_test_id(tooltip_content).nth(0)).to_have_text(
|
||||
"Liquidation: 583.62409Margin: 11,109.99996Order: 11,000.00"
|
||||
)
|
||||
page.get_by_role("button", name="Cross").click()
|
||||
page.get_by_role("button", name="Confirm").click()
|
||||
wait_for_toast_confirmation(page)
|
||||
next_epoch(vega=vega)
|
||||
expect(page.locator(margin_row).nth(1)).to_have_text(
|
||||
"22,109.99996Cross1.0x")
|
||||
@@ -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})")
|
||||
)
|
||||
|
||||
@@ -29,15 +29,13 @@ def verify_data_grid(page: Page, data_test_id, expected_pattern):
|
||||
logger.info(f"Matched: {expected} == {actual}")
|
||||
else:
|
||||
logger.info(f"Not Matched: {expected} != {actual}")
|
||||
raise AssertionError(
|
||||
f"Pattern does not match: {expected} != {actual}")
|
||||
raise AssertionError(f"Pattern does not match: {expected} != {actual}")
|
||||
else: # it's not a regex, so we escape it
|
||||
if re.search(re.escape(expected), actual):
|
||||
logger.info(f"Matched: {expected} == {actual}")
|
||||
else:
|
||||
logger.info(f"Not Matched: {expected} != {actual}")
|
||||
raise AssertionError(
|
||||
f"Pattern does not match: {expected} != {actual}")
|
||||
raise AssertionError(f"Pattern does not match: {expected} != {actual}")
|
||||
|
||||
|
||||
def submit_order(vega: VegaServiceNull, wallet_name, market_id, side, volume, price):
|
||||
@@ -93,7 +91,7 @@ def test_limit_order_trade_open_position(continuous_market, page: Page):
|
||||
"average_entry_price": "107.50",
|
||||
"mark_price": "107.50",
|
||||
"margin": "8.50269",
|
||||
"leverage": "Cross1.0x",
|
||||
"leverage": "1.0x",
|
||||
"liquidation": "0.00",
|
||||
"realised_pnl": "0.00",
|
||||
"unrealised_pnl": "0.00",
|
||||
@@ -106,8 +104,7 @@ def test_limit_order_trade_open_position(continuous_market, page: Page):
|
||||
# 7004-POSI-002
|
||||
|
||||
size_and_notional = table.locator("[col-id='openVolume']")
|
||||
expect(size_and_notional.get_by_test_id(
|
||||
primary_id)).to_have_text(position["size"])
|
||||
expect(size_and_notional.get_by_test_id(primary_id)).to_have_text(position["size"])
|
||||
expect(size_and_notional.get_by_test_id(secondary_id)).to_have_text(
|
||||
position["notional"]
|
||||
)
|
||||
|
||||
@@ -28,9 +28,8 @@ def test_usage_breakdown(continuous_market, page: Page):
|
||||
usage_breakdown = page.get_by_test_id("usage-breakdown")
|
||||
|
||||
# Verify headers
|
||||
headers = ["Market", "Account type", "Balance"]
|
||||
ag_headers = usage_breakdown.locator(
|
||||
".ag-header-cell-text").element_handles()
|
||||
headers = ["Market", "Account type", "Balance", "Margin health"]
|
||||
ag_headers = usage_breakdown.locator(".ag-header-cell-text").element_handles()
|
||||
for i, header_element in enumerate(ag_headers):
|
||||
header_text = header_element.text_content()
|
||||
assert header_text == headers[i]
|
||||
@@ -39,10 +38,30 @@ def test_usage_breakdown(continuous_market, page: Page):
|
||||
expect(usage_breakdown.locator('[class="mb-2 text-sm"]')).to_have_text(
|
||||
"You have 1,000,000.00 tDAI in total."
|
||||
)
|
||||
expect(usage_breakdown.locator(
|
||||
COL_ID_USED).first).to_have_text("8.50269 (0%)")
|
||||
expect(usage_breakdown.locator(COL_ID_USED).first).to_have_text("8.50269 (0%)")
|
||||
expect(usage_breakdown.locator(COL_ID_USED).nth(1)).to_have_text(
|
||||
"999,991.49731 (99%)"
|
||||
)
|
||||
|
||||
# Maintenance Level
|
||||
expect(
|
||||
usage_breakdown.locator(
|
||||
".ag-center-cols-container [col-id='market.id'] .ag-cell-value"
|
||||
).first
|
||||
).to_have_text("2.85556 above maintenance level")
|
||||
|
||||
# Margin health tooltip
|
||||
usage_breakdown.get_by_test_id("margin-health-chart-track").hover()
|
||||
tooltip_data = [
|
||||
("maintenance level", "5.64713"),
|
||||
("search level", "6.21184"),
|
||||
("initial level", "8.47069"),
|
||||
("balance", "8.50269"),
|
||||
("release level", "9.60012"),
|
||||
]
|
||||
|
||||
for index, (label, value) in enumerate(tooltip_data):
|
||||
expect(page.get_by_test_id(TOOLTIP_LABEL).nth(index)).to_have_text(label)
|
||||
expect(page.get_by_test_id(TOOLTIP_VALUE).nth(index)).to_have_text(value)
|
||||
|
||||
page.get_by_test_id("dialog-close").click()
|
||||
|
||||
@@ -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
|
||||
):
|
||||
|
||||
@@ -3,9 +3,6 @@ fragment MarginFields on MarginLevels {
|
||||
searchLevel
|
||||
initialLevel
|
||||
collateralReleaseLevel
|
||||
marginFactor
|
||||
marginMode
|
||||
orderMarginLevel
|
||||
asset {
|
||||
id
|
||||
}
|
||||
@@ -36,9 +33,6 @@ subscription MarginsSubscription($partyId: ID!) {
|
||||
searchLevel
|
||||
initialLevel
|
||||
collateralReleaseLevel
|
||||
marginFactor
|
||||
marginMode
|
||||
orderMarginLevel
|
||||
timestamp
|
||||
}
|
||||
}
|
||||
|
||||
+3
-9
@@ -3,21 +3,21 @@ import * as Types from '@vegaprotocol/types';
|
||||
import { gql } from '@apollo/client';
|
||||
import * as Apollo from '@apollo/client';
|
||||
const defaultOptions = {} as const;
|
||||
export type MarginFieldsFragment = { __typename?: 'MarginLevels', maintenanceLevel: string, searchLevel: string, initialLevel: string, collateralReleaseLevel: string, marginFactor: string, marginMode: Types.MarginMode, orderMarginLevel: string, asset: { __typename?: 'Asset', id: string }, market: { __typename?: 'Market', id: string } };
|
||||
export type MarginFieldsFragment = { __typename?: 'MarginLevels', maintenanceLevel: string, searchLevel: string, initialLevel: string, collateralReleaseLevel: string, asset: { __typename?: 'Asset', id: string }, market: { __typename?: 'Market', id: string } };
|
||||
|
||||
export type MarginsQueryVariables = Types.Exact<{
|
||||
partyId: Types.Scalars['ID'];
|
||||
}>;
|
||||
|
||||
|
||||
export type MarginsQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, marginsConnection?: { __typename?: 'MarginConnection', edges?: Array<{ __typename?: 'MarginEdge', node: { __typename?: 'MarginLevels', maintenanceLevel: string, searchLevel: string, initialLevel: string, collateralReleaseLevel: string, marginFactor: string, marginMode: Types.MarginMode, orderMarginLevel: string, asset: { __typename?: 'Asset', id: string }, market: { __typename?: 'Market', id: string } } }> | null } | null } | null };
|
||||
export type MarginsQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, marginsConnection?: { __typename?: 'MarginConnection', edges?: Array<{ __typename?: 'MarginEdge', node: { __typename?: 'MarginLevels', maintenanceLevel: string, searchLevel: string, initialLevel: string, collateralReleaseLevel: string, asset: { __typename?: 'Asset', id: string }, market: { __typename?: 'Market', id: string } } }> | null } | null } | null };
|
||||
|
||||
export type MarginsSubscriptionSubscriptionVariables = Types.Exact<{
|
||||
partyId: Types.Scalars['ID'];
|
||||
}>;
|
||||
|
||||
|
||||
export type MarginsSubscriptionSubscription = { __typename?: 'Subscription', margins: { __typename?: 'MarginLevelsUpdate', marketId: string, asset: string, partyId: string, maintenanceLevel: string, searchLevel: string, initialLevel: string, collateralReleaseLevel: string, marginFactor: string, marginMode: Types.MarginMode, orderMarginLevel: string, timestamp: any } };
|
||||
export type MarginsSubscriptionSubscription = { __typename?: 'Subscription', margins: { __typename?: 'MarginLevelsUpdate', marketId: string, asset: string, partyId: string, maintenanceLevel: string, searchLevel: string, initialLevel: string, collateralReleaseLevel: string, timestamp: any } };
|
||||
|
||||
export const MarginFieldsFragmentDoc = gql`
|
||||
fragment MarginFields on MarginLevels {
|
||||
@@ -25,9 +25,6 @@ export const MarginFieldsFragmentDoc = gql`
|
||||
searchLevel
|
||||
initialLevel
|
||||
collateralReleaseLevel
|
||||
marginFactor
|
||||
marginMode
|
||||
orderMarginLevel
|
||||
asset {
|
||||
id
|
||||
}
|
||||
@@ -88,9 +85,6 @@ export const MarginsSubscriptionDocument = gql`
|
||||
searchLevel
|
||||
initialLevel
|
||||
collateralReleaseLevel
|
||||
marginFactor
|
||||
marginMode
|
||||
orderMarginLevel
|
||||
timestamp
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +105,6 @@ export interface AccountFields extends Account {
|
||||
// The total balance of these accounts will be used for the 'used' column in the
|
||||
// collateral table
|
||||
const USE_ACCOUNT_TYPES = [
|
||||
AccountType.ACCOUNT_TYPE_ORDER_MARGIN,
|
||||
AccountType.ACCOUNT_TYPE_MARGIN,
|
||||
AccountType.ACCOUNT_TYPE_BOND,
|
||||
AccountType.ACCOUNT_TYPE_FEES_INFRASTRUCTURE,
|
||||
|
||||
@@ -4,6 +4,14 @@ import * as Types from '@vegaprotocol/types';
|
||||
import type { AccountFields } from './accounts-data-provider';
|
||||
import { getAccountData } from './accounts-data-provider';
|
||||
|
||||
const marginHealthChartTestId = 'margin-health-chart';
|
||||
|
||||
jest.mock('./margin-health-chart', () => ({
|
||||
MarginHealthChart: () => {
|
||||
return <div data-testid={marginHealthChartTestId}></div>;
|
||||
},
|
||||
}));
|
||||
|
||||
const singleRow = {
|
||||
__typename: 'AccountBalance',
|
||||
type: Types.AccountType.ACCOUNT_TYPE_MARGIN,
|
||||
@@ -41,10 +49,10 @@ describe('BreakdownTable', () => {
|
||||
render(<BreakdownTable data={singleRowData} />);
|
||||
});
|
||||
const headers = await screen.findAllByRole('columnheader');
|
||||
expect(headers).toHaveLength(3);
|
||||
expect(headers).toHaveLength(4);
|
||||
expect(
|
||||
headers.map((h) => h.querySelector('[ref="eText"]')?.textContent?.trim())
|
||||
).toEqual(['Market', 'Account type', 'Balance']);
|
||||
).toEqual(['Market', 'Account type', 'Balance', 'Margin health']);
|
||||
});
|
||||
|
||||
it('should apply correct formatting', async () => {
|
||||
@@ -62,6 +70,24 @@ describe('BreakdownTable', () => {
|
||||
cells.slice(0, -1).forEach((cell, i) => {
|
||||
expect(cell).toHaveTextContent(expectedValues[i]);
|
||||
});
|
||||
expect(screen.getByTestId(marginHealthChartTestId)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('displays margin health chart only for margin account', async () => {
|
||||
await act(async () => {
|
||||
render(
|
||||
<BreakdownTable
|
||||
data={[
|
||||
{
|
||||
...singleRow,
|
||||
type: Types.AccountType.ACCOUNT_TYPE_GENERAL,
|
||||
market: null,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
);
|
||||
});
|
||||
expect(screen.queryByTestId(marginHealthChartTestId)).toBeNull();
|
||||
});
|
||||
|
||||
it('should get correct account data', () => {
|
||||
|
||||
@@ -16,13 +16,14 @@ import { ProgressBarCell } from '@vegaprotocol/datagrid';
|
||||
import { AgGrid, PriceCell } from '@vegaprotocol/datagrid';
|
||||
import type { ColDef } from 'ag-grid-community';
|
||||
import { accountValuesComparator } from './accounts-table';
|
||||
import { MarginHealthChart } from './margin-health-chart';
|
||||
import { MarketNameCell } from '@vegaprotocol/datagrid';
|
||||
import { AccountType } from '@vegaprotocol/types';
|
||||
|
||||
const defaultColDef = {
|
||||
resizable: true,
|
||||
sortable: true,
|
||||
minWidth: 100,
|
||||
flex: 1,
|
||||
};
|
||||
|
||||
interface BreakdownTableProps extends AgGridReactProps {
|
||||
@@ -38,7 +39,7 @@ const BreakdownTable = forwardRef<AgGridReact, BreakdownTableProps>(
|
||||
{
|
||||
headerName: t('Market'),
|
||||
field: 'market.tradableInstrument.instrument.code',
|
||||
maxWidth: 150,
|
||||
width: 90,
|
||||
pinned: true,
|
||||
sort: 'desc',
|
||||
cellRenderer: ({
|
||||
@@ -110,6 +111,23 @@ const BreakdownTable = forwardRef<AgGridReact, BreakdownTableProps>(
|
||||
},
|
||||
comparator: accountValuesComparator,
|
||||
},
|
||||
{
|
||||
headerName: t('Margin health'),
|
||||
field: 'market.id',
|
||||
maxWidth: 500,
|
||||
sortable: false,
|
||||
cellRenderer: ({
|
||||
data,
|
||||
}: VegaICellRendererParams<AccountFields, 'market.id'>) =>
|
||||
data?.market?.id &&
|
||||
data.type === AccountType['ACCOUNT_TYPE_MARGIN'] &&
|
||||
data?.asset.id ? (
|
||||
<MarginHealthChart
|
||||
marketId={data.market.id}
|
||||
assetId={data.asset.id}
|
||||
/>
|
||||
) : null,
|
||||
},
|
||||
];
|
||||
return defs;
|
||||
}, [t]);
|
||||
|
||||
@@ -20,20 +20,14 @@ const update = (
|
||||
return produce(data || [], (draft) => {
|
||||
const { marketId } = delta;
|
||||
const index = draft.findIndex((node) => node.market.id === marketId);
|
||||
const deltaData = {
|
||||
maintenanceLevel: delta.maintenanceLevel,
|
||||
searchLevel: delta.searchLevel,
|
||||
initialLevel: delta.initialLevel,
|
||||
collateralReleaseLevel: delta.collateralReleaseLevel,
|
||||
marginFactor: delta.marginFactor,
|
||||
marginMode: delta.marginMode,
|
||||
orderMarginLevel: delta.orderMarginLevel,
|
||||
};
|
||||
if (index !== -1) {
|
||||
const currNode = draft[index];
|
||||
draft[index] = {
|
||||
...currNode,
|
||||
...deltaData,
|
||||
maintenanceLevel: delta.maintenanceLevel,
|
||||
searchLevel: delta.searchLevel,
|
||||
initialLevel: delta.initialLevel,
|
||||
collateralReleaseLevel: delta.collateralReleaseLevel,
|
||||
};
|
||||
} else {
|
||||
draft.unshift({
|
||||
@@ -42,7 +36,10 @@ const update = (
|
||||
__typename: 'Market',
|
||||
id: delta.marketId,
|
||||
},
|
||||
...deltaData,
|
||||
maintenanceLevel: delta.maintenanceLevel,
|
||||
searchLevel: delta.searchLevel,
|
||||
initialLevel: delta.initialLevel,
|
||||
collateralReleaseLevel: delta.collateralReleaseLevel,
|
||||
asset: {
|
||||
__typename: 'Asset',
|
||||
id: delta.asset,
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
import { act, render, screen } from '@testing-library/react';
|
||||
import type { MarginFieldsFragment } from './__generated__/Margins';
|
||||
import type { AssetFieldsFragment } from '@vegaprotocol/assets';
|
||||
import { MarginMode } from '@vegaprotocol/types';
|
||||
|
||||
const asset: AssetFieldsFragment = {
|
||||
id: 'assetId',
|
||||
@@ -19,9 +18,6 @@ const margins: MarginFieldsFragment = {
|
||||
initialLevel: '800',
|
||||
searchLevel: '600',
|
||||
maintenanceLevel: '400',
|
||||
marginFactor: '',
|
||||
marginMode: MarginMode.MARGIN_MODE_CROSS_MARGIN,
|
||||
orderMarginLevel: '',
|
||||
market: {
|
||||
id: 'marketId',
|
||||
},
|
||||
|
||||
@@ -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/)
|
||||
);
|
||||
|
||||
@@ -13,7 +13,6 @@ import { AsyncRendererInline } from '@vegaprotocol/ui-toolkit';
|
||||
import { DealTicket } from './deal-ticket';
|
||||
import { useFeatureFlags } from '@vegaprotocol/environment';
|
||||
import { useT } from '../../use-t';
|
||||
import { MarginModeSelector } from './margin-mode-selector';
|
||||
|
||||
interface DealTicketContainerProps {
|
||||
marketId: string;
|
||||
@@ -52,31 +51,21 @@ export const DealTicketContainer = ({
|
||||
reload={reload}
|
||||
>
|
||||
{market && marketData ? (
|
||||
<>
|
||||
{featureFlags.ISOLATED_MARGIN && (
|
||||
<>
|
||||
<MarginModeSelector marketId={marketId} />
|
||||
<hr className="border-vega-clight-500 dark:border-vega-cdark-500 mb-4" />
|
||||
</>
|
||||
)}
|
||||
{featureFlags.STOP_ORDERS && showStopOrder ? (
|
||||
<StopOrder
|
||||
market={market}
|
||||
marketPrice={marketPrice}
|
||||
submit={(stopOrdersSubmission) =>
|
||||
create({ stopOrdersSubmission })
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<DealTicket
|
||||
{...props}
|
||||
market={market}
|
||||
marketPrice={marketPrice}
|
||||
marketData={marketData}
|
||||
submit={(orderSubmission) => create({ orderSubmission })}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
featureFlags.STOP_ORDERS && showStopOrder ? (
|
||||
<StopOrder
|
||||
market={market}
|
||||
marketPrice={marketPrice}
|
||||
submit={(stopOrdersSubmission) => create({ stopOrdersSubmission })}
|
||||
/>
|
||||
) : (
|
||||
<DealTicket
|
||||
{...props}
|
||||
market={market}
|
||||
marketPrice={marketPrice}
|
||||
marketData={marketData}
|
||||
submit={(orderSubmission) => create({ orderSubmission })}
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
<p>{t('Could not load market')}</p>
|
||||
)}
|
||||
|
||||
@@ -1,246 +0,0 @@
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
import {
|
||||
TradingButton as Button,
|
||||
TradingInput as Input,
|
||||
FormGroup,
|
||||
LeverageSlider,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { MarginMode, useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import * as Types from '@vegaprotocol/types';
|
||||
import {
|
||||
type VegaTransactionStore,
|
||||
useVegaTransactionStore,
|
||||
} from '@vegaprotocol/web3';
|
||||
import { Dialog } from '@vegaprotocol/ui-toolkit';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useT } from '../../use-t';
|
||||
import classnames from 'classnames';
|
||||
import { marketMarginDataProvider } from '@vegaprotocol/accounts';
|
||||
import { useMaxLeverage } from '@vegaprotocol/positions';
|
||||
|
||||
const defaultLeverage = 10;
|
||||
interface MarginDialogProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
marketId: string;
|
||||
partyId: string;
|
||||
create: VegaTransactionStore['create'];
|
||||
}
|
||||
|
||||
const CrossMarginModeDialog = ({
|
||||
open,
|
||||
onClose,
|
||||
marketId,
|
||||
create,
|
||||
}: MarginDialogProps) => {
|
||||
const t = useT();
|
||||
return (
|
||||
<Dialog
|
||||
title={t('Cross margin')}
|
||||
size="small"
|
||||
open={open}
|
||||
onChange={(isOpen) => {
|
||||
if (!isOpen) {
|
||||
onClose();
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div className="text-sm mb-4">
|
||||
<p className="mb-1">
|
||||
{t('You are setting this market to cross-margin mode.')}
|
||||
</p>
|
||||
<p className="mb-1">
|
||||
{t(
|
||||
'Your max leverage on each position will be determined by the risk model of the market.'
|
||||
)}
|
||||
</p>
|
||||
<p>
|
||||
{t(
|
||||
'All available funds in your general account will be used to finance your margin if the market moves against you.'
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
className="w-full"
|
||||
onClick={() => {
|
||||
create({
|
||||
updateMarginMode: {
|
||||
market_id: marketId,
|
||||
mode: MarginMode.MARGIN_MODE_CROSS_MARGIN,
|
||||
},
|
||||
});
|
||||
onClose();
|
||||
}}
|
||||
>
|
||||
{t('Confirm')}
|
||||
</Button>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
const IsolatedMarginModeDialog = ({
|
||||
open,
|
||||
onClose,
|
||||
marketId,
|
||||
partyId,
|
||||
marginFactor,
|
||||
create,
|
||||
}: MarginDialogProps & { marginFactor: string }) => {
|
||||
const [leverage, setLeverage] = useState(
|
||||
Number((1 / Number(marginFactor)).toFixed(1))
|
||||
);
|
||||
const { data: maxLeverage } = useMaxLeverage(marketId, partyId);
|
||||
const max = Math.floor((maxLeverage || 1) * 10) / 10;
|
||||
useEffect(() => {
|
||||
setLeverage(Number((1 / Number(marginFactor)).toFixed(1)));
|
||||
}, [marginFactor]);
|
||||
useEffect(() => {
|
||||
if (maxLeverage && leverage > max) {
|
||||
setLeverage(max);
|
||||
}
|
||||
}, [max, maxLeverage, leverage]);
|
||||
|
||||
const t = useT();
|
||||
return (
|
||||
<Dialog
|
||||
title={t('Isolated margin')}
|
||||
size="small"
|
||||
open={open}
|
||||
onChange={(isOpen) => {
|
||||
if (!isOpen) {
|
||||
onClose();
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div className="text-sm mb-4">
|
||||
<p className="mb-1">
|
||||
{t('You are setting this market to isolated margin mode.')}
|
||||
</p>
|
||||
<p className="mb-1">
|
||||
{t(
|
||||
'Set the leverage you want below. The maximum leverage you can take is determined by the risk model of the market.'
|
||||
)}
|
||||
</p>
|
||||
<p className="mb-1">
|
||||
{t(
|
||||
'Only your allocated margin will be used to fund this position, and if the maintenance margin is breached you will be closed out.'
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<form
|
||||
onSubmit={() => {
|
||||
create({
|
||||
updateMarginMode: {
|
||||
market_id: marketId,
|
||||
mode: MarginMode.MARGIN_MODE_ISOLATED_MARGIN,
|
||||
marginFactor: `${1 / leverage}`,
|
||||
},
|
||||
});
|
||||
onClose();
|
||||
}}
|
||||
>
|
||||
<FormGroup label={t('Leverage')} labelFor="leverage-input" compact>
|
||||
<div className="mb-2">
|
||||
<LeverageSlider
|
||||
max={max}
|
||||
step={0.1}
|
||||
value={[leverage]}
|
||||
onValueChange={([value]) => setLeverage(value)}
|
||||
/>
|
||||
</div>
|
||||
<Input
|
||||
type="number"
|
||||
id="leverage-input"
|
||||
min={1}
|
||||
max={max}
|
||||
step={0.1}
|
||||
value={leverage}
|
||||
onChange={(e) => setLeverage(Number(e.target.value))}
|
||||
/>
|
||||
</FormGroup>
|
||||
<Button className="w-full" type="submit">
|
||||
{t('Confirm')}
|
||||
</Button>
|
||||
</form>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export const MarginModeSelector = ({ marketId }: { marketId: string }) => {
|
||||
const t = useT();
|
||||
const [dialog, setDialog] = useState<'cross' | 'isolated' | ''>();
|
||||
const { pubKey: partyId, isReadOnly } = useVegaWallet();
|
||||
const { data: margin } = useDataProvider({
|
||||
dataProvider: marketMarginDataProvider,
|
||||
variables: {
|
||||
partyId: partyId || '',
|
||||
marketId,
|
||||
},
|
||||
skip: !partyId,
|
||||
});
|
||||
useEffect(() => {
|
||||
if (!partyId) {
|
||||
setDialog('');
|
||||
}
|
||||
}, [partyId]);
|
||||
const create = useVegaTransactionStore((state) => state.create);
|
||||
const marginMode = margin?.marginMode;
|
||||
const marginFactor =
|
||||
margin?.marginFactor && margin?.marginFactor !== '0'
|
||||
? margin?.marginFactor
|
||||
: undefined;
|
||||
const disabled = isReadOnly;
|
||||
const onClose = () => setDialog(undefined);
|
||||
const enabledModeClassName = 'bg-vega-clight-500 dark:bg-vega-cdark-500';
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="mb-4 grid h-8 leading-8 font-alpha text-xs grid-cols-2">
|
||||
<button
|
||||
disabled={disabled}
|
||||
onClick={() => partyId && setDialog('cross')}
|
||||
className={classnames('rounded', {
|
||||
[enabledModeClassName]:
|
||||
!marginMode ||
|
||||
marginMode === Types.MarginMode.MARGIN_MODE_CROSS_MARGIN,
|
||||
})}
|
||||
>
|
||||
{t('Cross')}
|
||||
</button>
|
||||
<button
|
||||
disabled={disabled}
|
||||
onClick={() => partyId && setDialog('isolated')}
|
||||
className={classnames('rounded', {
|
||||
[enabledModeClassName]:
|
||||
marginMode === Types.MarginMode.MARGIN_MODE_ISOLATED_MARGIN,
|
||||
})}
|
||||
>
|
||||
{t('Isolated {{leverage}}x', {
|
||||
leverage: marginFactor
|
||||
? (1 / Number(marginFactor)).toFixed(1)
|
||||
: defaultLeverage,
|
||||
})}
|
||||
</button>
|
||||
</div>
|
||||
{partyId && (
|
||||
<CrossMarginModeDialog
|
||||
partyId={partyId}
|
||||
open={dialog === 'cross'}
|
||||
onClose={onClose}
|
||||
marketId={marketId}
|
||||
create={create}
|
||||
/>
|
||||
)}
|
||||
{partyId && (
|
||||
<IsolatedMarginModeDialog
|
||||
partyId={partyId}
|
||||
open={dialog === 'isolated'}
|
||||
onClose={onClose}
|
||||
marketId={marketId}
|
||||
create={create}
|
||||
marginFactor={marginFactor || `${1 / defaultLeverage}`}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -323,9 +323,6 @@ export const compileFeatureFlags = (refresh = false): FeatureFlags => {
|
||||
STOP_ORDERS: TRUTHY.includes(
|
||||
windowOrDefault('NX_STOP_ORDERS', process.env['NX_STOP_ORDERS']) as string
|
||||
),
|
||||
ISOLATED_MARGIN: TRUTHY.includes(
|
||||
windowOrDefault('NX_STOP_ORDERS', process.env['NX_STOP_ORDERS']) as string
|
||||
),
|
||||
SUCCESSOR_MARKETS: TRUTHY.includes(
|
||||
windowOrDefault(
|
||||
'NX_SUCCESSOR_MARKETS',
|
||||
|
||||
@@ -19,7 +19,6 @@ export type FeatureFlags = z.infer<typeof featureFlagsSchema>;
|
||||
export type CosmicElevatorFlags = Pick<
|
||||
FeatureFlags,
|
||||
| 'ICEBERG_ORDERS'
|
||||
| 'ISOLATED_MARGIN'
|
||||
| 'STOP_ORDERS'
|
||||
| 'SUCCESSOR_MARKETS'
|
||||
| 'PRODUCT_PERPETUALS'
|
||||
|
||||
@@ -76,7 +76,6 @@ export const envSchema = z
|
||||
const COSMIC_ELEVATOR_FLAGS = {
|
||||
SUCCESSOR_MARKETS: z.optional(z.boolean()),
|
||||
STOP_ORDERS: z.optional(z.boolean()),
|
||||
ISOLATED_MARGIN: z.optional(z.boolean()),
|
||||
ICEBERG_ORDERS: z.optional(z.boolean()),
|
||||
PRODUCT_PERPETUALS: z.optional(z.boolean()),
|
||||
METAMASK_SNAPS: z.optional(z.boolean()),
|
||||
|
||||
@@ -8,17 +8,13 @@
|
||||
"A release candidate for the staging environment": "A release candidate for the staging environment",
|
||||
"above": "above",
|
||||
"Advanced": "Advanced",
|
||||
"All available funds in your general account will be used to finance your margin if the market moves against you.": "All available funds in your general account will be used to finance your margin if the market moves against you.",
|
||||
"An estimate of the most you would be expected to pay in fees, in the market's settlement asset {{assetSymbol}}. Fees estimated are \"taker\" fees and will only be payable if the order trades aggressively. Rebate equal to the maker portion will be paid to the trader if the order trades passively.": "An estimate of the most you would be expected to pay in fees, in the market's settlement asset {{assetSymbol}}. Fees estimated are \"taker\" fees and will only be payable if the order trades aggressively. Rebate equal to the maker portion will be paid to the trader if the order trades passively.",
|
||||
"Any orders placed now will not trade until the auction ends": "Any orders placed now will not trade until the auction ends",
|
||||
"below": "below",
|
||||
"Cancel": "Cancel",
|
||||
"Closed": "Closed",
|
||||
"Closing on {{time}}": "Closing on {{time}}",
|
||||
"Confirm": "Confirm",
|
||||
"Could not load market": "Could not load market",
|
||||
"Cross": "Cross",
|
||||
"Cross margin": "Cross margin",
|
||||
"Current margin allocation": "Current margin allocation",
|
||||
"Custom": "Custom",
|
||||
"Deduction from collateral": "Deduction from collateral",
|
||||
@@ -39,9 +35,6 @@
|
||||
"Iceberg": "Iceberg",
|
||||
"ICEBERG_TOOLTIP": "Trade only a fraction of the order size at once. After the peak size of the order has traded, the size is reset. This is repeated until the order is cancelled, expires, or its full volume trades away. For example, an iceberg order with a size of 1000 and a peak size of 100 will effectively be split into 10 orders with a size of 100 each. Note that the full volume of the order is not hidden and is still reflected in the order book.",
|
||||
"Infrastructure fee": "Infrastructure fee",
|
||||
"Isolated {{leverage}}x": "Isolated {{leverage}}x",
|
||||
"Isolated margin": "Isolated margin",
|
||||
"Leverage": "Leverage",
|
||||
"Limit": "Limit",
|
||||
"Liquidation": "Liquidation",
|
||||
"LIQUIDATION_PRICE_ESTIMATE_TOOLTIP_TEXT": "This is an approximation for the liquidation price for that particular contract position, assuming nothing else changes, which may affect your margin and collateral balances.",
|
||||
@@ -66,7 +59,6 @@
|
||||
"OCO": "OCO",
|
||||
"One cancels another": "One cancels another",
|
||||
"Only limit orders are permitted when market is in auction": "Only limit orders are permitted when market is in auction",
|
||||
"Only your allocated margin will be used to fund this position, and if the maintenance margin is breached you will be closed out.": "Only your allocated margin will be used to fund this position, and if the maintenance margin is breached you will be closed out.",
|
||||
"Peak size": "Peak size",
|
||||
"Peak size cannot be greater than the size ({{size}})": "Peak size cannot be greater than the size ({{size}})",
|
||||
"Peak size cannot be lower than {{stepSize}}": "Peak size cannot be lower than {{stepSize}}",
|
||||
@@ -83,7 +75,6 @@
|
||||
"Public testnet run by the Vega team, often used for incentives": "Public testnet run by the Vega team, often used for incentives",
|
||||
"Reduce only": "Reduce only",
|
||||
"Referral discount": "Referral discount",
|
||||
"Set the leverage you want below. The maximum leverage you can take is determined by the risk model of the market.": "Set the leverage you want below. The maximum leverage you can take is determined by the risk model of the market.",
|
||||
"Short": "Short",
|
||||
"Size": "Size",
|
||||
"Size cannot be lower than {{sizeStep}}": "Size cannot be lower than {{sizeStep}}",
|
||||
@@ -137,8 +128,6 @@
|
||||
"VALIDATOR_TESTNET": "VALIDATOR_TESTNET",
|
||||
"Volume discount": "Volume discount",
|
||||
"When the order trades and its size falls below this threshold, it will be reset to the peak size and moved to the back of the priority order. Must be less than or equal to peak size, and greater than 0.": "When the order trades and its size falls below this threshold, it will be reset to the peak size and moved to the back of the priority order. Must be less than or equal to peak size, and greater than 0.",
|
||||
"You are setting this market to cross-margin mode.": "You are setting this market to cross-margin mode.",
|
||||
"You are setting this market to isolated margin mode.": "You are setting this market to isolated margin mode.",
|
||||
"You have only {{amount}}.": "You have only {{amount}}.",
|
||||
"You may not have enough margin available to open this position.": "You may not have enough margin available to open this position.",
|
||||
"You need {{symbol}} in your wallet to trade in this market.": "You need {{symbol}} in your wallet to trade in this market.",
|
||||
@@ -148,6 +137,5 @@
|
||||
"You need to connect your own wallet to start trading on this market": "You need to connect your own wallet to start trading on this market",
|
||||
"You need to provide a minimum visible size": "You need to provide a minimum visible size",
|
||||
"You need to provide a peak size": "You need to provide a peak size",
|
||||
"You need to provide a size": "You need to provide a size",
|
||||
"Your max leverage on each position will be determined by the risk model of the market.": "Your max leverage on each position will be determined by the risk model of the market."
|
||||
"You need to provide a size": "You need to provide a size"
|
||||
}
|
||||
|
||||
@@ -1,17 +1,11 @@
|
||||
{
|
||||
"Best case": "Best case",
|
||||
"Cross": "Cross",
|
||||
"Close position": "Close position",
|
||||
"Entry / Mark": "Entry / Mark",
|
||||
"General account: {{balance}}": "General account: {{balance}}",
|
||||
"Isolated": "Isolated",
|
||||
"Lifetime loss socialisation deductions: {{losses}}": "Lifetime loss socialisation deductions: {{losses}}",
|
||||
"Liquidation: {{maintenanceLevel}}": "Liquidation: {{maintenanceLevel}}",
|
||||
"Maintained by network": "Maintained by network",
|
||||
"Margin / Leverage": "Margin / Leverage",
|
||||
"Margin: {{balance}}": "Margin: {{balance}}",
|
||||
"Market": "Market",
|
||||
"Order: {{balance}}": "Order: {{balance}}",
|
||||
"No positions": "No positions",
|
||||
"Profit or loss is realised whenever your position is reduced to zero and the margin is released back to your collateral balance. P&L excludes any fees paid.": "Profit or loss is realised whenever your position is reduced to zero and the margin is released back to your collateral balance. P&L excludes any fees paid.",
|
||||
"Read more about loss socialisation": "Read more about loss socialisation",
|
||||
|
||||
@@ -43,7 +43,6 @@
|
||||
"Go to your Ethereum wallet and connect to the network {{networkName}}": "Go to your Ethereum wallet and connect to the network {{networkName}}",
|
||||
"If the network is reset or has an outage, records of your withdrawal may be lost. It is recommended that you save these details in a safe place so you can still complete your withdrawal.": "If the network is reset or has an outage, records of your withdrawal may be lost. It is recommended that you save these details in a safe place so you can still complete your withdrawal.",
|
||||
"Invalid asset source: {{source}}": "Invalid asset source: {{source}}",
|
||||
"Isolated margin mode, leverage: {{leverage}}x": "Isolated margin mode, leverage: {{leverage}}x",
|
||||
"Loading": "Loading",
|
||||
"MetaMask": "MetaMask",
|
||||
"MetaMask, Brave or other injected web wallet": "MetaMask, Brave or other injected web wallet",
|
||||
@@ -80,7 +79,6 @@
|
||||
"Transfer": "Transfer",
|
||||
"Transfer complete": "Transfer complete",
|
||||
"Unknown": "Unknown",
|
||||
"Update margin mode": "Update margin mode",
|
||||
"Vega confirmation": "Vega confirmation",
|
||||
"Vega is confirming your transaction...": "Vega is confirming your transaction...",
|
||||
"Verifying withdrawal approval": "Verifying withdrawal approval",
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
|
||||
|
||||
@@ -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<
|
||||
|
||||
@@ -174,13 +174,13 @@ const marketsData = [
|
||||
describe('getMetrics && rejoinPositionData', () => {
|
||||
it('returns positions metrics', () => {
|
||||
const positionsRejoined = rejoinPositionData(positions, marketsData);
|
||||
const metrics = getMetrics(positionsRejoined, accounts || null, null);
|
||||
const metrics = getMetrics(positionsRejoined, accounts || null);
|
||||
expect(metrics.length).toEqual(2);
|
||||
});
|
||||
|
||||
it('calculates metrics', () => {
|
||||
const positionsRejoined = rejoinPositionData(positions, marketsData);
|
||||
const metrics = getMetrics(positionsRejoined, accounts || null, null);
|
||||
const metrics = getMetrics(positionsRejoined, accounts || null);
|
||||
|
||||
expect(metrics[0].assetSymbol).toEqual('tDAI');
|
||||
expect(metrics[0].averageEntryPrice).toEqual('8993727');
|
||||
|
||||
@@ -1,26 +1,19 @@
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import produce from 'immer';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import sortBy from 'lodash/sortBy';
|
||||
import {
|
||||
marginsDataProvider,
|
||||
type Account,
|
||||
type MarginFieldsFragment,
|
||||
marketMarginDataProvider,
|
||||
} from '@vegaprotocol/accounts';
|
||||
import { type Account } from '@vegaprotocol/accounts';
|
||||
import { accountsDataProvider } from '@vegaprotocol/accounts';
|
||||
import { toBigNum, removePaginationWrapper } from '@vegaprotocol/utils';
|
||||
import {
|
||||
makeDataProvider,
|
||||
makeDerivedDataProvider,
|
||||
useDataProvider,
|
||||
} from '@vegaprotocol/data-provider';
|
||||
import {
|
||||
type MarketMaybeWithData,
|
||||
type MarketDataQueryVariables,
|
||||
allMarketsWithLiveDataProvider,
|
||||
getAsset,
|
||||
marketInfoProvider,
|
||||
type MarketInfo,
|
||||
} from '@vegaprotocol/markets';
|
||||
import {
|
||||
PositionsDocument,
|
||||
@@ -33,7 +26,6 @@ import {
|
||||
} from './__generated__/Positions';
|
||||
import {
|
||||
AccountType,
|
||||
MarginMode,
|
||||
MarketState,
|
||||
type MarketTradingMode,
|
||||
type PositionStatus,
|
||||
@@ -41,8 +33,6 @@ import {
|
||||
} from '@vegaprotocol/types';
|
||||
|
||||
export interface Position {
|
||||
marginMode: MarginFieldsFragment['marginMode'];
|
||||
maintenanceLevel: MarginFieldsFragment['maintenanceLevel'] | undefined;
|
||||
assetId: string;
|
||||
assetSymbol: string;
|
||||
averageEntryPrice: string;
|
||||
@@ -51,8 +41,6 @@ export interface Position {
|
||||
quantum: string;
|
||||
lossSocializationAmount: string;
|
||||
marginAccountBalance: string;
|
||||
orderAccountBalance: string;
|
||||
generalAccountBalance: string;
|
||||
marketDecimalPlaces: number;
|
||||
marketId: string;
|
||||
marketCode: string;
|
||||
@@ -73,8 +61,7 @@ export interface Position {
|
||||
|
||||
export const getMetrics = (
|
||||
data: ReturnType<typeof rejoinPositionData> | null,
|
||||
accounts: Account[] | null,
|
||||
margins: MarginFieldsFragment[] | null
|
||||
accounts: Account[] | null
|
||||
): Position[] => {
|
||||
if (!data || !data?.length) {
|
||||
return [];
|
||||
@@ -88,20 +75,8 @@ export const getMetrics = (
|
||||
}
|
||||
|
||||
const marketData = market?.data;
|
||||
const margin = margins?.find((margin) => {
|
||||
return margin.market?.id === market?.id;
|
||||
});
|
||||
const marginAccount = accounts?.find((account) => {
|
||||
return (
|
||||
account.market?.id === market?.id &&
|
||||
account.type === AccountType.ACCOUNT_TYPE_MARGIN
|
||||
);
|
||||
});
|
||||
const orderAccount = accounts?.find((account) => {
|
||||
return (
|
||||
account.market?.id === market?.id &&
|
||||
account.type === AccountType.ACCOUNT_TYPE_ORDER_MARGIN
|
||||
);
|
||||
return account.market?.id === market?.id;
|
||||
});
|
||||
const asset = getAsset(market);
|
||||
const generalAccount = accounts?.find(
|
||||
@@ -118,10 +93,6 @@ export const getMetrics = (
|
||||
marginAccount?.balance ?? 0,
|
||||
asset.decimals
|
||||
);
|
||||
const orderAccountBalance = toBigNum(
|
||||
orderAccount?.balance ?? 0,
|
||||
asset.decimals
|
||||
);
|
||||
const generalAccountBalance = toBigNum(
|
||||
generalAccount?.balance ?? 0,
|
||||
asset.decimals
|
||||
@@ -136,33 +107,21 @@ export const getMetrics = (
|
||||
: openVolume.multipliedBy(-1)
|
||||
).multipliedBy(markPrice)
|
||||
: undefined;
|
||||
const totalBalance = marginAccountBalance
|
||||
.plus(generalAccountBalance)
|
||||
.plus(orderAccountBalance);
|
||||
const marginMode =
|
||||
margin?.marginMode || MarginMode.MARGIN_MODE_CROSS_MARGIN;
|
||||
const marginFactor = margin?.marginFactor;
|
||||
const currentLeverage =
|
||||
marginMode === MarginMode.MARGIN_MODE_ISOLATED_MARGIN
|
||||
? (marginFactor && 1 / Number(marginFactor)) || undefined
|
||||
: notional
|
||||
? totalBalance.isEqualTo(0)
|
||||
? 0
|
||||
: notional.dividedBy(totalBalance).toNumber()
|
||||
: undefined;
|
||||
const totalBalance = marginAccountBalance.plus(generalAccountBalance);
|
||||
const currentLeverage = notional
|
||||
? totalBalance.isEqualTo(0)
|
||||
? new BigNumber(0)
|
||||
: notional.dividedBy(totalBalance)
|
||||
: undefined;
|
||||
metrics.push({
|
||||
marginMode,
|
||||
maintenanceLevel: margin?.maintenanceLevel,
|
||||
assetId: asset.id,
|
||||
assetSymbol: asset.symbol,
|
||||
averageEntryPrice: position.averageEntryPrice,
|
||||
currentLeverage,
|
||||
currentLeverage: currentLeverage ? currentLeverage.toNumber() : undefined,
|
||||
assetDecimals: asset.decimals,
|
||||
quantum: asset.quantum,
|
||||
lossSocializationAmount: position.lossSocializationAmount || '0',
|
||||
marginAccountBalance: marginAccount?.balance ?? '0',
|
||||
orderAccountBalance: orderAccount?.balance ?? '0',
|
||||
generalAccountBalance: generalAccount?.balance ?? '0',
|
||||
marketDecimalPlaces,
|
||||
marketId: market.id,
|
||||
marketCode: market.tradableInstrument.instrument.code,
|
||||
@@ -332,9 +291,6 @@ export const positionsMarketsProvider = makeDerivedDataProvider<
|
||||
).sort();
|
||||
});
|
||||
|
||||
const firstOrSelf = (partyIds: string | string[]) =>
|
||||
Array.isArray(partyIds) ? partyIds[0] : partyIds;
|
||||
|
||||
export const positionsMetricsProvider = makeDerivedDataProvider<
|
||||
Position[],
|
||||
Position[],
|
||||
@@ -345,24 +301,18 @@ export const positionsMetricsProvider = makeDerivedDataProvider<
|
||||
positionsDataProvider(callback, client, { partyIds: variables.partyIds }),
|
||||
(callback, client, variables) =>
|
||||
accountsDataProvider(callback, client, {
|
||||
partyId: firstOrSelf(variables.partyIds),
|
||||
partyId: Array.isArray(variables.partyIds)
|
||||
? variables.partyIds[0]
|
||||
: variables.partyIds,
|
||||
}),
|
||||
(callback, client, variables) =>
|
||||
allMarketsWithLiveDataProvider(callback, client, {
|
||||
marketIds: variables.marketIds,
|
||||
}),
|
||||
(callback, client, variables) =>
|
||||
marginsDataProvider(callback, client, {
|
||||
partyId: firstOrSelf(variables.partyIds),
|
||||
}),
|
||||
],
|
||||
([positions, accounts, marketsData, margins], variables) => {
|
||||
([positions, accounts, marketsData], variables) => {
|
||||
const positionsData = rejoinPositionData(positions, marketsData);
|
||||
const metrics = getMetrics(
|
||||
positionsData,
|
||||
accounts as Account[] | null,
|
||||
margins
|
||||
);
|
||||
const metrics = getMetrics(positionsData, accounts as Account[] | null);
|
||||
return preparePositions(metrics, variables.showClosed);
|
||||
},
|
||||
(data, delta, previousData) =>
|
||||
@@ -373,67 +323,3 @@ export const positionsMetricsProvider = makeDerivedDataProvider<
|
||||
return !(previousRow && isEqual(previousRow, row));
|
||||
})
|
||||
);
|
||||
|
||||
export const maxLeverageProvider = makeDerivedDataProvider<
|
||||
number,
|
||||
never,
|
||||
{ partyId: string; marketId: string }
|
||||
>(
|
||||
[
|
||||
(callback, client, { marketId }) =>
|
||||
marketInfoProvider(callback, client, { marketId }),
|
||||
(callback, client, { marketId, partyId }) =>
|
||||
positionDataProvider(callback, client, { partyIds: partyId, marketId }),
|
||||
marketMarginDataProvider,
|
||||
],
|
||||
(parts) => {
|
||||
const market: MarketInfo | null = parts[0];
|
||||
const position: PositionFieldsFragment | null = parts[1];
|
||||
const margin: MarginFieldsFragment | null = parts[2];
|
||||
if (!market || !market?.riskFactors) {
|
||||
return 1;
|
||||
}
|
||||
const maxLeverage =
|
||||
1 /
|
||||
(Math.max(
|
||||
Number(market.riskFactors.long),
|
||||
Number(market.riskFactors.short)
|
||||
) || 1);
|
||||
|
||||
if (
|
||||
market &&
|
||||
position?.openVolume &&
|
||||
position?.openVolume !== '0' &&
|
||||
margin
|
||||
) {
|
||||
const asset = getAsset(market);
|
||||
const { positionDecimalPlaces, decimalPlaces: marketDecimalPlaces } =
|
||||
market;
|
||||
const openVolume = toBigNum(
|
||||
position.openVolume.replace(/^-/, ''),
|
||||
positionDecimalPlaces
|
||||
);
|
||||
const averageEntryPrice = toBigNum(
|
||||
position.averageEntryPrice,
|
||||
marketDecimalPlaces
|
||||
);
|
||||
// https://github.com/vegaprotocol/specs/blob/nebula/protocol/0019-MCAL-margin_calculator.md#isolated-margin-mode
|
||||
return Math.min(
|
||||
averageEntryPrice
|
||||
.multipliedBy(openVolume)
|
||||
.dividedBy(toBigNum(margin.initialLevel, asset.decimals))
|
||||
.toNumber(),
|
||||
maxLeverage
|
||||
);
|
||||
}
|
||||
return maxLeverage;
|
||||
}
|
||||
);
|
||||
|
||||
export const useMaxLeverage = (marketId: string, partyId?: string) => {
|
||||
return useDataProvider({
|
||||
dataProvider: maxLeverageProvider,
|
||||
variables: { marketId, partyId: partyId || '' },
|
||||
skip: !partyId,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -21,7 +21,6 @@ import {
|
||||
VegaIcon,
|
||||
VegaIconNames,
|
||||
Tooltip,
|
||||
Lozenge,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
volumePrefix,
|
||||
@@ -32,17 +31,14 @@ import {
|
||||
} from '@vegaprotocol/utils';
|
||||
import { type Position } from './positions-data-providers';
|
||||
import {
|
||||
MarginMode,
|
||||
MarketTradingMode,
|
||||
PositionStatus,
|
||||
PositionStatusMapping,
|
||||
} from '@vegaprotocol/types';
|
||||
import { DocsLinks, useFeatureFlags } from '@vegaprotocol/environment';
|
||||
import { DocsLinks } from '@vegaprotocol/environment';
|
||||
import { PositionActionsDropdown } from './position-actions-dropdown';
|
||||
import { LiquidationPrice } from './liquidation-price';
|
||||
import { useT } from '../use-t';
|
||||
import classnames from 'classnames';
|
||||
import BigNumber from 'bignumber.js';
|
||||
|
||||
interface Props extends TypedDataAgGrid<Position> {
|
||||
onClose?: (data: Position) => void;
|
||||
@@ -78,126 +74,6 @@ const defaultColDef = {
|
||||
minWidth: 110,
|
||||
};
|
||||
|
||||
interface MarginChartProps {
|
||||
width?: number;
|
||||
label: string;
|
||||
other?: string;
|
||||
marker?: number;
|
||||
markerLabel?: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const MarginChart = ({
|
||||
width,
|
||||
label,
|
||||
other,
|
||||
marker,
|
||||
markerLabel,
|
||||
className,
|
||||
}: MarginChartProps) => {
|
||||
return (
|
||||
<div className={classnames('relative min-w-[208px]', className)}>
|
||||
{markerLabel ? (
|
||||
<div className="mb-1 whitespace-nowrap">{markerLabel}</div>
|
||||
) : null}
|
||||
<div
|
||||
className={classnames('flex relative h-2', {
|
||||
'dark:bg-vega-clight-800 bg-vega-cdark-800': other,
|
||||
})}
|
||||
>
|
||||
<div
|
||||
style={{ width: `${width || 100}%` }}
|
||||
className="dark:bg-vega-clight-400 bg-vega-cdark-400"
|
||||
></div>
|
||||
{marker ? (
|
||||
<div
|
||||
className="absolute dark:border-t-vega-clight-400 border-t-vega-cdark-400 border-l-transparent border-r-transparent"
|
||||
style={{
|
||||
top: '-5px',
|
||||
left: `${marker}%`,
|
||||
borderWidth: '5px 5px 0px 5px',
|
||||
transform: 'translateX(-5px)',
|
||||
display: 'inline-block',
|
||||
}}
|
||||
></div>
|
||||
) : null}
|
||||
</div>
|
||||
<div className="flex flex-wrap justify-between whitespace-nowrap">
|
||||
<div className={classnames({ 'mr-1': other })}>{label}</div>
|
||||
{other ? <div className="text-right">{other}</div> : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const PositionMargin = ({ data }: { data: Position }) => {
|
||||
const t = useT();
|
||||
const max =
|
||||
data.marginMode === MarginMode.MARGIN_MODE_CROSS_MARGIN
|
||||
? (
|
||||
BigInt(data.marginAccountBalance) + BigInt(data.generalAccountBalance)
|
||||
).toString()
|
||||
: BigInt(data.marginAccountBalance) > BigInt(data.orderAccountBalance)
|
||||
? data.marginAccountBalance
|
||||
: data.orderAccountBalance;
|
||||
const getWidth = (balance: string) =>
|
||||
BigNumber(balance).multipliedBy(100).dividedBy(max).toNumber();
|
||||
const inCrossMode = data.marginMode === MarginMode.MARGIN_MODE_CROSS_MARGIN;
|
||||
const hasOrderAccountBalance =
|
||||
!inCrossMode && data.orderAccountBalance !== '0';
|
||||
|
||||
return (
|
||||
<>
|
||||
<MarginChart
|
||||
width={inCrossMode ? getWidth(data.marginAccountBalance) : undefined}
|
||||
label={t('Margin: {{balance}}', {
|
||||
balance: addDecimalsFormatNumberQuantum(
|
||||
data.marginAccountBalance,
|
||||
data.assetDecimals,
|
||||
data.quantum
|
||||
),
|
||||
})}
|
||||
other={
|
||||
inCrossMode
|
||||
? t('General account: {{balance}}', {
|
||||
balance: addDecimalsFormatNumberQuantum(
|
||||
data.generalAccountBalance,
|
||||
data.assetDecimals,
|
||||
data.quantum
|
||||
),
|
||||
})
|
||||
: undefined
|
||||
}
|
||||
className={classnames({ 'mb-2': hasOrderAccountBalance })}
|
||||
marker={
|
||||
data.maintenanceLevel ? getWidth(data.maintenanceLevel) : undefined
|
||||
}
|
||||
markerLabel={
|
||||
data.maintenanceLevel &&
|
||||
t('Liquidation: {{maintenanceLevel}}', {
|
||||
maintenanceLevel: addDecimalsFormatNumberQuantum(
|
||||
data.maintenanceLevel,
|
||||
data.assetDecimals,
|
||||
data.quantum
|
||||
),
|
||||
})
|
||||
}
|
||||
/>
|
||||
{hasOrderAccountBalance ? (
|
||||
<MarginChart
|
||||
width={getWidth(data.orderAccountBalance)}
|
||||
label={t('Order: {{balance}}', {
|
||||
balance: addDecimalsFormatNumber(
|
||||
data.orderAccountBalance,
|
||||
data.assetDecimals
|
||||
),
|
||||
})}
|
||||
/>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const PositionsTable = ({
|
||||
onClose,
|
||||
onMarketClick,
|
||||
@@ -207,7 +83,6 @@ export const PositionsTable = ({
|
||||
pubKey,
|
||||
...props
|
||||
}: Props) => {
|
||||
const featureFlags = useFeatureFlags((state) => state.flags);
|
||||
const t = useT();
|
||||
|
||||
const colDefs = useMemo<ColDef[]>(() => {
|
||||
@@ -257,8 +132,7 @@ export const PositionsTable = ({
|
||||
cellClass: 'font-mono text-right',
|
||||
cellClassRules: signedNumberCssClassRules,
|
||||
filter: 'agNumberColumnFilter',
|
||||
sortable: false,
|
||||
filterValueGetter: ({ data }: { data: Position }) => {
|
||||
valueGetter: ({ data }: { data: Position }) => {
|
||||
return data?.openVolume === undefined
|
||||
? undefined
|
||||
: toBigNum(data?.openVolume, data.positionDecimalPlaces).toNumber();
|
||||
@@ -335,8 +209,7 @@ export const PositionsTable = ({
|
||||
type: 'rightAligned',
|
||||
cellClass: 'font-mono text-right',
|
||||
filter: 'agNumberColumnFilter',
|
||||
sortable: false,
|
||||
filterValueGetter: ({ data }: VegaValueGetterParams<Position>) => {
|
||||
valueGetter: ({ data }: VegaValueGetterParams<Position>) => {
|
||||
return !data
|
||||
? undefined
|
||||
: toBigNum(
|
||||
@@ -360,35 +233,7 @@ export const PositionsTable = ({
|
||||
|
||||
const lev = data?.currentLeverage ? data.currentLeverage : 1;
|
||||
const leverage = formatNumber(Math.max(1, lev), 1);
|
||||
return (
|
||||
<Tooltip
|
||||
description={
|
||||
data &&
|
||||
data.marginAccountBalance !== '0' && (
|
||||
<PositionMargin data={data} />
|
||||
)
|
||||
}
|
||||
>
|
||||
<div>
|
||||
<StackedCell
|
||||
primary={margin}
|
||||
secondary={
|
||||
<>
|
||||
{featureFlags.ISOLATED_MARGIN && (
|
||||
<Lozenge className="mr-1">
|
||||
{data?.marginMode ===
|
||||
MarginMode.MARGIN_MODE_ISOLATED_MARGIN
|
||||
? t('Isolated')
|
||||
: t('Cross')}
|
||||
</Lozenge>
|
||||
)}
|
||||
{leverage}x
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
return <StackedCell primary={margin} secondary={leverage + 'x'} />;
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -561,16 +406,7 @@ export const PositionsTable = ({
|
||||
return columnDefs.filter<ColDef>(
|
||||
(colDef: ColDef | null): colDef is ColDef => colDef !== null
|
||||
);
|
||||
}, [
|
||||
isReadOnly,
|
||||
multipleKeys,
|
||||
onClose,
|
||||
onMarketClick,
|
||||
pubKey,
|
||||
pubKeys,
|
||||
t,
|
||||
featureFlags.ISOLATED_MARGIN,
|
||||
]);
|
||||
}, [isReadOnly, multipleKeys, onClose, onMarketClick, pubKey, pubKeys, t]);
|
||||
|
||||
return (
|
||||
<AgGrid
|
||||
|
||||
@@ -130,9 +130,6 @@ const marginsFields: MarginFieldsFragment[] = [
|
||||
searchLevel: '0',
|
||||
initialLevel: '0',
|
||||
collateralReleaseLevel: '0',
|
||||
marginFactor: '',
|
||||
marginMode: Schema.MarginMode.MARGIN_MODE_CROSS_MARGIN,
|
||||
orderMarginLevel: '',
|
||||
market: {
|
||||
__typename: 'Market',
|
||||
id: 'market-0',
|
||||
@@ -148,9 +145,6 @@ const marginsFields: MarginFieldsFragment[] = [
|
||||
searchLevel: '0',
|
||||
initialLevel: '0',
|
||||
collateralReleaseLevel: '0',
|
||||
marginFactor: '',
|
||||
marginMode: Schema.MarginMode.MARGIN_MODE_CROSS_MARGIN,
|
||||
orderMarginLevel: '',
|
||||
market: {
|
||||
__typename: 'Market',
|
||||
id: 'market-1',
|
||||
@@ -166,9 +160,6 @@ const marginsFields: MarginFieldsFragment[] = [
|
||||
searchLevel: '0',
|
||||
initialLevel: '0',
|
||||
collateralReleaseLevel: '0',
|
||||
marginFactor: '',
|
||||
marginMode: Schema.MarginMode.MARGIN_MODE_CROSS_MARGIN,
|
||||
orderMarginLevel: '',
|
||||
market: {
|
||||
__typename: 'Market',
|
||||
id: 'market-2',
|
||||
@@ -181,10 +172,6 @@ const marginsFields: MarginFieldsFragment[] = [
|
||||
];
|
||||
|
||||
export const singleRow: Position = {
|
||||
generalAccountBalance: '12345600',
|
||||
maintenanceLevel: '12300000',
|
||||
marginMode: Schema.MarginMode.MARGIN_MODE_CROSS_MARGIN,
|
||||
orderAccountBalance: '0',
|
||||
partyId: 'partyId',
|
||||
assetId: 'asset-id',
|
||||
assetSymbol: 'BTC',
|
||||
|
||||
@@ -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<
|
||||
|
||||
Generated
-72
@@ -113,8 +113,6 @@ export enum AccountType {
|
||||
ACCOUNT_TYPE_MARGIN = 'ACCOUNT_TYPE_MARGIN',
|
||||
/** Network treasury, per-asset treasury controlled by the network */
|
||||
ACCOUNT_TYPE_NETWORK_TREASURY = 'ACCOUNT_TYPE_NETWORK_TREASURY',
|
||||
/** Per asset market account for party in isolated margin mode */
|
||||
ACCOUNT_TYPE_ORDER_MARGIN = 'ACCOUNT_TYPE_ORDER_MARGIN',
|
||||
/** Holds pending rewards to be paid to the referrer of a party out of fees paid by the taker */
|
||||
ACCOUNT_TYPE_PENDING_FEE_REFERRAL_REWARD = 'ACCOUNT_TYPE_PENDING_FEE_REFERRAL_REWARD',
|
||||
/** PendingTransfers - a global account for the pending transfers pool */
|
||||
@@ -1988,14 +1986,8 @@ export type MarginLevels = {
|
||||
initialLevel: Scalars['String'];
|
||||
/** Minimal margin for the position to be maintained in the network (unsigned integer) */
|
||||
maintenanceLevel: Scalars['String'];
|
||||
/** Margin factor, only relevant for isolated margin mode, else 0 */
|
||||
marginFactor: Scalars['String'];
|
||||
/** Margin mode of the party, cross margin or isolated margin */
|
||||
marginMode: MarginMode;
|
||||
/** Market in which the margin is required for this party */
|
||||
market: Market;
|
||||
/** When in isolated margin, the required order margin level, otherwise, 0 */
|
||||
orderMarginLevel: Scalars['String'];
|
||||
/** The party for this margin */
|
||||
party: Party;
|
||||
/** If the margin is between maintenance and search, the network will initiate a collateral search, expressed as unsigned integer */
|
||||
@@ -2018,14 +2010,8 @@ export type MarginLevelsUpdate = {
|
||||
initialLevel: Scalars['String'];
|
||||
/** Minimal margin for the position to be maintained in the network (unsigned integer) */
|
||||
maintenanceLevel: Scalars['String'];
|
||||
/** Margin factor, only relevant for isolated margin mode, else 0 */
|
||||
marginFactor: Scalars['String'];
|
||||
/** Margin mode of the party, cross margin or isolated margin */
|
||||
marginMode: MarginMode;
|
||||
/** Market in which the margin is required for this party */
|
||||
marketId: Scalars['ID'];
|
||||
/** When in isolated margin, the required order margin level, otherwise, 0 */
|
||||
orderMarginLevel: Scalars['String'];
|
||||
/** The party for this margin */
|
||||
partyId: Scalars['ID'];
|
||||
/** If the margin is between maintenance and search, the network will initiate a collateral search (unsigned integer) */
|
||||
@@ -2034,13 +2020,6 @@ export type MarginLevelsUpdate = {
|
||||
timestamp: Scalars['Timestamp'];
|
||||
};
|
||||
|
||||
export enum MarginMode {
|
||||
/** Party is in cross margin mode */
|
||||
MARGIN_MODE_CROSS_MARGIN = 'MARGIN_MODE_CROSS_MARGIN',
|
||||
/** Party is in isolated margin mode */
|
||||
MARGIN_MODE_ISOLATED_MARGIN = 'MARGIN_MODE_ISOLATED_MARGIN'
|
||||
}
|
||||
|
||||
/** Represents a product & associated parameters that can be traded on Vega, has an associated OrderBook and Trade history */
|
||||
export type Market = {
|
||||
__typename?: 'Market';
|
||||
@@ -3139,8 +3118,6 @@ export enum OrderRejectionReason {
|
||||
ORDER_ERROR_INVALID_TIME_IN_FORCE = 'ORDER_ERROR_INVALID_TIME_IN_FORCE',
|
||||
/** Invalid type */
|
||||
ORDER_ERROR_INVALID_TYPE = 'ORDER_ERROR_INVALID_TYPE',
|
||||
/** Party has insufficient funds to cover for the order margin for the new or amended order */
|
||||
ORDER_ERROR_ISOLATED_MARGIN_CHECK_FAILED = 'ORDER_ERROR_ISOLATED_MARGIN_CHECK_FAILED',
|
||||
/** Margin check failed - not enough available margin */
|
||||
ORDER_ERROR_MARGIN_CHECK_FAILED = 'ORDER_ERROR_MARGIN_CHECK_FAILED',
|
||||
/** Market is closed */
|
||||
@@ -3161,8 +3138,6 @@ export enum OrderRejectionReason {
|
||||
ORDER_ERROR_OFFSET_MUST_BE_GREATER_THAN_ZERO = 'ORDER_ERROR_OFFSET_MUST_BE_GREATER_THAN_ZERO',
|
||||
/** Order is out of sequence */
|
||||
ORDER_ERROR_OUT_OF_SEQUENCE = 'ORDER_ERROR_OUT_OF_SEQUENCE',
|
||||
/** Pegged orders are not allowed for a party in isolated margin mode */
|
||||
ORDER_ERROR_PEGGED_ORDERS_NOT_ALLOWED_IN_ISOLATED_MARGIN_MODE = 'ORDER_ERROR_PEGGED_ORDERS_NOT_ALLOWED_IN_ISOLATED_MARGIN_MODE',
|
||||
/** A post-only order would produce an aggressive trade and thus it has been rejected */
|
||||
ORDER_ERROR_POST_ONLY_ORDER_WOULD_TRADE = 'ORDER_ERROR_POST_ONLY_ORDER_WOULD_TRADE',
|
||||
/** A reduce-ony order would not reduce the party's position and thus it has been rejected */
|
||||
@@ -3611,41 +3586,6 @@ export type PartyLockedBalance = {
|
||||
untilEpoch: Scalars['Int'];
|
||||
};
|
||||
|
||||
/** Margin mode selected for the given party and market. */
|
||||
export type PartyMarginMode = {
|
||||
__typename?: 'PartyMarginMode';
|
||||
/** Epoch at which the update happened. */
|
||||
atEpoch: Scalars['Int'];
|
||||
/** Selected margin mode. */
|
||||
marginMode: MarginMode;
|
||||
/** Margin factor for the market. Isolated mode only. */
|
||||
margin_factor?: Maybe<Scalars['String']>;
|
||||
/** Unique ID of the market. */
|
||||
marketId: Scalars['ID'];
|
||||
/** Maximum theoretical leverage for the market. Isolated mode only. */
|
||||
max_theoretical_leverage?: Maybe<Scalars['String']>;
|
||||
/** Minimum theoretical margin factor for the market. Isolated mode only. */
|
||||
min_theoretical_margin_factor?: Maybe<Scalars['String']>;
|
||||
/** Unique ID of the party. */
|
||||
partyId: Scalars['ID'];
|
||||
};
|
||||
|
||||
/** Edge type containing the deposit and cursor information returned by a PartyMarginModeConnection */
|
||||
export type PartyMarginModeEdge = {
|
||||
__typename?: 'PartyMarginModeEdge';
|
||||
cursor: Scalars['String'];
|
||||
node: PartyMarginMode;
|
||||
};
|
||||
|
||||
/** Connection type for retrieving cursor-based paginated party margin modes information */
|
||||
export type PartyMarginModesConnection = {
|
||||
__typename?: 'PartyMarginModesConnection';
|
||||
/** The party margin modes */
|
||||
edges?: Maybe<Array<Maybe<PartyMarginModeEdge>>>;
|
||||
/** The pagination information */
|
||||
pageInfo?: Maybe<PageInfo>;
|
||||
};
|
||||
|
||||
/**
|
||||
* All staking information related to a Party.
|
||||
* Contains the current recognised balance by the network and
|
||||
@@ -4498,12 +4438,6 @@ export type Query = {
|
||||
partiesConnection?: Maybe<PartyConnection>;
|
||||
/** An entity that is trading on the Vega network */
|
||||
party?: Maybe<Party>;
|
||||
/**
|
||||
* List margin modes per party per market
|
||||
*
|
||||
* Get a list of all margin modes, or for a specific market ID, or party ID.
|
||||
*/
|
||||
partyMarginModes?: Maybe<PartyMarginModesConnection>;
|
||||
/** Fetch all positions */
|
||||
positions?: Maybe<PositionConnection>;
|
||||
/** A governance proposal located by either its ID or reference. If both are set, ID is used. */
|
||||
@@ -6279,8 +6213,6 @@ export enum TransferType {
|
||||
TRANSFER_TYPE_INFRASTRUCTURE_FEE_DISTRIBUTE = 'TRANSFER_TYPE_INFRASTRUCTURE_FEE_DISTRIBUTE',
|
||||
/** Infrastructure fee paid from general account */
|
||||
TRANSFER_TYPE_INFRASTRUCTURE_FEE_PAY = 'TRANSFER_TYPE_INFRASTRUCTURE_FEE_PAY',
|
||||
/** Funds moved from order margin account to margin account. */
|
||||
TRANSFER_TYPE_ISOLATED_MARGIN_LOW = 'TRANSFER_TYPE_ISOLATED_MARGIN_LOW',
|
||||
/** Allocates liquidity fee earnings to each liquidity provider's network controlled liquidity fee account. */
|
||||
TRANSFER_TYPE_LIQUIDITY_FEE_ALLOCATE = 'TRANSFER_TYPE_LIQUIDITY_FEE_ALLOCATE',
|
||||
/** Liquidity fee received into general account */
|
||||
@@ -6307,10 +6239,6 @@ export enum TransferType {
|
||||
TRANSFER_TYPE_MTM_LOSS = 'TRANSFER_TYPE_MTM_LOSS',
|
||||
/** Funds added to margin account after mark to market gain */
|
||||
TRANSFER_TYPE_MTM_WIN = 'TRANSFER_TYPE_MTM_WIN',
|
||||
/** Funds released from order margin account to general. */
|
||||
TRANSFER_TYPE_ORDER_MARGIN_HIGH = 'TRANSFER_TYPE_ORDER_MARGIN_HIGH',
|
||||
/** Funds moved from general account to order margin account. */
|
||||
TRANSFER_TYPE_ORDER_MARGIN_LOW = 'TRANSFER_TYPE_ORDER_MARGIN_LOW',
|
||||
/** Funds deducted from margin account after a perpetuals funding loss. */
|
||||
TRANSFER_TYPE_PERPETUALS_FUNDING_LOSS = 'TRANSFER_TYPE_PERPETUALS_FUNDING_LOSS',
|
||||
/** Funds added to margin account after a perpetuals funding gain. */
|
||||
|
||||
@@ -38,7 +38,6 @@ import type { ProductType, ProposalProductType } from './product';
|
||||
export const AccountTypeMapping: {
|
||||
[T in AccountType]: string;
|
||||
} = {
|
||||
ACCOUNT_TYPE_ORDER_MARGIN: 'Per asset market account',
|
||||
ACCOUNT_TYPE_BOND: 'Bond account',
|
||||
ACCOUNT_TYPE_EXTERNAL: 'External account',
|
||||
ACCOUNT_TYPE_FEES_INFRASTRUCTURE: 'Infrastructure fees account',
|
||||
@@ -212,8 +211,6 @@ export const OrderRejectionReasonMapping: {
|
||||
ORDER_ERROR_INVALID_SIZE: 'Invalid size',
|
||||
ORDER_ERROR_INVALID_TIME_IN_FORCE: 'Invalid time in force',
|
||||
ORDER_ERROR_INVALID_TYPE: 'Invalid type',
|
||||
ORDER_ERROR_ISOLATED_MARGIN_CHECK_FAILED:
|
||||
'Party has insufficient funds to cover for the order margin for the new or amended order',
|
||||
ORDER_ERROR_MARGIN_CHECK_FAILED: 'Margin check failed',
|
||||
ORDER_ERROR_MARKET_CLOSED: 'Market closed',
|
||||
ORDER_ERROR_MISSING_GENERAL_ACCOUNT: 'Missing general account',
|
||||
@@ -224,8 +221,6 @@ export const OrderRejectionReasonMapping: {
|
||||
ORDER_ERROR_NOT_FOUND: 'Not found',
|
||||
ORDER_ERROR_OFFSET_MUST_BE_GREATER_OR_EQUAL_TO_ZERO:
|
||||
'Offset must be greater or equal to zero',
|
||||
ORDER_ERROR_PEGGED_ORDERS_NOT_ALLOWED_IN_ISOLATED_MARGIN_MODE:
|
||||
'Pegged orders are not allowed for a party in isolated margin mode',
|
||||
ORDER_ERROR_OFFSET_MUST_BE_GREATER_THAN_ZERO:
|
||||
'Offset must be greater than zero',
|
||||
ORDER_ERROR_OUT_OF_SEQUENCE: 'Out of sequence',
|
||||
@@ -480,9 +475,6 @@ export const TransferTypeMapping: TransferTypeMap = {
|
||||
TRANSFER_TYPE_WIN: 'Final settlement gain',
|
||||
TRANSFER_TYPE_MTM_LOSS: 'Mark to market loss',
|
||||
TRANSFER_TYPE_MTM_WIN: 'Mark to market gain',
|
||||
TRANSFER_TYPE_ORDER_MARGIN_HIGH: 'From order margin account to general',
|
||||
TRANSFER_TYPE_ORDER_MARGIN_LOW:
|
||||
'From general account to order margin account',
|
||||
TRANSFER_TYPE_MARGIN_LOW: 'Margin topped up',
|
||||
TRANSFER_TYPE_MARGIN_HIGH: 'Margin returned',
|
||||
TRANSFER_TYPE_MARGIN_CONFISCATED: 'Margin confiscated',
|
||||
@@ -490,8 +482,6 @@ export const TransferTypeMapping: TransferTypeMap = {
|
||||
TRANSFER_TYPE_MAKER_FEE_RECEIVE: 'Maker fee received',
|
||||
TRANSFER_TYPE_INFRASTRUCTURE_FEE_PAY: 'Infrastructure fee paid',
|
||||
TRANSFER_TYPE_INFRASTRUCTURE_FEE_DISTRIBUTE: 'Infrastructure fee distributed',
|
||||
TRANSFER_TYPE_ISOLATED_MARGIN_LOW:
|
||||
'From order margin account to margin account',
|
||||
TRANSFER_TYPE_LIQUIDITY_FEE_PAY: 'Liquidity fee paid',
|
||||
TRANSFER_TYPE_LIQUIDITY_FEE_DISTRIBUTE: 'Liquidity fee received',
|
||||
TRANSFER_TYPE_BOND_LOW: 'Bond account funded',
|
||||
@@ -525,10 +515,6 @@ export const DescriptionTransferTypeMapping: TransferTypeMap = {
|
||||
TRANSFER_TYPE_WIN: `Funds added to your general account after final settlement gain`,
|
||||
TRANSFER_TYPE_MTM_LOSS: `Funds deducted from your margin account after mark to market loss`,
|
||||
TRANSFER_TYPE_MTM_WIN: `Funds added to your margin account after mark to market gain`,
|
||||
TRANSFER_TYPE_ORDER_MARGIN_HIGH:
|
||||
'Funds released from order margin account to general',
|
||||
TRANSFER_TYPE_ORDER_MARGIN_LOW:
|
||||
'Funds moved from general account to order margin account',
|
||||
TRANSFER_TYPE_MARGIN_LOW: `Funds deducted from your general account to meet margin requirement`,
|
||||
TRANSFER_TYPE_MARGIN_HIGH: `Excess margin amount returned to your general account`,
|
||||
TRANSFER_TYPE_MARGIN_CONFISCATED: `Margin confiscated from your margin account to fulfil closeout`,
|
||||
@@ -536,8 +522,6 @@ export const DescriptionTransferTypeMapping: TransferTypeMap = {
|
||||
TRANSFER_TYPE_MAKER_FEE_RECEIVE: `Maker fee received into your general account when your passive order was filled`,
|
||||
TRANSFER_TYPE_INFRASTRUCTURE_FEE_PAY: `Infrastructure fee paid from your general account when your order was filled`,
|
||||
TRANSFER_TYPE_INFRASTRUCTURE_FEE_DISTRIBUTE: `Infrastructure fee received: Infrastructure fee, paid by traders, received into your general account`,
|
||||
TRANSFER_TYPE_ISOLATED_MARGIN_LOW:
|
||||
'Funds moved from order margin account to margin account',
|
||||
TRANSFER_TYPE_LIQUIDITY_FEE_PAY: `Liquidity fee paid from your general account to market's liquidity providers`,
|
||||
TRANSFER_TYPE_LIQUIDITY_FEE_DISTRIBUTE: `Liquidity fee received into your general account from traders`,
|
||||
TRANSFER_TYPE_BOND_LOW: `Funds deducted from your general account to meet your required liquidity bond amount`,
|
||||
|
||||
@@ -38,14 +38,14 @@ export function Dialog({
|
||||
);
|
||||
const wrapperClasses = classNames(
|
||||
// Dimensions
|
||||
'w-screen sm:max-w-[90vw] p-4 md:p-8',
|
||||
'max-w-[90vw] p-4 md:p-8',
|
||||
// Need to apply background and text colors again as content is rendered in a portal
|
||||
'dark:bg-black bg-white dark:text-white',
|
||||
getIntentBorder(intent),
|
||||
{
|
||||
'sm:w-[520px]': size === 'small',
|
||||
'sm:w-[680px]': size === 'medium',
|
||||
'sm:w-[720px] lg:w-[940px]': size === 'large',
|
||||
'w-[520px]': size === 'small',
|
||||
'w-[680px]': size === 'medium',
|
||||
'w-[720px] lg:w-[940px]': size === 'large',
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
export * from './slider';
|
||||
export * from './leverage-slider';
|
||||
|
||||
@@ -451,22 +451,7 @@ export type CreateReferralSet = {
|
||||
};
|
||||
};
|
||||
|
||||
export enum MarginMode {
|
||||
MARGIN_MODE_CROSS_MARGIN = 1,
|
||||
MARGIN_MODE_ISOLATED_MARGIN,
|
||||
}
|
||||
export interface UpdateMarginMode {
|
||||
market_id: string;
|
||||
mode: MarginMode;
|
||||
marginFactor?: string;
|
||||
}
|
||||
|
||||
export interface UpdateMarginModeBody {
|
||||
updateMarginMode: UpdateMarginMode;
|
||||
}
|
||||
|
||||
export type Transaction =
|
||||
| UpdateMarginModeBody
|
||||
| StopOrdersSubmissionBody
|
||||
| StopOrdersCancellationBody
|
||||
| OrderSubmissionBody
|
||||
@@ -483,10 +468,6 @@ export type Transaction =
|
||||
| ApplyReferralCode
|
||||
| CreateReferralSet;
|
||||
|
||||
export const isMarginModeUpdateTransaction = (
|
||||
transaction: Transaction
|
||||
): transaction is UpdateMarginModeBody => 'updateMarginMode' in transaction;
|
||||
|
||||
export const isWithdrawTransaction = (
|
||||
transaction: Transaction
|
||||
): transaction is WithdrawSubmissionBody => 'withdrawSubmission' in transaction;
|
||||
|
||||
@@ -10,7 +10,6 @@ import {
|
||||
isStopOrdersSubmissionTransaction,
|
||||
isStopOrdersCancellationTransaction,
|
||||
determineId,
|
||||
isMarginModeUpdateTransaction,
|
||||
} from '@vegaprotocol/wallet';
|
||||
|
||||
import { create } from 'zustand';
|
||||
@@ -59,7 +58,7 @@ export interface VegaTransactionStore {
|
||||
|
||||
export const useVegaTransactionStore = create<VegaTransactionStore>()(
|
||||
subscribeWithSelector((set, get) => ({
|
||||
transactions: [] as (VegaStoredTxState | undefined)[],
|
||||
transactions: [] as VegaStoredTxState[],
|
||||
create: (body: Transaction, order?: OrderTxUpdateFieldsFragment) => {
|
||||
const transactions = get().transactions;
|
||||
const now = new Date();
|
||||
@@ -206,22 +205,16 @@ export const useVegaTransactionStore = create<VegaTransactionStore>()(
|
||||
isStopOrdersCancellationTransaction(transaction.body);
|
||||
const isConfirmedStopOrderSubmission =
|
||||
isStopOrdersSubmissionTransaction(transaction.body);
|
||||
const isConfirmedMarginModeTransaction =
|
||||
isMarginModeUpdateTransaction(transaction.body);
|
||||
|
||||
if (
|
||||
isConfirmedOrderCancellation ||
|
||||
isConfirmedTransfer ||
|
||||
isConfirmedStopOrderCancellation ||
|
||||
isConfirmedStopOrderSubmission ||
|
||||
isConfirmedMarginModeTransaction
|
||||
(isConfirmedOrderCancellation ||
|
||||
isConfirmedTransfer ||
|
||||
isConfirmedStopOrderCancellation ||
|
||||
isConfirmedStopOrderSubmission) &&
|
||||
!transactionResult.error &&
|
||||
transactionResult.status
|
||||
) {
|
||||
if (transactionResult.error) {
|
||||
transaction.status = VegaTxStatus.Error;
|
||||
transaction.error = new Error(transactionResult.error);
|
||||
} else if (transactionResult.status) {
|
||||
transaction.status = VegaTxStatus.Complete;
|
||||
}
|
||||
transaction.status = VegaTxStatus.Complete;
|
||||
}
|
||||
transaction.dialogOpen = true;
|
||||
transaction.updatedAt = new Date();
|
||||
|
||||
@@ -7,7 +7,6 @@ import type {
|
||||
OrderSubmission,
|
||||
StopOrdersSubmission,
|
||||
StopOrderSetup,
|
||||
UpdateMarginMode,
|
||||
} from '@vegaprotocol/wallet';
|
||||
import type {
|
||||
OrderTxUpdateFieldsFragment,
|
||||
@@ -27,8 +26,6 @@ import {
|
||||
isStopOrdersSubmissionTransaction,
|
||||
isStopOrdersCancellationTransaction,
|
||||
isReferralRelatedTransaction,
|
||||
isMarginModeUpdateTransaction,
|
||||
MarginMode,
|
||||
} from '@vegaprotocol/wallet';
|
||||
import { useVegaTransactionStore } from './use-vega-transaction-store';
|
||||
import { VegaTxStatus } from './types';
|
||||
@@ -166,7 +163,6 @@ const isClosePositionTransaction = (tx: VegaStoredTxState) => {
|
||||
};
|
||||
|
||||
const isTransactionTypeSupported = (tx: VegaStoredTxState) => {
|
||||
const marginModeUpdate = isMarginModeUpdateTransaction(tx.body);
|
||||
const withdraw = isWithdrawTransaction(tx.body);
|
||||
const submitOrder = isOrderSubmissionTransaction(tx.body);
|
||||
const cancelOrder = isOrderCancellationTransaction(tx.body);
|
||||
@@ -177,7 +173,6 @@ const isTransactionTypeSupported = (tx: VegaStoredTxState) => {
|
||||
const transfer = isTransferTransaction(tx.body);
|
||||
const referral = isReferralRelatedTransaction(tx.body);
|
||||
return (
|
||||
marginModeUpdate ||
|
||||
withdraw ||
|
||||
submitOrder ||
|
||||
cancelOrder ||
|
||||
@@ -450,27 +445,6 @@ const CancelOrderDetails = ({
|
||||
);
|
||||
};
|
||||
|
||||
const MarginModeDetails = ({ data }: { data: UpdateMarginMode }) => {
|
||||
const t = useT();
|
||||
const { data: markets } = useMarketsMapProvider();
|
||||
const marketId = data.market_id;
|
||||
const market = marketId && markets?.[marketId];
|
||||
if (!market) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<Panel>
|
||||
<h4>{t('Update margin mode')}</h4>
|
||||
<p>{market?.tradableInstrument.instrument.code}</p>
|
||||
{data.mode === MarginMode.MARGIN_MODE_CROSS_MARGIN
|
||||
? t('Cross margin mode')
|
||||
: t('Isolated margin mode, leverage: {{leverage}}x', {
|
||||
leverage: (1 / Number(data.marginFactor)).toFixed(1),
|
||||
})}
|
||||
</Panel>
|
||||
);
|
||||
};
|
||||
|
||||
const CancelStopOrderDetails = ({ stopOrderId }: { stopOrderId: string }) => {
|
||||
const t = useT();
|
||||
const formatTrigger = useFormatTrigger();
|
||||
@@ -624,10 +598,6 @@ export const VegaTransactionDetails = ({ tx }: { tx: VegaStoredTxState }) => {
|
||||
);
|
||||
}
|
||||
|
||||
if (isMarginModeUpdateTransaction(tx.body)) {
|
||||
return <MarginModeDetails data={tx.body.updateMarginMode} />;
|
||||
}
|
||||
|
||||
if (isClosePositionTransaction(tx)) {
|
||||
const transaction = tx.body as BatchMarketInstructionSubmissionBody;
|
||||
const marketId = first(
|
||||
|
||||
Reference in New Issue
Block a user