feat(trading): use custom toast content for stop order related transactions (#4476)

This commit is contained in:
Bartłomiej Głownia 2023-08-09 14:47:10 +02:00 committed by GitHub
parent 9cc8f5a377
commit 26d5a67604
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 350 additions and 79 deletions

View File

@ -150,3 +150,9 @@ query StopOrders($partyId: ID!) {
} }
} }
} }
query StopOrderById($stopOrderId: ID!) {
stopOrder(id: $stopOrderId) {
...StopOrderFields
}
}

View File

@ -32,7 +32,7 @@ export type OrdersUpdateSubscriptionVariables = Types.Exact<{
export type OrdersUpdateSubscription = { __typename?: 'Subscription', orders?: Array<{ __typename?: 'OrderUpdate', id: string, marketId: string, type?: Types.OrderType | null, side: Types.Side, size: string, status: Types.OrderStatus, rejectionReason?: Types.OrderRejectionReason | null, price: string, timeInForce: Types.OrderTimeInForce, remaining: string, expiresAt?: any | null, createdAt: any, updatedAt?: any | null, liquidityProvisionId?: string | null, peggedOrder?: { __typename: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null, icebergOrder?: { __typename: 'IcebergOrder', peakSize: string, minimumVisibleSize: string, reservedRemaining: string } | null }> | null }; export type OrdersUpdateSubscription = { __typename?: 'Subscription', orders?: Array<{ __typename?: 'OrderUpdate', id: string, marketId: string, type?: Types.OrderType | null, side: Types.Side, size: string, status: Types.OrderStatus, rejectionReason?: Types.OrderRejectionReason | null, price: string, timeInForce: Types.OrderTimeInForce, remaining: string, expiresAt?: any | null, createdAt: any, updatedAt?: any | null, liquidityProvisionId?: string | null, peggedOrder?: { __typename: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null, icebergOrder?: { __typename: 'IcebergOrder', peakSize: string, minimumVisibleSize: string, reservedRemaining: string } | null }> | null };
export type OrderSubmissionFieldsFragment = { __typename?: 'OrderSubmission', marketId: string, price: string, size: string, side: Types.Side, timeInForce: Types.OrderTimeInForce, expiresAt: any, type: Types.OrderType, reference?: string | null, postOnly?: boolean | null, reduceOnly?: boolean | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null}; export type OrderSubmissionFieldsFragment = { __typename?: 'OrderSubmission', marketId: string, price: string, size: string, side: Types.Side, timeInForce: Types.OrderTimeInForce, expiresAt: any, type: Types.OrderType, reference?: string | null, postOnly?: boolean | null, reduceOnly?: boolean | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null };
export type StopOrderFieldsFragment = { __typename?: 'StopOrder', id: string, ocoLinkId?: string | null, expiresAt?: any | null, expiryStrategy?: Types.StopOrderExpiryStrategy | null, triggerDirection: Types.StopOrderTriggerDirection, status: Types.StopOrderStatus, createdAt: any, updatedAt?: any | null, partyId: string, marketId: string, trigger?: { __typename?: 'StopOrderPrice', price: string } | { __typename?: 'StopOrderTrailingPercentOffset', trailingPercentOffset: string } | null, submission: { __typename?: 'OrderSubmission', marketId: string, price: string, size: string, side: Types.Side, timeInForce: Types.OrderTimeInForce, expiresAt: any, type: Types.OrderType, reference?: string | null, postOnly?: boolean | null, reduceOnly?: boolean | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null } }; export type StopOrderFieldsFragment = { __typename?: 'StopOrder', id: string, ocoLinkId?: string | null, expiresAt?: any | null, expiryStrategy?: Types.StopOrderExpiryStrategy | null, triggerDirection: Types.StopOrderTriggerDirection, status: Types.StopOrderStatus, createdAt: any, updatedAt?: any | null, partyId: string, marketId: string, trigger?: { __typename?: 'StopOrderPrice', price: string } | { __typename?: 'StopOrderTrailingPercentOffset', trailingPercentOffset: string } | null, submission: { __typename?: 'OrderSubmission', marketId: string, price: string, size: string, side: Types.Side, timeInForce: Types.OrderTimeInForce, expiresAt: any, type: Types.OrderType, reference?: string | null, postOnly?: boolean | null, reduceOnly?: boolean | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null } };
@ -43,6 +43,13 @@ export type StopOrdersQueryVariables = Types.Exact<{
export type StopOrdersQuery = { __typename?: 'Query', stopOrders?: { __typename?: 'StopOrderConnection', edges?: Array<{ __typename?: 'StopOrderEdge', node?: { __typename?: 'StopOrder', id: string, ocoLinkId?: string | null, expiresAt?: any | null, expiryStrategy?: Types.StopOrderExpiryStrategy | null, triggerDirection: Types.StopOrderTriggerDirection, status: Types.StopOrderStatus, createdAt: any, updatedAt?: any | null, partyId: string, marketId: string, trigger?: { __typename?: 'StopOrderPrice', price: string } | { __typename?: 'StopOrderTrailingPercentOffset', trailingPercentOffset: string } | null, submission: { __typename?: 'OrderSubmission', marketId: string, price: string, size: string, side: Types.Side, timeInForce: Types.OrderTimeInForce, expiresAt: any, type: Types.OrderType, reference?: string | null, postOnly?: boolean | null, reduceOnly?: boolean | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null } } | null }> | null } | null }; export type StopOrdersQuery = { __typename?: 'Query', stopOrders?: { __typename?: 'StopOrderConnection', edges?: Array<{ __typename?: 'StopOrderEdge', node?: { __typename?: 'StopOrder', id: string, ocoLinkId?: string | null, expiresAt?: any | null, expiryStrategy?: Types.StopOrderExpiryStrategy | null, triggerDirection: Types.StopOrderTriggerDirection, status: Types.StopOrderStatus, createdAt: any, updatedAt?: any | null, partyId: string, marketId: string, trigger?: { __typename?: 'StopOrderPrice', price: string } | { __typename?: 'StopOrderTrailingPercentOffset', trailingPercentOffset: string } | null, submission: { __typename?: 'OrderSubmission', marketId: string, price: string, size: string, side: Types.Side, timeInForce: Types.OrderTimeInForce, expiresAt: any, type: Types.OrderType, reference?: string | null, postOnly?: boolean | null, reduceOnly?: boolean | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null } } | null }> | null } | null };
export type StopOrderByIdQueryVariables = Types.Exact<{
stopOrderId: Types.Scalars['ID'];
}>;
export type StopOrderByIdQuery = { __typename?: 'Query', stopOrder?: { __typename?: 'StopOrder', id: string, ocoLinkId?: string | null, expiresAt?: any | null, expiryStrategy?: Types.StopOrderExpiryStrategy | null, triggerDirection: Types.StopOrderTriggerDirection, status: Types.StopOrderStatus, createdAt: any, updatedAt?: any | null, partyId: string, marketId: string, trigger?: { __typename?: 'StopOrderPrice', price: string } | { __typename?: 'StopOrderTrailingPercentOffset', trailingPercentOffset: string } | null, submission: { __typename?: 'OrderSubmission', marketId: string, price: string, size: string, side: Types.Side, timeInForce: Types.OrderTimeInForce, expiresAt: any, type: Types.OrderType, reference?: string | null, postOnly?: boolean | null, reduceOnly?: boolean | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null } } | null };
export const OrderFieldsFragmentDoc = gql` export const OrderFieldsFragmentDoc = gql`
fragment OrderFields on Order { fragment OrderFields on Order {
id id
@ -309,4 +316,39 @@ export function useStopOrdersLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions
} }
export type StopOrdersQueryHookResult = ReturnType<typeof useStopOrdersQuery>; export type StopOrdersQueryHookResult = ReturnType<typeof useStopOrdersQuery>;
export type StopOrdersLazyQueryHookResult = ReturnType<typeof useStopOrdersLazyQuery>; export type StopOrdersLazyQueryHookResult = ReturnType<typeof useStopOrdersLazyQuery>;
export type StopOrdersQueryResult = Apollo.QueryResult<StopOrdersQuery, StopOrdersQueryVariables>; export type StopOrdersQueryResult = Apollo.QueryResult<StopOrdersQuery, StopOrdersQueryVariables>;
export const StopOrderByIdDocument = gql`
query StopOrderById($stopOrderId: ID!) {
stopOrder(id: $stopOrderId) {
...StopOrderFields
}
}
${StopOrderFieldsFragmentDoc}`;
/**
* __useStopOrderByIdQuery__
*
* To run a query within a React component, call `useStopOrderByIdQuery` and pass it any options that fit your needs.
* When your component renders, `useStopOrderByIdQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useStopOrderByIdQuery({
* variables: {
* stopOrderId: // value for 'stopOrderId'
* },
* });
*/
export function useStopOrderByIdQuery(baseOptions: Apollo.QueryHookOptions<StopOrderByIdQuery, StopOrderByIdQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<StopOrderByIdQuery, StopOrderByIdQueryVariables>(StopOrderByIdDocument, options);
}
export function useStopOrderByIdLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<StopOrderByIdQuery, StopOrderByIdQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<StopOrderByIdQuery, StopOrderByIdQueryVariables>(StopOrderByIdDocument, options);
}
export type StopOrderByIdQueryHookResult = ReturnType<typeof useStopOrderByIdQuery>;
export type StopOrderByIdLazyQueryHookResult = ReturnType<typeof useStopOrderByIdLazyQuery>;
export type StopOrderByIdQueryResult = Apollo.QueryResult<StopOrderByIdQuery, StopOrderByIdQueryVariables>;

View File

@ -3,6 +3,7 @@ import {
getDateTimeFormat, getDateTimeFormat,
isNumeric, isNumeric,
toBigNum, toBigNum,
formatTrigger,
} from '@vegaprotocol/utils'; } from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import * as Schema from '@vegaprotocol/types'; import * as Schema from '@vegaprotocol/types';
@ -55,29 +56,8 @@ export const StopOrdersTable = memo<
sortable: false, sortable: false,
valueFormatter: ({ valueFormatter: ({
data, data,
value, }: VegaValueFormatterParams<StopOrder, 'trigger'>): string =>
}: VegaValueFormatterParams<StopOrder, 'trigger'>): string => { data ? formatTrigger(data, data.market.decimalPlaces) : '',
if (data && value?.__typename === 'StopOrderPrice') {
return `${t('Mark')} ${
data?.triggerDirection ===
Schema.StopOrderTriggerDirection.TRIGGER_DIRECTION_FALLS_BELOW
? '<'
: '>'
} ${addDecimalsFormatNumber(
value.price,
data.market.decimalPlaces
)}`;
}
if (data && value?.__typename === 'StopOrderTrailingPercentOffset') {
return `${t('Mark')} ${
data?.triggerDirection ===
Schema.StopOrderTriggerDirection.TRIGGER_DIRECTION_FALLS_BELOW
? '+'
: '-'
}${(Number(value.trailingPercentOffset) * 100).toFixed(1)}%`;
}
return '-';
},
minWidth: 100, minWidth: 100,
}, },
{ {

View File

@ -3,3 +3,4 @@ export * from './number';
export * from './range'; export * from './range';
export * from './size'; export * from './size';
export * from './strings'; export * from './strings';
export * from './trigger';

View File

@ -0,0 +1,27 @@
import * as Schema from '@vegaprotocol/types';
import { t } from '@vegaprotocol/i18n';
import { addDecimalsFormatNumber } from './number';
export const formatTrigger = (
data: Pick<Schema.StopOrder, 'trigger' | 'triggerDirection'> | undefined,
marketDecimalPlaces: number,
defaultValue = '-'
) => {
if (data && data?.trigger?.__typename === 'StopOrderPrice') {
return `${t('Mark')} ${
data?.triggerDirection ===
Schema.StopOrderTriggerDirection.TRIGGER_DIRECTION_FALLS_BELOW
? '<'
: '>'
} ${addDecimalsFormatNumber(data.trigger.price, marketDecimalPlaces)}`;
}
if (data && data?.trigger?.__typename === 'StopOrderTrailingPercentOffset') {
return `${t('Mark')} ${
data?.triggerDirection ===
Schema.StopOrderTriggerDirection.TRIGGER_DIRECTION_FALLS_BELOW
? '+'
: '-'
}${(Number(data?.trigger.trailingPercentOffset) * 100).toFixed(1)}%`;
}
return defaultValue;
};

View File

@ -12,6 +12,7 @@ import {
getVegaTransactionContentIntent, getVegaTransactionContentIntent,
} from './use-vega-transaction-toasts'; } from './use-vega-transaction-toasts';
import { Intent } from '@vegaprotocol/ui-toolkit'; import { Intent } from '@vegaprotocol/ui-toolkit';
import type { OrderByIdQuery, StopOrderByIdQuery } from '@vegaprotocol/orders';
jest.mock('@vegaprotocol/assets', () => { jest.mock('@vegaprotocol/assets', () => {
const A1 = { const A1 = {
@ -23,7 +24,7 @@ jest.mock('@vegaprotocol/assets', () => {
}; };
return { return {
...jest.requireActual('@vegaprotocol/assets'), ...jest.requireActual('@vegaprotocol/assets'),
useAssetsDataProvider: jest.fn(() => ({ data: [A1] })), useAssetsMapProvider: jest.fn(() => ({ data: { [A1.id]: A1 } })),
}; };
}); });
@ -50,7 +51,7 @@ jest.mock('@vegaprotocol/markets', () => {
}; };
return { return {
...jest.requireActual('@vegaprotocol/markets'), ...jest.requireActual('@vegaprotocol/markets'),
useMarketList: jest.fn(() => ({ data: [M1] })), useMarketsMapProvider: jest.fn(() => ({ data: { [M1.id]: M1 } })),
}; };
}); });
@ -59,20 +60,64 @@ jest.mock('@vegaprotocol/orders', () => {
...jest.requireActual('@vegaprotocol/orders'), ...jest.requireActual('@vegaprotocol/orders'),
useOrderByIdQuery: jest.fn(({ variables: { orderId } }) => { useOrderByIdQuery: jest.fn(({ variables: { orderId } }) => {
if (orderId === '0') { if (orderId === '0') {
return { const data: OrderByIdQuery = {
data: { orderByID: {
orderByID: { id: '0',
id: '0', side: 'SIDE_BUY',
side: 'SIDE_BUY', size: '10',
size: '10', remaining: '10',
timeInForce: 'TIME_IN_FORCE_FOK', timeInForce: 'TIME_IN_FORCE_FOK',
type: 'TYPE_MARKET', type: 'TYPE_MARKET',
price: '1234', price: '1234',
createdAt: new Date(), createdAt: new Date(),
status: 'STATUS_ACTIVE', status: 'STATUS_ACTIVE',
market: { id: 'market-1' }, market: { id: 'market-1' },
},
}, },
} as OrderByIdQuery;
return {
data,
};
} else {
return { data: undefined };
}
}),
useStopOrderByIdQuery: jest.fn(({ variables: { stopOrderId } }) => {
if (stopOrderId === '0') {
const data: StopOrderByIdQuery = {
stopOrder: {
id: '0',
ocoLinkId: null,
expiresAt: null,
expiryStrategy: null,
triggerDirection: 'TRIGGER_DIRECTION_RISES_ABOVE',
status: 'STATUS_CANCELLED',
createdAt: '2023-08-03T07:12:36.325927Z',
updatedAt: null,
partyId: 'party-id',
marketId: 'market-1',
trigger: {
price: '1234',
__typename: 'StopOrderPrice',
},
submission: {
marketId: 'market-1',
price: '1234',
size: '10',
side: 'SIDE_SELL',
timeInForce: 'TIME_IN_FORCE_FOK',
expiresAt: null,
type: 'TYPE_MARKET',
reference: '',
peggedOrder: null,
postOnly: false,
reduceOnly: true,
__typename: 'OrderSubmission',
},
__typename: 'StopOrder',
},
} as StopOrderByIdQuery;
return {
data,
}; };
} else { } else {
return { data: undefined }; return { data: undefined };
@ -143,6 +188,31 @@ const submitOrder: VegaStoredTxState = {
}, },
}; };
const submitStopOrder: VegaStoredTxState = {
id: 0,
createdAt: new Date(),
updatedAt: new Date(),
body: {
stopOrdersSubmission: {
risesAbove: {
price: '1234',
orderSubmission: {
marketId: 'market-1',
side: Side.SIDE_BUY,
size: '10',
timeInForce: OrderTimeInForce.TIME_IN_FORCE_FOK,
type: OrderType.TYPE_MARKET,
},
},
},
},
status: VegaTxStatus.Default,
error: null,
txHash: null,
signature: null,
dialogOpen: false,
};
const editOrder: VegaStoredTxState = { const editOrder: VegaStoredTxState = {
id: 0, id: 0,
createdAt: new Date(), createdAt: new Date(),
@ -208,6 +278,23 @@ const cancelAll: VegaStoredTxState = {
dialogOpen: false, dialogOpen: false,
}; };
const cancelStopOrder: VegaStoredTxState = {
id: 0,
createdAt: new Date(),
updatedAt: new Date(),
body: {
stopOrdersCancellation: {
marketId: 'market-1',
stopOrderId: '0',
},
},
status: VegaTxStatus.Default,
error: null,
txHash: null,
signature: null,
dialogOpen: false,
};
const closePosition: VegaStoredTxState = { const closePosition: VegaStoredTxState = {
id: 0, id: 0,
createdAt: new Date(), createdAt: new Date(),
@ -269,12 +356,20 @@ describe('VegaTransactionDetails', () => {
it.each([ it.each([
{ tx: withdraw, details: 'Withdraw 12.34 $A' }, { tx: withdraw, details: 'Withdraw 12.34 $A' },
{ tx: submitOrder, details: 'Submit order - activeM1+0.10 @ 12.34 $A' }, { tx: submitOrder, details: 'Submit order - activeM1+0.10 @ 12.34 $A' },
{
tx: submitStopOrder,
details: 'Submit stop orderM1+0.10 @ ~ $AMark > 12.34',
},
{ {
tx: editOrder, tx: editOrder,
details: 'Edit order - activeM1+0.10 @ 12.34 $A+0.11 @ 10.00 $A', details: 'Edit order - activeM1+0.10 @ 12.34 $A+0.11 @ 10.00 $A',
}, },
{ tx: cancelOrder, details: 'Cancel orderM1+0.10 @ 12.34 $A' }, { tx: cancelOrder, details: 'Cancel orderM1+0.10 @ 12.34 $A' },
{ tx: cancelAll, details: 'Cancel all orders' }, { tx: cancelAll, details: 'Cancel all orders' },
{
tx: cancelStopOrder,
details: 'Cancel stop orderM1-0.10 @ 12.34 $AMark > 12.34',
},
{ tx: closePosition, details: 'Close position for M1' }, { tx: closePosition, details: 'Close position for M1' },
{ tx: batch, details: 'Batch market instruction' }, { tx: batch, details: 'Batch market instruction' },
])('display details for transaction', ({ tx, details }) => { ])('display details for transaction', ({ tx, details }) => {
@ -291,12 +386,18 @@ describe('getVegaTransactionContentIntent', () => {
expect(getVegaTransactionContentIntent(submitOrder).intent).toBe( expect(getVegaTransactionContentIntent(submitOrder).intent).toBe(
Intent.Success Intent.Success
); );
expect(getVegaTransactionContentIntent(submitStopOrder).intent).toBe(
Intent.Primary
);
expect(getVegaTransactionContentIntent(editOrder).intent).toBe( expect(getVegaTransactionContentIntent(editOrder).intent).toBe(
Intent.Primary Intent.Primary
); );
expect(getVegaTransactionContentIntent(cancelOrder).intent).toBe( expect(getVegaTransactionContentIntent(cancelOrder).intent).toBe(
Intent.Primary Intent.Primary
); );
expect(getVegaTransactionContentIntent(cancelStopOrder).intent).toBe(
Intent.Primary
);
expect(getVegaTransactionContentIntent(cancelAll).intent).toBe( expect(getVegaTransactionContentIntent(cancelAll).intent).toBe(
Intent.Primary Intent.Primary
); );

View File

@ -5,10 +5,10 @@ import type {
BatchMarketInstructionSubmissionBody, BatchMarketInstructionSubmissionBody,
OrderAmendment, OrderAmendment,
OrderTxUpdateFieldsFragment, OrderTxUpdateFieldsFragment,
OrderCancellationBody,
OrderSubmission, OrderSubmission,
VegaStoredTxState, VegaStoredTxState,
WithdrawalBusEventFieldsFragment, WithdrawalBusEventFieldsFragment,
StopOrdersSubmission,
} from '@vegaprotocol/wallet'; } from '@vegaprotocol/wallet';
import { import {
isTransferTransaction, isTransferTransaction,
@ -36,9 +36,10 @@ import {
formatNumber, formatNumber,
toBigNum, toBigNum,
truncateByChars, truncateByChars,
formatTrigger,
} from '@vegaprotocol/utils'; } from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import { useAssetsDataProvider } from '@vegaprotocol/assets'; import { useAssetsMapProvider } from '@vegaprotocol/assets';
import { useEthWithdrawApprovalsStore } from './use-ethereum-withdraw-approvals-store'; import { useEthWithdrawApprovalsStore } from './use-ethereum-withdraw-approvals-store';
import { DApp, EXPLORER_TX, useLinks } from '@vegaprotocol/environment'; import { DApp, EXPLORER_TX, useLinks } from '@vegaprotocol/environment';
import { import {
@ -46,8 +47,9 @@ import {
getOrderToastTitle, getOrderToastTitle,
getRejectionReason, getRejectionReason,
useOrderByIdQuery, useOrderByIdQuery,
useStopOrderByIdQuery,
} from '@vegaprotocol/orders'; } from '@vegaprotocol/orders';
import { useMarketList } from '@vegaprotocol/markets'; import { useMarketsMapProvider } from '@vegaprotocol/markets';
import type { Side } from '@vegaprotocol/types'; import type { Side } from '@vegaprotocol/types';
import { OrderStatusMapping } from '@vegaprotocol/types'; import { OrderStatusMapping } from '@vegaprotocol/types';
import { Size } from '@vegaprotocol/datagrid'; import { Size } from '@vegaprotocol/datagrid';
@ -136,8 +138,8 @@ const SubmitOrderDetails = ({
data: OrderSubmission; data: OrderSubmission;
order?: OrderTxUpdateFieldsFragment; order?: OrderTxUpdateFieldsFragment;
}) => { }) => {
const { data: markets } = useMarketList(); const { data: markets } = useMarketsMapProvider();
const market = markets?.find((m) => m.id === order?.marketId); const market = markets?.[order?.marketId || ''];
if (!market) return null; if (!market) return null;
const price = order ? order.price : data.price; const price = order ? order.price : data.price;
@ -172,6 +174,58 @@ const SubmitOrderDetails = ({
); );
}; };
const SubmitStopOrderDetails = ({ data }: { data: StopOrdersSubmission }) => {
const { data: markets } = useMarketsMapProvider();
const stopOrderSetup = data.risesAbove || data.fallsBelow;
if (!stopOrderSetup) return null;
const market = markets?.[stopOrderSetup?.orderSubmission.marketId];
if (!market || !stopOrderSetup) return null;
const { price, size, side } = stopOrderSetup.orderSubmission;
let trigger: Schema.StopOrderTrigger | null = null;
if (stopOrderSetup.price) {
trigger = { price: stopOrderSetup.price, __typename: 'StopOrderPrice' };
} else if (stopOrderSetup.trailingPercentOffset) {
trigger = {
trailingPercentOffset: stopOrderSetup.trailingPercentOffset,
__typename: 'StopOrderTrailingPercentOffset',
};
}
const triggerDirection = data.risesAbove
? Schema.StopOrderTriggerDirection.TRIGGER_DIRECTION_RISES_ABOVE
: Schema.StopOrderTriggerDirection.TRIGGER_DIRECTION_FALLS_BELOW;
return (
<Panel>
<h4>{t('Submit stop order')}</h4>
<p>{market?.tradableInstrument.instrument.code}</p>
<p>
<SizeAtPrice
meta={{
positionDecimalPlaces: market.positionDecimalPlaces,
decimalPlaces: market.decimalPlaces,
asset:
market.tradableInstrument.instrument.product.settlementAsset
.symbol,
}}
side={side}
size={size}
price={price}
/>
<br />
{trigger &&
formatTrigger(
{
triggerDirection,
trigger,
},
market.decimalPlaces,
''
)}
</p>
</Panel>
);
};
const EditOrderDetails = ({ const EditOrderDetails = ({
data, data,
order, order,
@ -183,13 +237,12 @@ const EditOrderDetails = ({
variables: { orderId: data.orderId }, variables: { orderId: data.orderId },
fetchPolicy: 'no-cache', fetchPolicy: 'no-cache',
}); });
const { data: markets } = useMarketList(); const { data: markets } = useMarketsMapProvider();
const originalOrder = order || orderById?.orderByID; const originalOrder = order || orderById?.orderByID;
const marketId = order?.marketId || orderById?.orderByID.market.id; const marketId = order?.marketId || orderById?.orderByID.market.id;
if (!originalOrder) return null; const market = markets?.[marketId || ''];
const market = markets?.find((m) => m.id === marketId); if (!originalOrder || !market) return null;
if (!market) return null;
const original = ( const original = (
<SizeAtPrice <SizeAtPrice
@ -245,11 +298,11 @@ const CancelOrderDetails = ({
const { data: orderById } = useOrderByIdQuery({ const { data: orderById } = useOrderByIdQuery({
variables: { orderId }, variables: { orderId },
}); });
const { data: markets } = useMarketList(); const { data: markets } = useMarketsMapProvider();
const originalOrder = orderById?.orderByID; const originalOrder = orderById?.orderByID;
if (!originalOrder) return null; if (!originalOrder) return null;
const market = markets?.find((m) => m.id === originalOrder.market.id); const market = markets?.[originalOrder.market.id];
if (!market) return null; if (!market) return null;
const original = ( const original = (
@ -282,15 +335,52 @@ const CancelOrderDetails = ({
); );
}; };
const CancelStopOrderDetails = ({ stopOrderId }: { stopOrderId: string }) => {
const { data: orderById } = useStopOrderByIdQuery({
variables: { stopOrderId },
});
const { data: markets } = useMarketsMapProvider();
const originalOrder = orderById?.stopOrder;
if (!originalOrder) return null;
const market = markets?.[originalOrder.marketId];
if (!market) return null;
const original = (
<>
<SizeAtPrice
side={originalOrder.submission.side}
size={originalOrder.submission.size}
price={originalOrder.submission.price}
meta={{
positionDecimalPlaces: market.positionDecimalPlaces,
decimalPlaces: market.decimalPlaces,
asset:
market.tradableInstrument.instrument.product.settlementAsset.symbol,
}}
/>
<br />
{formatTrigger(originalOrder, market.decimalPlaces, '')}
</>
);
return (
<Panel title={stopOrderId}>
<h4>{t('Cancel stop order')}</h4>
<p>{market?.tradableInstrument.instrument.code}</p>
<p>
<s>{original}</s>
</p>
</Panel>
);
};
export const VegaTransactionDetails = ({ tx }: { tx: VegaStoredTxState }) => { export const VegaTransactionDetails = ({ tx }: { tx: VegaStoredTxState }) => {
const { data: assets } = useAssetsDataProvider(); const { data: assets } = useAssetsMapProvider();
const { data: markets } = useMarketList(); const { data: markets } = useMarketsMapProvider();
if (isWithdrawTransaction(tx.body)) { if (isWithdrawTransaction(tx.body)) {
const transactionDetails = tx.body; const transactionDetails = tx.body;
const asset = assets?.find( const asset = assets?.[transactionDetails.withdrawSubmission.asset];
(a) => a.id === transactionDetails.withdrawSubmission.asset
);
if (asset) { if (asset) {
const num = formatNumber( const num = formatNumber(
toBigNum(transactionDetails.withdrawSubmission.amount, asset.decimals), toBigNum(transactionDetails.withdrawSubmission.amount, asset.decimals),
@ -312,15 +402,11 @@ export const VegaTransactionDetails = ({ tx }: { tx: VegaStoredTxState }) => {
); );
} }
if (isOrderCancellationTransaction(tx.body)) { if (isStopOrdersSubmissionTransaction(tx.body)) {
// CANCEL ALL (from Portfolio) return <SubmitStopOrderDetails data={tx.body.stopOrdersSubmission} />;
if ( }
tx.body.orderCancellation.marketId === undefined &&
tx.body.orderCancellation.orderId === undefined
) {
return <Panel>{t('Cancel all orders')}</Panel>;
}
if (isOrderCancellationTransaction(tx.body)) {
// CANCEL // CANCEL
if ( if (
tx.body.orderCancellation.orderId && tx.body.orderCancellation.orderId &&
@ -336,22 +422,50 @@ export const VegaTransactionDetails = ({ tx }: { tx: VegaStoredTxState }) => {
// CANCEL ALL (from Trading) // CANCEL ALL (from Trading)
if (tx.body.orderCancellation.marketId) { if (tx.body.orderCancellation.marketId) {
const marketName = markets?.find( const marketName =
(m) => markets?.[tx.body.orderCancellation.marketId]?.tradableInstrument
m.id === (tx.body as OrderCancellationBody).orderCancellation.marketId .instrument.code;
)?.tradableInstrument.instrument.code; if (marketName) {
return (
<Panel>
{t('Cancel all orders for')} <strong>{marketName}</strong>
</Panel>
);
}
}
// CANCEL ALL (from Portfolio)
return <Panel>{t('Cancel all orders')}</Panel>;
}
if (isStopOrdersCancellationTransaction(tx.body)) {
// CANCEL
if (
tx.body.stopOrdersCancellation.stopOrderId &&
tx.body.stopOrdersCancellation.marketId
) {
return ( return (
<Panel> <CancelStopOrderDetails
{marketName ? ( stopOrderId={String(tx.body.stopOrdersCancellation.stopOrderId)}
<> />
{t('Cancel all orders for')} <strong>{marketName}</strong>
</>
) : (
t('Cancel all orders')
)}
</Panel>
); );
} }
// CANCEL ALL for market
if (tx.body.stopOrdersCancellation.marketId) {
const marketName =
markets?.[tx.body.stopOrdersCancellation.marketId]?.tradableInstrument
.instrument.code;
if (marketName) {
return (
<Panel>
{t('Cancel all stop orders for')} <strong>{marketName}</strong>
</Panel>
);
}
}
// CANCEL ALL
return <Panel>{t('Cancel all stop orders')}</Panel>;
} }
if (isOrderAmendmentTransaction(tx.body)) { if (isOrderAmendmentTransaction(tx.body)) {
@ -368,7 +482,7 @@ export const VegaTransactionDetails = ({ tx }: { tx: VegaStoredTxState }) => {
const marketId = first( const marketId = first(
transaction.batchMarketInstructions.cancellations transaction.batchMarketInstructions.cancellations
)?.marketId; )?.marketId;
const market = marketId && markets?.find((m) => m.id === marketId); const market = markets?.[marketId || ''];
if (market) { if (market) {
return ( return (
<Panel> <Panel>
@ -385,7 +499,7 @@ export const VegaTransactionDetails = ({ tx }: { tx: VegaStoredTxState }) => {
if (isTransferTransaction(tx.body)) { if (isTransferTransaction(tx.body)) {
const { amount, to, asset } = tx.body.transfer; const { amount, to, asset } = tx.body.transfer;
const transferAsset = assets?.find((a) => a.id === asset); const transferAsset = assets?.[asset];
// only render if we have an asset to avoid unformatted amounts showing // only render if we have an asset to avoid unformatted amounts showing
if (transferAsset) { if (transferAsset) {
const value = addDecimalsFormatNumber(amount, transferAsset.decimals); const value = addDecimalsFormatNumber(amount, transferAsset.decimals);