Revert "feat(trading): margin mode selector (#5575)"
This reverts commit fde77ebccb
.
This commit is contained in:
parent
fde77ebccb
commit
f22a3bc2d2
@ -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
|
||||
|
4
apps/trading/e2e/poetry.lock
generated
4
apps/trading/e2e/poetry.lock
generated
@ -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")
|
@ -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()
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
12
libs/accounts/src/lib/__generated__/Margins.ts
generated
12
libs/accounts/src/lib/__generated__/Margins.ts
generated
@ -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 {
|
||||
@ -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',
|
||||
},
|
||||
|
@ -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",
|
||||
|
@ -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',
|
||||
|
72
libs/types/src/__generated__/types.ts
generated
72
libs/types/src/__generated__/types.ts
generated
@ -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`,
|
||||
|
@ -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(
|
||||
|
Loading…
Reference in New Issue
Block a user