feat(trading): submit iceberg orders (#4230)
This commit is contained in:
parent
7c0a4f61e9
commit
94e398dd1c
File diff suppressed because one or more lines are too long
@ -50,7 +50,7 @@ describe('Portfolio page', { tags: '@smoke' }, () => {
|
||||
cy.get('fieldset.ag-simple-filter-body-wrapper')
|
||||
.should('be.visible')
|
||||
.within((fields) => {
|
||||
cy.wrap(fields).find('label').should('have.length', 17);
|
||||
cy.wrap(fields).find('label').should('have.length', 18);
|
||||
});
|
||||
cy.getByTestId('"Ledger entries"').click();
|
||||
cy.get('fieldset.ag-simple-filter-body-wrapper').should('not.exist');
|
||||
|
@ -0,0 +1,195 @@
|
||||
import { Controller, type Control } from 'react-hook-form';
|
||||
import type { Market } from '@vegaprotocol/markets';
|
||||
import type { OrderObj } from '@vegaprotocol/orders';
|
||||
import type { OrderFormFields } from '../../hooks/use-order-form';
|
||||
import { toDecimal, validateAmount } from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import {
|
||||
FormGroup,
|
||||
Input,
|
||||
InputError,
|
||||
Tooltip,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
export interface DealTicketSizeIcebergProps {
|
||||
control: Control<OrderFormFields>;
|
||||
market: Market;
|
||||
peakSizeError?: string;
|
||||
minimumVisibleSizeError?: string;
|
||||
update: (obj: Partial<OrderObj>) => void;
|
||||
peakSize: string;
|
||||
minimumVisibleSize: string;
|
||||
size: string;
|
||||
}
|
||||
|
||||
export const DealTicketSizeIceberg = ({
|
||||
control,
|
||||
market,
|
||||
update,
|
||||
peakSizeError,
|
||||
minimumVisibleSizeError,
|
||||
peakSize,
|
||||
minimumVisibleSize,
|
||||
size,
|
||||
}: DealTicketSizeIcebergProps) => {
|
||||
const sizeStep = toDecimal(market?.positionDecimalPlaces);
|
||||
|
||||
const renderPeakSizeError = () => {
|
||||
if (peakSizeError) {
|
||||
return (
|
||||
<InputError testId="deal-ticket-peak-error-message-size-limit">
|
||||
{peakSizeError}
|
||||
</InputError>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const renderMinimumSizeError = () => {
|
||||
if (minimumVisibleSizeError) {
|
||||
return (
|
||||
<InputError testId="deal-ticket-minimum-error-message-size-limit">
|
||||
{minimumVisibleSizeError}
|
||||
</InputError>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mb-2">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex-1">
|
||||
<FormGroup
|
||||
label={
|
||||
<Tooltip
|
||||
description={
|
||||
<div>
|
||||
{t(
|
||||
'The maximum volume that can be traded at once. Must be less than the total size of the order.'
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<span className="text-xs">{t('Peak size')}</span>
|
||||
</Tooltip>
|
||||
}
|
||||
labelFor="input-order-peak-size"
|
||||
className="!mb-1"
|
||||
>
|
||||
<Controller
|
||||
name="icebergOpts.peakSize"
|
||||
control={control}
|
||||
rules={{
|
||||
required: t('You need to provide a peak size'),
|
||||
min: {
|
||||
value: sizeStep,
|
||||
message: t('Peak size cannot be lower than ' + sizeStep),
|
||||
},
|
||||
max: {
|
||||
value: size,
|
||||
message: t(
|
||||
'Peak size cannot be greater than the size (%s) ',
|
||||
[size]
|
||||
),
|
||||
},
|
||||
validate: validateAmount(sizeStep, 'peakSize'),
|
||||
}}
|
||||
render={() => (
|
||||
<Input
|
||||
id="input-order-peak-size"
|
||||
className="w-full"
|
||||
type="number"
|
||||
value={peakSize}
|
||||
onChange={(e) =>
|
||||
update({
|
||||
icebergOpts: {
|
||||
peakSize: e.target.value,
|
||||
minimumVisibleSize,
|
||||
},
|
||||
})
|
||||
}
|
||||
step={sizeStep}
|
||||
min={sizeStep}
|
||||
max={size}
|
||||
data-testid="order-peak-size"
|
||||
onWheel={(e) => e.currentTarget.blur()}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</FormGroup>
|
||||
</div>
|
||||
<div className="flex-0 items-center">
|
||||
<div className="flex"></div>
|
||||
<div className="flex"></div>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<FormGroup
|
||||
label={
|
||||
<Tooltip
|
||||
description={
|
||||
<div>
|
||||
{t(
|
||||
'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.'
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<span className="text-xs">{t('Minimum size')}</span>
|
||||
</Tooltip>
|
||||
}
|
||||
labelFor="input-order-minimum-size"
|
||||
className="!mb-1"
|
||||
>
|
||||
<Controller
|
||||
name="icebergOpts.minimumVisibleSize"
|
||||
control={control}
|
||||
rules={{
|
||||
required: t('You need to provide a minimum visible size'),
|
||||
min: {
|
||||
value: sizeStep,
|
||||
message: t(
|
||||
'Minimum visible size cannot be lower than ' + sizeStep
|
||||
),
|
||||
},
|
||||
max: {
|
||||
value: peakSize,
|
||||
message: t(
|
||||
'Minimum visible size cannot be greater than the peak size (%s)',
|
||||
[peakSize]
|
||||
),
|
||||
},
|
||||
validate: validateAmount(sizeStep, 'minimumVisibleSize'),
|
||||
}}
|
||||
render={() => (
|
||||
<Input
|
||||
id="input-order-minimum-size"
|
||||
className="w-full"
|
||||
type="number"
|
||||
value={minimumVisibleSize}
|
||||
onChange={(e) =>
|
||||
update({
|
||||
icebergOpts: {
|
||||
peakSize,
|
||||
minimumVisibleSize: e.target.value,
|
||||
},
|
||||
})
|
||||
}
|
||||
step={sizeStep}
|
||||
min={sizeStep}
|
||||
max={peakSize}
|
||||
data-testid="order-minimum-size"
|
||||
onWheel={(e) => e.currentTarget.blur()}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</FormGroup>
|
||||
</div>
|
||||
</div>
|
||||
{renderPeakSizeError()}
|
||||
{renderMinimumSizeError()}
|
||||
</div>
|
||||
);
|
||||
};
|
@ -224,6 +224,109 @@ describe('DealTicket', () => {
|
||||
expect(screen.getByTestId('reduce-only')).not.toBeChecked();
|
||||
});
|
||||
|
||||
it('should set values for a persistent post only iceberg order and disable reduce only checkbox', () => {
|
||||
const expectedOrder = {
|
||||
marketId: market.id,
|
||||
type: Schema.OrderType.TYPE_LIMIT,
|
||||
side: Schema.Side.SIDE_SELL,
|
||||
size: '10',
|
||||
price: '300.22',
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||
persist: true,
|
||||
reduceOnly: false,
|
||||
postOnly: true,
|
||||
iceberg: true,
|
||||
icebergOpts: {
|
||||
peakSize: '5',
|
||||
minimumVisibleSize: '7',
|
||||
},
|
||||
};
|
||||
|
||||
useOrderStore.setState({
|
||||
orders: {
|
||||
[expectedOrder.marketId]: expectedOrder,
|
||||
},
|
||||
});
|
||||
|
||||
render(generateJsx());
|
||||
|
||||
// Assert correct defaults are used from store
|
||||
expect(
|
||||
screen
|
||||
.getByTestId(`order-type-${Schema.OrderType.TYPE_LIMIT}`)
|
||||
.querySelector('input')
|
||||
).toBeChecked();
|
||||
expect(
|
||||
screen.queryByTestId('order-side-SIDE_SELL')?.querySelector('input')
|
||||
).toBeChecked();
|
||||
expect(
|
||||
screen.queryByTestId('order-side-SIDE_BUY')?.querySelector('input')
|
||||
).not.toBeChecked();
|
||||
expect(screen.getByTestId('order-size')).toHaveDisplayValue(
|
||||
expectedOrder.size
|
||||
);
|
||||
expect(screen.getByTestId('order-tif')).toHaveValue(
|
||||
expectedOrder.timeInForce
|
||||
);
|
||||
expect(screen.getByTestId('order-price')).toHaveDisplayValue(
|
||||
expectedOrder.price
|
||||
);
|
||||
expect(screen.getByTestId('post-only')).toBeEnabled();
|
||||
expect(screen.getByTestId('reduce-only')).toBeDisabled();
|
||||
expect(screen.getByTestId('post-only')).toBeChecked();
|
||||
expect(screen.getByTestId('reduce-only')).not.toBeChecked();
|
||||
expect(screen.getByTestId('iceberg')).toBeEnabled();
|
||||
expect(screen.getByTestId('iceberg')).toBeChecked();
|
||||
});
|
||||
|
||||
it('should set values for a non-persistent iceberg order and disable post only checkbox', () => {
|
||||
const expectedOrder = {
|
||||
marketId: market.id,
|
||||
type: Schema.OrderType.TYPE_LIMIT,
|
||||
side: Schema.Side.SIDE_SELL,
|
||||
size: '0.1',
|
||||
price: '300.22',
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_IOC,
|
||||
persist: false,
|
||||
reduceOnly: false,
|
||||
postOnly: false,
|
||||
};
|
||||
useOrderStore.setState({
|
||||
orders: {
|
||||
[expectedOrder.marketId]: expectedOrder,
|
||||
},
|
||||
});
|
||||
|
||||
render(generateJsx());
|
||||
|
||||
// Assert correct defaults are used from store
|
||||
expect(
|
||||
screen
|
||||
.getByTestId(`order-type-${Schema.OrderType.TYPE_LIMIT}`)
|
||||
.querySelector('input')
|
||||
).toBeChecked();
|
||||
expect(
|
||||
screen.queryByTestId('order-side-SIDE_SELL')?.querySelector('input')
|
||||
).toBeChecked();
|
||||
expect(
|
||||
screen.queryByTestId('order-side-SIDE_BUY')?.querySelector('input')
|
||||
).not.toBeChecked();
|
||||
expect(screen.getByTestId('order-size')).toHaveDisplayValue(
|
||||
expectedOrder.size
|
||||
);
|
||||
expect(screen.getByTestId('order-tif')).toHaveValue(
|
||||
expectedOrder.timeInForce
|
||||
);
|
||||
expect(screen.getByTestId('order-price')).toHaveDisplayValue(
|
||||
expectedOrder.price
|
||||
);
|
||||
expect(screen.getByTestId('post-only')).toBeDisabled();
|
||||
expect(screen.getByTestId('reduce-only')).toBeEnabled();
|
||||
expect(screen.getByTestId('reduce-only')).not.toBeChecked();
|
||||
expect(screen.getByTestId('post-only')).not.toBeChecked();
|
||||
expect(screen.getByTestId('iceberg')).not.toBeChecked();
|
||||
});
|
||||
|
||||
it('handles TIF select box dependent on order type', async () => {
|
||||
render(generateJsx());
|
||||
|
||||
|
@ -54,6 +54,7 @@ import {
|
||||
import { OrderTimeInForce, OrderType } from '@vegaprotocol/types';
|
||||
import { useOrderForm } from '../../hooks/use-order-form';
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
import { DealTicketSizeIceberg } from './deal-ticket-size-iceberg';
|
||||
|
||||
export interface DealTicketProps {
|
||||
market: Market;
|
||||
@ -292,6 +293,22 @@ export const DealTicket = ({
|
||||
timeInForce: lastTIF[type] || order.timeInForce,
|
||||
postOnly:
|
||||
type === OrderType.TYPE_MARKET ? false : order.postOnly,
|
||||
iceberg:
|
||||
type === OrderType.TYPE_MARKET ||
|
||||
[
|
||||
OrderTimeInForce.TIME_IN_FORCE_FOK,
|
||||
OrderTimeInForce.TIME_IN_FORCE_IOC,
|
||||
].includes(lastTIF[type] || order.timeInForce)
|
||||
? false
|
||||
: order.iceberg,
|
||||
icebergOpts:
|
||||
type === OrderType.TYPE_MARKET ||
|
||||
[
|
||||
OrderTimeInForce.TIME_IN_FORCE_FOK,
|
||||
OrderTimeInForce.TIME_IN_FORCE_IOC,
|
||||
].includes(lastTIF[type] || order.timeInForce)
|
||||
? undefined
|
||||
: order.icebergOpts,
|
||||
reduceOnly:
|
||||
type === OrderType.TYPE_LIMIT &&
|
||||
![
|
||||
@ -463,6 +480,51 @@ export const DealTicket = ({
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex gap-2 pb-2 justify-between">
|
||||
{order.type === Schema.OrderType.TYPE_LIMIT && (
|
||||
<Controller
|
||||
name="iceberg"
|
||||
control={control}
|
||||
render={() => (
|
||||
<Checkbox
|
||||
name="iceberg"
|
||||
checked={order.iceberg}
|
||||
onCheckedChange={() => {
|
||||
update({ iceberg: !order.iceberg, icebergOpts: undefined });
|
||||
}}
|
||||
label={
|
||||
<Tooltip
|
||||
description={
|
||||
<p>
|
||||
{t(`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.`)}
|
||||
</p>
|
||||
}
|
||||
>
|
||||
<span className="text-xs">{t('Iceberg')}</span>
|
||||
</Tooltip>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
{order.iceberg && (
|
||||
<DealTicketSizeIceberg
|
||||
update={update}
|
||||
market={market}
|
||||
peakSizeError={errors.icebergOpts?.peakSize?.message}
|
||||
minimumVisibleSizeError={
|
||||
errors.icebergOpts?.minimumVisibleSize?.message
|
||||
}
|
||||
control={control}
|
||||
size={order.size}
|
||||
peakSize={order.icebergOpts?.peakSize || ''}
|
||||
minimumVisibleSize={order.icebergOpts?.minimumVisibleSize || ''}
|
||||
/>
|
||||
)}
|
||||
<SummaryMessage
|
||||
errorMessage={errors.summary?.message}
|
||||
asset={asset}
|
||||
|
@ -4,7 +4,6 @@ import { getDefaultOrder, useOrder } from '@vegaprotocol/orders';
|
||||
import { useEffect } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import type { OrderSubmission } from '@vegaprotocol/wallet';
|
||||
import type { Exact } from 'type-fest';
|
||||
|
||||
export type OrderFormFields = OrderObj & {
|
||||
summary: string;
|
||||
@ -51,13 +50,11 @@ export const useOrderForm = (marketId: string) => {
|
||||
}
|
||||
}, [order, isSubmitted, getValues, setValue]);
|
||||
|
||||
const handleSubmitWrapper = (
|
||||
cb: <T>(o: Exact<OrderSubmission, T>) => void
|
||||
) => {
|
||||
const handleSubmitWrapper = (cb: (o: OrderSubmission) => void) => {
|
||||
return handleSubmit(() => {
|
||||
// remove the persist key from the order in the store, the wallet will reject
|
||||
// remove the persist and iceberg key from the order in the store, the wallet will reject
|
||||
// an order that contains unrecognized additional keys
|
||||
cb(omit(order, 'persist'));
|
||||
cb(omit(order, 'persist', 'iceberg'));
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -22,7 +22,7 @@ export type OrdersQueryVariables = Types.Exact<{
|
||||
|
||||
export type OrdersQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, ordersConnection?: { __typename?: 'OrderConnection', edges?: Array<{ __typename?: 'OrderEdge', cursor?: string | null, node: { __typename?: 'Order', id: 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, postOnly?: boolean | null, reduceOnly?: boolean | null, market: { __typename?: 'Market', id: string }, liquidityProvision?: { __typename: 'LiquidityProvision' } | null, peggedOrder?: { __typename: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null, icebergOrder?: { __typename: 'IcebergOrder', peakSize: string, minimumVisibleSize: string, reservedRemaining: string } | null } }> | null, pageInfo?: { __typename?: 'PageInfo', startCursor: string, endCursor: string, hasNextPage: boolean, hasPreviousPage: boolean } | null } | null } | null };
|
||||
|
||||
export type OrderUpdateFieldsFragment = { __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 };
|
||||
export type OrderUpdateFieldsFragment = { __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 };
|
||||
|
||||
export type OrdersUpdateSubscriptionVariables = Types.Exact<{
|
||||
partyId: Types.Scalars['ID'];
|
||||
@ -30,7 +30,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 const OrderFieldsFragmentDoc = gql`
|
||||
fragment OrderFields on Order {
|
||||
@ -89,6 +89,7 @@ export const OrderUpdateFieldsFragmentDoc = gql`
|
||||
offset
|
||||
}
|
||||
icebergOrder {
|
||||
__typename
|
||||
peakSize
|
||||
minimumVisibleSize
|
||||
reservedRemaining
|
||||
|
@ -65,7 +65,6 @@ export const mapOrderUpdateToOrder = (
|
||||
liquidityProvision: liquidityProvision,
|
||||
icebergOrder: order.icebergOrder
|
||||
? {
|
||||
__typename: 'IcebergOrder',
|
||||
...order.icebergOrder,
|
||||
}
|
||||
: undefined,
|
||||
|
@ -267,12 +267,14 @@ export const OrderListTable = memo<
|
||||
<div className="flex gap-2 items-center justify-end">
|
||||
{isOrderAmendable(data) && !props.isReadOnly && (
|
||||
<>
|
||||
{!data.icebergOrder && (
|
||||
<ButtonLink
|
||||
data-testid="edit"
|
||||
onClick={() => onEdit(data)}
|
||||
>
|
||||
{t('Edit')}
|
||||
</ButtonLink>
|
||||
)}
|
||||
<ButtonLink
|
||||
data-testid="cancel"
|
||||
onClick={() => onCancel(data)}
|
||||
|
@ -16,7 +16,13 @@ export type OrderObj = {
|
||||
persist: boolean; // key used to determine if order should be kept in localStorage
|
||||
postOnly?: boolean;
|
||||
reduceOnly?: boolean;
|
||||
iceberg?: boolean;
|
||||
icebergOpts?: {
|
||||
peakSize: string;
|
||||
minimumVisibleSize: string;
|
||||
};
|
||||
};
|
||||
|
||||
type OrderMap = { [marketId: string]: OrderObj | undefined };
|
||||
|
||||
type UpdateOrder = (
|
||||
|
2
libs/types/src/__generated__/types.ts
generated
2
libs/types/src/__generated__/types.ts
generated
@ -96,6 +96,8 @@ export enum AccountType {
|
||||
ACCOUNT_TYPE_HOLDING = 'ACCOUNT_TYPE_HOLDING',
|
||||
/** Insurance pool account - only for 'system' party */
|
||||
ACCOUNT_TYPE_INSURANCE = 'ACCOUNT_TYPE_INSURANCE',
|
||||
/** Per liquidity provider, per market account for holding LPs' fees before distribution */
|
||||
ACCOUNT_TYPE_LP_LIQUIDITY_FEES = 'ACCOUNT_TYPE_LP_LIQUIDITY_FEES',
|
||||
/**
|
||||
* Margin - The leverage account for parties, contains funds set aside for the margin needed to support
|
||||
* a party's open positions. Each party will have a margin account for each market they have traded in.
|
||||
|
@ -45,6 +45,7 @@ export const AccountTypeMapping: {
|
||||
ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES: 'Reward Maker paid fees',
|
||||
ACCOUNT_TYPE_SETTLEMENT: 'Settlement',
|
||||
ACCOUNT_TYPE_HOLDING: 'Holding',
|
||||
ACCOUNT_TYPE_LP_LIQUIDITY_FEES: 'LP Liquidity Fees',
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -4,7 +4,7 @@ import type { ReactNode } from 'react';
|
||||
export interface FormGroupProps {
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
label: string; // For accessibility reasons this must always be set for screen readers. If you want it to not show, then use the hideLabel prop"
|
||||
label: string | ReactNode; // For accessibility reasons this must always be set for screen readers. If you want it to not show, then use the hideLabel prop"
|
||||
labelFor: string; // Same as above
|
||||
hideLabel?: boolean;
|
||||
labelDescription?: string;
|
||||
|
@ -7,7 +7,7 @@ import {
|
||||
export const formatValue = (
|
||||
value: string | number | null | undefined,
|
||||
decimalPlaces: number,
|
||||
quantum?: string,
|
||||
quantum?: string | number,
|
||||
formatDecimals?: number,
|
||||
emptyValue = '-'
|
||||
): string => {
|
||||
|
@ -88,7 +88,6 @@ export const OrderTxUpdateFieldsFragmentDoc = gql`
|
||||
expiresAt
|
||||
side
|
||||
marketId
|
||||
remaining
|
||||
}
|
||||
`;
|
||||
export const DepositBusEventFieldsFragmentDoc = gql`
|
||||
|
@ -47,6 +47,10 @@ export interface OrderSubmission {
|
||||
expiresAt?: string;
|
||||
postOnly?: boolean;
|
||||
reduceOnly?: boolean;
|
||||
icebergOpts?: {
|
||||
peakSize: string;
|
||||
minimumVisibleSize: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface OrderCancellation {
|
||||
|
@ -50,6 +50,13 @@ export const normalizeOrderSubmission = (
|
||||
: undefined,
|
||||
postOnly: order.postOnly,
|
||||
reduceOnly: order.reduceOnly,
|
||||
icebergOpts: order.icebergOpts && {
|
||||
peakSize: removeDecimal(order.icebergOpts.peakSize, positionDecimalPlaces),
|
||||
minimumVisibleSize: removeDecimal(
|
||||
order.icebergOpts.minimumVisibleSize,
|
||||
positionDecimalPlaces
|
||||
),
|
||||
},
|
||||
});
|
||||
|
||||
export const normalizeOrderAmendment = <T extends Exact<OrderAmendment, T>>(
|
||||
|
Loading…
Reference in New Issue
Block a user