fix(#623): order fixes
* feat: format size and volume with positionDecimalPlaces * fix: pass in calculated step so client side validation works * fix: add requested state to order dialog, handle user rejected error * feat: add test case for user rejecting tx * feat: add test case for order list fractional sizes * feat: add test case for fractional volume in positions table * fix: deal ticket tests imports * feat: add test case for trades fractional size * fix: props for orderbook tests * fix: add missing positionDecimalPlaces fields to mock functions * fix: improve error handling of service error with type guard
This commit is contained in:
parent
a9df2f425d
commit
d5727baffc
@ -12,6 +12,7 @@ export const generateOrderBook = (
|
|||||||
const marketDepth: MarketDepth_market = {
|
const marketDepth: MarketDepth_market = {
|
||||||
id: 'b2426f67b085ba8fb429f1b529d49372b2d096c6fb6f509f76c5863abb6d969e',
|
id: 'b2426f67b085ba8fb429f1b529d49372b2d096c6fb6f509f76c5863abb6d969e',
|
||||||
decimalPlaces: 5,
|
decimalPlaces: 5,
|
||||||
|
positionDecimalPlaces: 0,
|
||||||
data: {
|
data: {
|
||||||
staticMidPrice: '826337',
|
staticMidPrice: '826337',
|
||||||
marketTradingMode: MarketTradingMode.Continuous,
|
marketTradingMode: MarketTradingMode.Continuous,
|
||||||
|
@ -18,6 +18,7 @@ export const generateOrders = (override?: PartialDeep<Orders>): Orders => {
|
|||||||
id: 'c9f5acd348796011c075077e4d58d9b7f1689b7c1c8e030a5e886b83aa96923d',
|
id: 'c9f5acd348796011c075077e4d58d9b7f1689b7c1c8e030a5e886b83aa96923d',
|
||||||
name: 'AAVEDAI Monthly (30 Jun 2022)',
|
name: 'AAVEDAI Monthly (30 Jun 2022)',
|
||||||
decimalPlaces: 5,
|
decimalPlaces: 5,
|
||||||
|
positionDecimalPlaces: 0,
|
||||||
tradableInstrument: {
|
tradableInstrument: {
|
||||||
__typename: 'TradableInstrument',
|
__typename: 'TradableInstrument',
|
||||||
instrument: {
|
instrument: {
|
||||||
@ -46,6 +47,7 @@ export const generateOrders = (override?: PartialDeep<Orders>): Orders => {
|
|||||||
id: '5a4b0b9e9c0629f0315ec56fcb7bd444b0c6e4da5ec7677719d502626658a376',
|
id: '5a4b0b9e9c0629f0315ec56fcb7bd444b0c6e4da5ec7677719d502626658a376',
|
||||||
name: 'Tesla Quarterly (30 Jun 2022)',
|
name: 'Tesla Quarterly (30 Jun 2022)',
|
||||||
decimalPlaces: 5,
|
decimalPlaces: 5,
|
||||||
|
positionDecimalPlaces: 0,
|
||||||
tradableInstrument: {
|
tradableInstrument: {
|
||||||
__typename: 'TradableInstrument',
|
__typename: 'TradableInstrument',
|
||||||
instrument: {
|
instrument: {
|
||||||
|
@ -25,6 +25,7 @@ export const generatePositions = (
|
|||||||
market: { __typename: 'Market', id: '123' },
|
market: { __typename: 'Market', id: '123' },
|
||||||
},
|
},
|
||||||
decimalPlaces: 5,
|
decimalPlaces: 5,
|
||||||
|
positionDecimalPlaces: 0,
|
||||||
tradableInstrument: {
|
tradableInstrument: {
|
||||||
instrument: {
|
instrument: {
|
||||||
id: '',
|
id: '',
|
||||||
@ -78,6 +79,7 @@ export const generatePositions = (
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
decimalPlaces: 5,
|
decimalPlaces: 5,
|
||||||
|
positionDecimalPlaces: 0,
|
||||||
tradableInstrument: {
|
tradableInstrument: {
|
||||||
instrument: {
|
instrument: {
|
||||||
id: '',
|
id: '',
|
||||||
|
@ -12,6 +12,7 @@ export const generateTrades = (override?: PartialDeep<Trades>): Trades => {
|
|||||||
market: {
|
market: {
|
||||||
id: '0c3c1490db767f926d24fb674b4235a9aa339614915a4ab96cbfc0e1ad83c0ff',
|
id: '0c3c1490db767f926d24fb674b4235a9aa339614915a4ab96cbfc0e1ad83c0ff',
|
||||||
decimalPlaces: 5,
|
decimalPlaces: 5,
|
||||||
|
positionDecimalPlaces: 0,
|
||||||
__typename: 'Market',
|
__typename: 'Market',
|
||||||
},
|
},
|
||||||
__typename: 'Trade',
|
__typename: 'Trade',
|
||||||
@ -24,6 +25,7 @@ export const generateTrades = (override?: PartialDeep<Trades>): Trades => {
|
|||||||
market: {
|
market: {
|
||||||
id: '0c3c1490db767f926d24fb674b4235a9aa339614915a4ab96cbfc0e1ad83c0ff',
|
id: '0c3c1490db767f926d24fb674b4235a9aa339614915a4ab96cbfc0e1ad83c0ff',
|
||||||
decimalPlaces: 5,
|
decimalPlaces: 5,
|
||||||
|
positionDecimalPlaces: 0,
|
||||||
__typename: 'Market',
|
__typename: 'Market',
|
||||||
},
|
},
|
||||||
__typename: 'Trade',
|
__typename: 'Trade',
|
||||||
@ -36,6 +38,7 @@ export const generateTrades = (override?: PartialDeep<Trades>): Trades => {
|
|||||||
market: {
|
market: {
|
||||||
id: '0c3c1490db767f926d24fb674b4235a9aa339614915a4ab96cbfc0e1ad83c0ff',
|
id: '0c3c1490db767f926d24fb674b4235a9aa339614915a4ab96cbfc0e1ad83c0ff',
|
||||||
decimalPlaces: 5,
|
decimalPlaces: 5,
|
||||||
|
positionDecimalPlaces: 0,
|
||||||
__typename: 'Market',
|
__typename: 'Market',
|
||||||
},
|
},
|
||||||
__typename: 'Trade',
|
__typename: 'Trade',
|
||||||
|
@ -109,7 +109,7 @@ interface TradeGridProps {
|
|||||||
export const TradeGrid = ({ market }: TradeGridProps) => {
|
export const TradeGrid = ({ market }: TradeGridProps) => {
|
||||||
const wrapperClasses = classNames(
|
const wrapperClasses = classNames(
|
||||||
'h-full max-h-full',
|
'h-full max-h-full',
|
||||||
'grid gap-4 grid-cols-[1fr_375px_460px] grid-rows-[min-content_1fr_200px]',
|
'grid gap-4 grid-cols-[1fr_375px_460px] grid-rows-[min-content_1fr_300px]',
|
||||||
'bg-black-10 dark:bg-white-10',
|
'bg-black-10 dark:bg-white-10',
|
||||||
'text-ui'
|
'text-ui'
|
||||||
);
|
);
|
||||||
|
@ -1,108 +0,0 @@
|
|||||||
/* tslint:disable */
|
|
||||||
/* eslint-disable */
|
|
||||||
// @generated
|
|
||||||
// This file was automatically generated and should not be edited.
|
|
||||||
|
|
||||||
import { BusEventType, OrderType, OrderStatus, OrderRejectionReason } from "@vegaprotocol/types";
|
|
||||||
|
|
||||||
// ====================================================
|
|
||||||
// GraphQL subscription operation: OrderEvent
|
|
||||||
// ====================================================
|
|
||||||
|
|
||||||
export interface OrderEvent_busEvents_event_TimeUpdate {
|
|
||||||
__typename: "TimeUpdate" | "MarketEvent" | "TransferResponses" | "PositionResolution" | "Trade" | "Account" | "Party" | "MarginLevels" | "Proposal" | "Vote" | "MarketData" | "NodeSignature" | "LossSocialization" | "SettlePosition" | "Market" | "Asset" | "MarketTick" | "SettleDistressed" | "AuctionEvent" | "RiskFactor" | "Deposit" | "Withdrawal" | "OracleSpec" | "LiquidityProvision";
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface OrderEvent_busEvents_event_Order_market {
|
|
||||||
__typename: "Market";
|
|
||||||
/**
|
|
||||||
* Market full name
|
|
||||||
*/
|
|
||||||
name: string;
|
|
||||||
/**
|
|
||||||
* decimalPlaces indicates the number of decimal places that an integer must be shifted by in order to get a correct
|
|
||||||
* number denominated in the currency of the Market. (uint64)
|
|
||||||
*
|
|
||||||
* Examples:
|
|
||||||
* Currency Balance decimalPlaces Real Balance
|
|
||||||
* GBP 100 0 GBP 100
|
|
||||||
* GBP 100 2 GBP 1.00
|
|
||||||
* GBP 100 4 GBP 0.01
|
|
||||||
* GBP 1 4 GBP 0.0001 ( 0.01p )
|
|
||||||
*
|
|
||||||
* GBX (pence) 100 0 GBP 1.00 (100p )
|
|
||||||
* GBX (pence) 100 2 GBP 0.01 ( 1p )
|
|
||||||
* GBX (pence) 100 4 GBP 0.0001 ( 0.01p )
|
|
||||||
* GBX (pence) 1 4 GBP 0.000001 ( 0.0001p)
|
|
||||||
*/
|
|
||||||
decimalPlaces: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface OrderEvent_busEvents_event_Order {
|
|
||||||
__typename: "Order";
|
|
||||||
/**
|
|
||||||
* Type the order type (defaults to PARTY)
|
|
||||||
*/
|
|
||||||
type: OrderType | null;
|
|
||||||
/**
|
|
||||||
* Hash of the order data
|
|
||||||
*/
|
|
||||||
id: string;
|
|
||||||
/**
|
|
||||||
* The status of an order, for example 'Active'
|
|
||||||
*/
|
|
||||||
status: OrderStatus;
|
|
||||||
/**
|
|
||||||
* Reason for the order to be rejected
|
|
||||||
*/
|
|
||||||
rejectionReason: OrderRejectionReason | null;
|
|
||||||
/**
|
|
||||||
* RFC3339Nano formatted date and time for when the order was created (timestamp)
|
|
||||||
*/
|
|
||||||
createdAt: string;
|
|
||||||
/**
|
|
||||||
* Total number of contracts that may be bought or sold (immutable) (uint64)
|
|
||||||
*/
|
|
||||||
size: string;
|
|
||||||
/**
|
|
||||||
* The worst price the order will trade at (e.g. buy for price or less, sell for price or more) (uint64)
|
|
||||||
*/
|
|
||||||
price: string;
|
|
||||||
/**
|
|
||||||
* The market the order is trading on (probably stored internally as a hash of the market details)
|
|
||||||
*/
|
|
||||||
market: OrderEvent_busEvents_event_Order_market | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type OrderEvent_busEvents_event = OrderEvent_busEvents_event_TimeUpdate | OrderEvent_busEvents_event_Order;
|
|
||||||
|
|
||||||
export interface OrderEvent_busEvents {
|
|
||||||
__typename: "BusEvent";
|
|
||||||
/**
|
|
||||||
* the id for this event
|
|
||||||
*/
|
|
||||||
eventId: string;
|
|
||||||
/**
|
|
||||||
* the block hash
|
|
||||||
*/
|
|
||||||
block: string;
|
|
||||||
/**
|
|
||||||
* the type of event we're dealing with
|
|
||||||
*/
|
|
||||||
type: BusEventType;
|
|
||||||
/**
|
|
||||||
* the payload - the wrapped event
|
|
||||||
*/
|
|
||||||
event: OrderEvent_busEvents_event;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface OrderEvent {
|
|
||||||
/**
|
|
||||||
* Subscribe to event data from the event bus
|
|
||||||
*/
|
|
||||||
busEvents: OrderEvent_busEvents[] | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface OrderEventVariables {
|
|
||||||
partyId: string;
|
|
||||||
}
|
|
@ -1,3 +1,2 @@
|
|||||||
export * from './DealTicketQuery';
|
export * from './DealTicketQuery';
|
||||||
export * from './MarketInfoQuery';
|
export * from './MarketInfoQuery';
|
||||||
export * from './OrderEvent';
|
|
||||||
|
@ -12,22 +12,17 @@ export interface DealTicketAmountProps {
|
|||||||
price?: string;
|
price?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getAmountComponent = (type: OrderType) => {
|
export const DealTicketAmount = ({
|
||||||
switch (type) {
|
orderType,
|
||||||
|
...props
|
||||||
|
}: DealTicketAmountProps) => {
|
||||||
|
switch (orderType) {
|
||||||
case OrderType.Market:
|
case OrderType.Market:
|
||||||
return DealTicketMarketAmount;
|
return <DealTicketMarketAmount {...props} />;
|
||||||
case OrderType.Limit:
|
case OrderType.Limit:
|
||||||
return DealTicketLimitAmount;
|
return <DealTicketLimitAmount {...props} />;
|
||||||
default: {
|
default: {
|
||||||
throw new Error('Invalid ticket type');
|
throw new Error('Invalid ticket type');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DealTicketAmount = ({
|
|
||||||
orderType,
|
|
||||||
...props
|
|
||||||
}: DealTicketAmountProps) => {
|
|
||||||
const AmountComponent = getAmountComponent(orderType);
|
|
||||||
return <AmountComponent {...props} />;
|
|
||||||
};
|
|
||||||
|
@ -37,6 +37,10 @@ export const DealTicketManager = ({
|
|||||||
return Intent.Danger;
|
return Intent.Danger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (status === VegaTxStatus.Requested) {
|
||||||
|
return Intent.Warning;
|
||||||
|
}
|
||||||
|
|
||||||
if (status === VegaTxStatus.Error) {
|
if (status === VegaTxStatus.Error) {
|
||||||
return Intent.Danger;
|
return Intent.Danger;
|
||||||
}
|
}
|
||||||
@ -47,6 +51,8 @@ export const DealTicketManager = ({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (transaction.status !== VegaTxStatus.Default) {
|
if (transaction.status !== VegaTxStatus.Default) {
|
||||||
setOrderDialogOpen(true);
|
setOrderDialogOpen(true);
|
||||||
|
} else {
|
||||||
|
setOrderDialogOpen(false);
|
||||||
}
|
}
|
||||||
}, [transaction.status]);
|
}, [transaction.status]);
|
||||||
|
|
||||||
|
@ -6,13 +6,14 @@ import {
|
|||||||
import { addDecimal } from '@vegaprotocol/react-helpers';
|
import { addDecimal } from '@vegaprotocol/react-helpers';
|
||||||
import { fireEvent, render, screen, act } from '@testing-library/react';
|
import { fireEvent, render, screen, act } from '@testing-library/react';
|
||||||
import { DealTicket } from './deal-ticket';
|
import { DealTicket } from './deal-ticket';
|
||||||
import type { DealTicketQuery_market } from '../__generated__/DealTicketQuery';
|
import type { DealTicketQuery_market } from './__generated__/DealTicketQuery';
|
||||||
import type { Order } from '../utils/get-default-order';
|
import type { Order } from '../utils/get-default-order';
|
||||||
import { MarketState, MarketTradingMode } from '@vegaprotocol/types';
|
import { MarketState, MarketTradingMode } from '@vegaprotocol/types';
|
||||||
|
|
||||||
const market: DealTicketQuery_market = {
|
const market: DealTicketQuery_market = {
|
||||||
__typename: 'Market',
|
__typename: 'Market',
|
||||||
id: 'market-id',
|
id: 'market-id',
|
||||||
|
name: 'market-name',
|
||||||
decimalPlaces: 2,
|
decimalPlaces: 2,
|
||||||
positionDecimalPlaces: 1,
|
positionDecimalPlaces: 1,
|
||||||
tradingMode: MarketTradingMode.Continuous,
|
tradingMode: MarketTradingMode.Continuous,
|
||||||
@ -24,6 +25,12 @@ const market: DealTicketQuery_market = {
|
|||||||
product: {
|
product: {
|
||||||
__typename: 'Future',
|
__typename: 'Future',
|
||||||
quoteName: 'quote-name',
|
quoteName: 'quote-name',
|
||||||
|
settlementAsset: {
|
||||||
|
__typename: 'Asset',
|
||||||
|
id: 'asset-id',
|
||||||
|
name: 'asset-name',
|
||||||
|
symbol: 'asset-symbol',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -77,7 +77,7 @@ export const DealTicket = ({
|
|||||||
/>
|
/>
|
||||||
<DealTicketAmount
|
<DealTicketAmount
|
||||||
orderType={orderType}
|
orderType={orderType}
|
||||||
step={0.02}
|
step={step}
|
||||||
register={register}
|
register={register}
|
||||||
price={
|
price={
|
||||||
market.depth.lastTrade
|
market.depth.lastTrade
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
import { Icon, Loader } from '@vegaprotocol/ui-toolkit';
|
import { Icon, Loader } from '@vegaprotocol/ui-toolkit';
|
||||||
import type { ReactNode } from 'react';
|
import type { ReactNode } from 'react';
|
||||||
import type { OrderEvent_busEvents_event_Order } from './__generated__/OrderEvent';
|
import {
|
||||||
import { addDecimalsFormatNumber, t } from '@vegaprotocol/react-helpers';
|
addDecimal,
|
||||||
|
addDecimalsFormatNumber,
|
||||||
|
t,
|
||||||
|
} from '@vegaprotocol/react-helpers';
|
||||||
import type { VegaTxState } from '@vegaprotocol/wallet';
|
import type { VegaTxState } from '@vegaprotocol/wallet';
|
||||||
import { VegaTxStatus } from '@vegaprotocol/wallet';
|
import { VegaTxStatus } from '@vegaprotocol/wallet';
|
||||||
|
import type { OrderEvent_busEvents_event_Order } from '../hooks/__generated__/OrderEvent';
|
||||||
|
|
||||||
interface OrderDialogProps {
|
interface OrderDialogProps {
|
||||||
transaction: VegaTxState;
|
transaction: VegaTxState;
|
||||||
@ -14,9 +18,22 @@ export const OrderDialog = ({
|
|||||||
transaction,
|
transaction,
|
||||||
finalizedOrder,
|
finalizedOrder,
|
||||||
}: OrderDialogProps) => {
|
}: OrderDialogProps) => {
|
||||||
// TODO: When wallets support confirming transactions return UI for 'awaiting confirmation' step
|
|
||||||
|
|
||||||
// Rejected by wallet
|
// Rejected by wallet
|
||||||
|
if (transaction.status === VegaTxStatus.Requested) {
|
||||||
|
return (
|
||||||
|
<OrderDialogWrapper
|
||||||
|
title="Confirm transaction in wallet"
|
||||||
|
icon={<Icon name="hand-up" size={20} />}
|
||||||
|
>
|
||||||
|
<p>
|
||||||
|
Please open your wallet application and confirm or reject the
|
||||||
|
transaction
|
||||||
|
</p>
|
||||||
|
</OrderDialogWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transaction error
|
||||||
if (transaction.status === VegaTxStatus.Error) {
|
if (transaction.status === VegaTxStatus.Error) {
|
||||||
return (
|
return (
|
||||||
<OrderDialogWrapper
|
<OrderDialogWrapper
|
||||||
@ -72,7 +89,14 @@ export const OrderDialog = ({
|
|||||||
<p>{t(`Market: ${finalizedOrder.market.name}`)}</p>
|
<p>{t(`Market: ${finalizedOrder.market.name}`)}</p>
|
||||||
)}
|
)}
|
||||||
<p>{t(`Type: ${finalizedOrder.type}`)}</p>
|
<p>{t(`Type: ${finalizedOrder.type}`)}</p>
|
||||||
<p>{t(`Amount: ${finalizedOrder.size}`)}</p>
|
<p>
|
||||||
|
{t(
|
||||||
|
`Amount: ${addDecimal(
|
||||||
|
finalizedOrder.size,
|
||||||
|
finalizedOrder.market?.positionDecimalPlaces || 0
|
||||||
|
)}`
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
{finalizedOrder.type === 'Limit' && finalizedOrder.market && (
|
{finalizedOrder.type === 'Limit' && finalizedOrder.market && (
|
||||||
<p>
|
<p>
|
||||||
{t(
|
{t(
|
||||||
|
@ -36,6 +36,12 @@ export interface OrderEvent_busEvents_event_Order_market {
|
|||||||
* GBX (pence) 1 4 GBP 0.000001 ( 0.0001p)
|
* GBX (pence) 1 4 GBP 0.000001 ( 0.0001p)
|
||||||
*/
|
*/
|
||||||
decimalPlaces: number;
|
decimalPlaces: number;
|
||||||
|
/**
|
||||||
|
* positionDecimalPlaces indicated the number of decimal places that an integer must be shifted in order to get a correct size (uint64).
|
||||||
|
* i.e. 0 means there are no fractional orders for the market, and order sizes are always whole sizes.
|
||||||
|
* 2 means sizes given as 10^2 * desired size, e.g. a desired size of 1.23 is represented as 123 in this market.
|
||||||
|
*/
|
||||||
|
positionDecimalPlaces: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OrderEvent_busEvents_event_Order {
|
export interface OrderEvent_busEvents_event_Order {
|
||||||
|
@ -4,12 +4,12 @@ import type { Order } from '../utils/get-default-order';
|
|||||||
import { OrderType, useVegaWallet } from '@vegaprotocol/wallet';
|
import { OrderType, useVegaWallet } from '@vegaprotocol/wallet';
|
||||||
import { determineId, removeDecimal } from '@vegaprotocol/react-helpers';
|
import { determineId, removeDecimal } from '@vegaprotocol/react-helpers';
|
||||||
import { useVegaTransaction } from '@vegaprotocol/wallet';
|
import { useVegaTransaction } from '@vegaprotocol/wallet';
|
||||||
|
import type { DealTicketQuery_market } from '../components/__generated__/DealTicketQuery';
|
||||||
import type {
|
import type {
|
||||||
OrderEvent,
|
OrderEvent,
|
||||||
OrderEventVariables,
|
OrderEventVariables,
|
||||||
OrderEvent_busEvents_event_Order,
|
OrderEvent_busEvents_event_Order,
|
||||||
} from '../components/__generated__/OrderEvent';
|
} from './__generated__/OrderEvent';
|
||||||
import type { DealTicketQuery_market } from '../components/__generated__/DealTicketQuery';
|
|
||||||
|
|
||||||
const ORDER_EVENT_SUB = gql`
|
const ORDER_EVENT_SUB = gql`
|
||||||
subscription OrderEvent($partyId: ID!) {
|
subscription OrderEvent($partyId: ID!) {
|
||||||
@ -29,6 +29,7 @@ const ORDER_EVENT_SUB = gql`
|
|||||||
market {
|
market {
|
||||||
name
|
name
|
||||||
decimalPlaces
|
decimalPlaces
|
||||||
|
positionDecimalPlaces
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -132,6 +132,12 @@ export interface MarketDepth_market {
|
|||||||
* GBX (pence) 1 4 GBP 0.000001 ( 0.0001p)
|
* GBX (pence) 1 4 GBP 0.000001 ( 0.0001p)
|
||||||
*/
|
*/
|
||||||
decimalPlaces: number;
|
decimalPlaces: number;
|
||||||
|
/**
|
||||||
|
* positionDecimalPlaces indicated the number of decimal places that an integer must be shifted in order to get a correct size (uint64).
|
||||||
|
* i.e. 0 means there are no fractional orders for the market, and order sizes are always whole sizes.
|
||||||
|
* 2 means sizes given as 10^2 * desired size, e.g. a desired size of 1.23 is represented as 123 in this market.
|
||||||
|
*/
|
||||||
|
positionDecimalPlaces: number;
|
||||||
/**
|
/**
|
||||||
* marketData for the given market
|
* marketData for the given market
|
||||||
*/
|
*/
|
||||||
|
@ -55,6 +55,12 @@ export interface MarketDepthSubscription_marketDepthUpdate_market {
|
|||||||
* Market ID
|
* Market ID
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
/**
|
||||||
|
* positionDecimalPlaces indicated the number of decimal places that an integer must be shifted in order to get a correct size (uint64).
|
||||||
|
* i.e. 0 means there are no fractional orders for the market, and order sizes are always whole sizes.
|
||||||
|
* 2 means sizes given as 10^2 * desired size, e.g. a desired size of 1.23 is represented as 123 in this market.
|
||||||
|
*/
|
||||||
|
positionDecimalPlaces: number;
|
||||||
/**
|
/**
|
||||||
* marketData for the given market
|
* marketData for the given market
|
||||||
*/
|
*/
|
||||||
|
@ -16,6 +16,7 @@ const MARKET_DEPTH_QUERY = gql`
|
|||||||
market(id: $marketId) {
|
market(id: $marketId) {
|
||||||
id
|
id
|
||||||
decimalPlaces
|
decimalPlaces
|
||||||
|
positionDecimalPlaces
|
||||||
data {
|
data {
|
||||||
staticMidPrice
|
staticMidPrice
|
||||||
marketTradingMode
|
marketTradingMode
|
||||||
@ -52,6 +53,7 @@ export const MARKET_DEPTH_SUBSCRIPTION_QUERY = gql`
|
|||||||
marketDepthUpdate(marketId: $marketId) {
|
marketDepthUpdate(marketId: $marketId) {
|
||||||
market {
|
market {
|
||||||
id
|
id
|
||||||
|
positionDecimalPlaces
|
||||||
data {
|
data {
|
||||||
staticMidPrice
|
staticMidPrice
|
||||||
marketTradingMode
|
marketTradingMode
|
||||||
|
@ -82,6 +82,7 @@ export const OrderbookManager = ({ marketId }: OrderbookManagerProps) => {
|
|||||||
<Orderbook
|
<Orderbook
|
||||||
{...orderbookData}
|
{...orderbookData}
|
||||||
decimalPlaces={data?.decimalPlaces ?? 0}
|
decimalPlaces={data?.decimalPlaces ?? 0}
|
||||||
|
positionDecimalPlaces={data?.positionDecimalPlaces ?? 0}
|
||||||
resolution={resolution}
|
resolution={resolution}
|
||||||
onResolutionChange={(resolution: number) => setResolution(resolution)}
|
onResolutionChange={(resolution: number) => setResolution(resolution)}
|
||||||
/>
|
/>
|
||||||
|
@ -5,6 +5,7 @@ import {
|
|||||||
CumulativeVol,
|
CumulativeVol,
|
||||||
addDecimalsFormatNumber,
|
addDecimalsFormatNumber,
|
||||||
VolumeType,
|
VolumeType,
|
||||||
|
addDecimal,
|
||||||
} from '@vegaprotocol/react-helpers';
|
} from '@vegaprotocol/react-helpers';
|
||||||
|
|
||||||
interface OrderbookRowProps {
|
interface OrderbookRowProps {
|
||||||
@ -15,6 +16,7 @@ interface OrderbookRowProps {
|
|||||||
cumulativeRelativeAsk?: number;
|
cumulativeRelativeAsk?: number;
|
||||||
cumulativeRelativeBid?: number;
|
cumulativeRelativeBid?: number;
|
||||||
decimalPlaces: number;
|
decimalPlaces: number;
|
||||||
|
positionDecimalPlaces: number;
|
||||||
indicativeVolume?: string;
|
indicativeVolume?: string;
|
||||||
price: string;
|
price: string;
|
||||||
relativeAsk?: number;
|
relativeAsk?: number;
|
||||||
@ -30,6 +32,7 @@ export const OrderbookRow = React.memo(
|
|||||||
cumulativeRelativeAsk,
|
cumulativeRelativeAsk,
|
||||||
cumulativeRelativeBid,
|
cumulativeRelativeBid,
|
||||||
decimalPlaces,
|
decimalPlaces,
|
||||||
|
positionDecimalPlaces,
|
||||||
indicativeVolume,
|
indicativeVolume,
|
||||||
price,
|
price,
|
||||||
relativeAsk,
|
relativeAsk,
|
||||||
@ -40,6 +43,7 @@ export const OrderbookRow = React.memo(
|
|||||||
<Vol
|
<Vol
|
||||||
testId={`bid-vol-${price}`}
|
testId={`bid-vol-${price}`}
|
||||||
value={bid}
|
value={bid}
|
||||||
|
valueFormatted={addDecimal(bid, positionDecimalPlaces)}
|
||||||
relativeValue={relativeBid}
|
relativeValue={relativeBid}
|
||||||
type={VolumeType.bid}
|
type={VolumeType.bid}
|
||||||
/>
|
/>
|
||||||
@ -51,6 +55,7 @@ export const OrderbookRow = React.memo(
|
|||||||
<Vol
|
<Vol
|
||||||
testId={`ask-vol-${price}`}
|
testId={`ask-vol-${price}`}
|
||||||
value={ask}
|
value={ask}
|
||||||
|
valueFormatted={addDecimal(ask, positionDecimalPlaces)}
|
||||||
relativeValue={relativeAsk}
|
relativeValue={relativeAsk}
|
||||||
type={VolumeType.ask}
|
type={VolumeType.ask}
|
||||||
/>
|
/>
|
||||||
|
@ -22,6 +22,7 @@ describe('Orderbook', () => {
|
|||||||
const result = render(
|
const result = render(
|
||||||
<Orderbook
|
<Orderbook
|
||||||
decimalPlaces={decimalPlaces}
|
decimalPlaces={decimalPlaces}
|
||||||
|
positionDecimalPlaces={0}
|
||||||
{...generateMockData(params)}
|
{...generateMockData(params)}
|
||||||
onResolutionChange={onResolutionChange}
|
onResolutionChange={onResolutionChange}
|
||||||
/>
|
/>
|
||||||
@ -35,6 +36,7 @@ describe('Orderbook', () => {
|
|||||||
const result = render(
|
const result = render(
|
||||||
<Orderbook
|
<Orderbook
|
||||||
decimalPlaces={decimalPlaces}
|
decimalPlaces={decimalPlaces}
|
||||||
|
positionDecimalPlaces={0}
|
||||||
{...generateMockData(params)}
|
{...generateMockData(params)}
|
||||||
onResolutionChange={onResolutionChange}
|
onResolutionChange={onResolutionChange}
|
||||||
/>
|
/>
|
||||||
@ -44,6 +46,7 @@ describe('Orderbook', () => {
|
|||||||
result.rerender(
|
result.rerender(
|
||||||
<Orderbook
|
<Orderbook
|
||||||
decimalPlaces={decimalPlaces}
|
decimalPlaces={decimalPlaces}
|
||||||
|
positionDecimalPlaces={0}
|
||||||
{...generateMockData({
|
{...generateMockData({
|
||||||
...params,
|
...params,
|
||||||
numberOfSellRows: params.numberOfSellRows - 1,
|
numberOfSellRows: params.numberOfSellRows - 1,
|
||||||
@ -60,6 +63,7 @@ describe('Orderbook', () => {
|
|||||||
const result = render(
|
const result = render(
|
||||||
<Orderbook
|
<Orderbook
|
||||||
decimalPlaces={decimalPlaces}
|
decimalPlaces={decimalPlaces}
|
||||||
|
positionDecimalPlaces={0}
|
||||||
{...generateMockData(params)}
|
{...generateMockData(params)}
|
||||||
onResolutionChange={onResolutionChange}
|
onResolutionChange={onResolutionChange}
|
||||||
/>
|
/>
|
||||||
@ -69,6 +73,7 @@ describe('Orderbook', () => {
|
|||||||
result.rerender(
|
result.rerender(
|
||||||
<Orderbook
|
<Orderbook
|
||||||
decimalPlaces={decimalPlaces}
|
decimalPlaces={decimalPlaces}
|
||||||
|
positionDecimalPlaces={0}
|
||||||
{...generateMockData({
|
{...generateMockData({
|
||||||
...params,
|
...params,
|
||||||
bestStaticBidPrice: params.bestStaticBidPrice + 1,
|
bestStaticBidPrice: params.bestStaticBidPrice + 1,
|
||||||
@ -86,6 +91,7 @@ describe('Orderbook', () => {
|
|||||||
const result = render(
|
const result = render(
|
||||||
<Orderbook
|
<Orderbook
|
||||||
decimalPlaces={decimalPlaces}
|
decimalPlaces={decimalPlaces}
|
||||||
|
positionDecimalPlaces={0}
|
||||||
{...generateMockData(params)}
|
{...generateMockData(params)}
|
||||||
onResolutionChange={onResolutionChange}
|
onResolutionChange={onResolutionChange}
|
||||||
/>
|
/>
|
||||||
@ -98,6 +104,7 @@ describe('Orderbook', () => {
|
|||||||
result.rerender(
|
result.rerender(
|
||||||
<Orderbook
|
<Orderbook
|
||||||
decimalPlaces={decimalPlaces}
|
decimalPlaces={decimalPlaces}
|
||||||
|
positionDecimalPlaces={0}
|
||||||
{...generateMockData({
|
{...generateMockData({
|
||||||
...params,
|
...params,
|
||||||
numberOfSellRows: params.numberOfSellRows - 1,
|
numberOfSellRows: params.numberOfSellRows - 1,
|
||||||
@ -114,6 +121,7 @@ describe('Orderbook', () => {
|
|||||||
const result = render(
|
const result = render(
|
||||||
<Orderbook
|
<Orderbook
|
||||||
decimalPlaces={decimalPlaces}
|
decimalPlaces={decimalPlaces}
|
||||||
|
positionDecimalPlaces={0}
|
||||||
{...generateMockData(params)}
|
{...generateMockData(params)}
|
||||||
onResolutionChange={onResolutionChange}
|
onResolutionChange={onResolutionChange}
|
||||||
/>
|
/>
|
||||||
@ -134,6 +142,7 @@ describe('Orderbook', () => {
|
|||||||
const result = render(
|
const result = render(
|
||||||
<Orderbook
|
<Orderbook
|
||||||
decimalPlaces={decimalPlaces}
|
decimalPlaces={decimalPlaces}
|
||||||
|
positionDecimalPlaces={0}
|
||||||
{...generateMockData(params)}
|
{...generateMockData(params)}
|
||||||
onResolutionChange={onResolutionChange}
|
onResolutionChange={onResolutionChange}
|
||||||
/>
|
/>
|
||||||
@ -153,6 +162,7 @@ describe('Orderbook', () => {
|
|||||||
result.rerender(
|
result.rerender(
|
||||||
<Orderbook
|
<Orderbook
|
||||||
decimalPlaces={decimalPlaces}
|
decimalPlaces={decimalPlaces}
|
||||||
|
positionDecimalPlaces={0}
|
||||||
{...generateMockData({
|
{...generateMockData({
|
||||||
...params,
|
...params,
|
||||||
resolution: 10,
|
resolution: 10,
|
||||||
|
@ -19,6 +19,7 @@ import { Icon, Splash } from '@vegaprotocol/ui-toolkit';
|
|||||||
import type { OrderbookData, OrderbookRowData } from './orderbook-data';
|
import type { OrderbookData, OrderbookRowData } from './orderbook-data';
|
||||||
interface OrderbookProps extends OrderbookData {
|
interface OrderbookProps extends OrderbookData {
|
||||||
decimalPlaces: number;
|
decimalPlaces: number;
|
||||||
|
positionDecimalPlaces: number;
|
||||||
resolution: number;
|
resolution: number;
|
||||||
onResolutionChange: (resolution: number) => void;
|
onResolutionChange: (resolution: number) => void;
|
||||||
}
|
}
|
||||||
@ -100,6 +101,7 @@ export const Orderbook = ({
|
|||||||
indicativeVolume,
|
indicativeVolume,
|
||||||
indicativePrice,
|
indicativePrice,
|
||||||
decimalPlaces,
|
decimalPlaces,
|
||||||
|
positionDecimalPlaces,
|
||||||
resolution,
|
resolution,
|
||||||
onResolutionChange,
|
onResolutionChange,
|
||||||
}: OrderbookProps) => {
|
}: OrderbookProps) => {
|
||||||
@ -298,6 +300,7 @@ export const Orderbook = ({
|
|||||||
<OrderbookRow
|
<OrderbookRow
|
||||||
price={(BigInt(data.price) / BigInt(resolution)).toString()}
|
price={(BigInt(data.price) / BigInt(resolution)).toString()}
|
||||||
decimalPlaces={decimalPlaces - Math.log10(resolution)}
|
decimalPlaces={decimalPlaces - Math.log10(resolution)}
|
||||||
|
positionDecimalPlaces={positionDecimalPlaces}
|
||||||
bid={data.bid}
|
bid={data.bid}
|
||||||
relativeBid={data.relativeBid}
|
relativeBid={data.relativeBid}
|
||||||
cumulativeBid={data.cumulativeVol.bid}
|
cumulativeBid={data.cumulativeVol.bid}
|
||||||
|
@ -52,6 +52,12 @@ export interface OrderFields_market {
|
|||||||
* GBX (pence) 1 4 GBP 0.000001 ( 0.0001p)
|
* GBX (pence) 1 4 GBP 0.000001 ( 0.0001p)
|
||||||
*/
|
*/
|
||||||
decimalPlaces: number;
|
decimalPlaces: number;
|
||||||
|
/**
|
||||||
|
* positionDecimalPlaces indicated the number of decimal places that an integer must be shifted in order to get a correct size (uint64).
|
||||||
|
* i.e. 0 means there are no fractional orders for the market, and order sizes are always whole sizes.
|
||||||
|
* 2 means sizes given as 10^2 * desired size, e.g. a desired size of 1.23 is represented as 123 in this market.
|
||||||
|
*/
|
||||||
|
positionDecimalPlaces: number;
|
||||||
/**
|
/**
|
||||||
* An instance of or reference to a tradable instrument.
|
* An instance of or reference to a tradable instrument.
|
||||||
*/
|
*/
|
||||||
|
@ -52,6 +52,12 @@ export interface OrderSub_orders_market {
|
|||||||
* GBX (pence) 1 4 GBP 0.000001 ( 0.0001p)
|
* GBX (pence) 1 4 GBP 0.000001 ( 0.0001p)
|
||||||
*/
|
*/
|
||||||
decimalPlaces: number;
|
decimalPlaces: number;
|
||||||
|
/**
|
||||||
|
* positionDecimalPlaces indicated the number of decimal places that an integer must be shifted in order to get a correct size (uint64).
|
||||||
|
* i.e. 0 means there are no fractional orders for the market, and order sizes are always whole sizes.
|
||||||
|
* 2 means sizes given as 10^2 * desired size, e.g. a desired size of 1.23 is represented as 123 in this market.
|
||||||
|
*/
|
||||||
|
positionDecimalPlaces: number;
|
||||||
/**
|
/**
|
||||||
* An instance of or reference to a tradable instrument.
|
* An instance of or reference to a tradable instrument.
|
||||||
*/
|
*/
|
||||||
|
6
libs/order-list/src/lib/__generated__/Orders.ts
generated
6
libs/order-list/src/lib/__generated__/Orders.ts
generated
@ -52,6 +52,12 @@ export interface Orders_party_orders_market {
|
|||||||
* GBX (pence) 1 4 GBP 0.000001 ( 0.0001p)
|
* GBX (pence) 1 4 GBP 0.000001 ( 0.0001p)
|
||||||
*/
|
*/
|
||||||
decimalPlaces: number;
|
decimalPlaces: number;
|
||||||
|
/**
|
||||||
|
* positionDecimalPlaces indicated the number of decimal places that an integer must be shifted in order to get a correct size (uint64).
|
||||||
|
* i.e. 0 means there are no fractional orders for the market, and order sizes are always whole sizes.
|
||||||
|
* 2 means sizes given as 10^2 * desired size, e.g. a desired size of 1.23 is represented as 123 in this market.
|
||||||
|
*/
|
||||||
|
positionDecimalPlaces: number;
|
||||||
/**
|
/**
|
||||||
* An instance of or reference to a tradable instrument.
|
* An instance of or reference to a tradable instrument.
|
||||||
*/
|
*/
|
||||||
|
@ -25,6 +25,7 @@ const marketOrder: Orders_party_orders = {
|
|||||||
id: 'market-id',
|
id: 'market-id',
|
||||||
name: 'market-name',
|
name: 'market-name',
|
||||||
decimalPlaces: 2,
|
decimalPlaces: 2,
|
||||||
|
positionDecimalPlaces: 0,
|
||||||
tradableInstrument: {
|
tradableInstrument: {
|
||||||
__typename: 'TradableInstrument',
|
__typename: 'TradableInstrument',
|
||||||
instrument: {
|
instrument: {
|
||||||
@ -54,6 +55,7 @@ const limitOrder: Orders_party_orders = {
|
|||||||
id: 'market-id',
|
id: 'market-id',
|
||||||
name: 'market-name',
|
name: 'market-name',
|
||||||
decimalPlaces: 2,
|
decimalPlaces: 2,
|
||||||
|
positionDecimalPlaces: 2,
|
||||||
tradableInstrument: {
|
tradableInstrument: {
|
||||||
__typename: 'TradableInstrument',
|
__typename: 'TradableInstrument',
|
||||||
instrument: {
|
instrument: {
|
||||||
@ -62,11 +64,11 @@ const limitOrder: Orders_party_orders = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
size: '10',
|
size: '1000',
|
||||||
type: OrderType.Limit,
|
type: OrderType.Limit,
|
||||||
status: OrderStatus.Active,
|
status: OrderStatus.Active,
|
||||||
side: Side.Sell,
|
side: Side.Sell,
|
||||||
remaining: '5',
|
remaining: '500',
|
||||||
price: '12345',
|
price: '12345',
|
||||||
timeInForce: OrderTimeInForce.GTT,
|
timeInForce: OrderTimeInForce.GTT,
|
||||||
createdAt: new Date('2022-3-3').toISOString(),
|
createdAt: new Date('2022-3-3').toISOString(),
|
||||||
@ -122,10 +124,10 @@ it('Correct formatting applied for GTT limit order', async () => {
|
|||||||
const cells = screen.getAllByRole('gridcell');
|
const cells = screen.getAllByRole('gridcell');
|
||||||
const expectedValues = [
|
const expectedValues = [
|
||||||
limitOrder.market?.tradableInstrument.instrument.code,
|
limitOrder.market?.tradableInstrument.instrument.code,
|
||||||
'-10',
|
'-10.00',
|
||||||
limitOrder.type,
|
limitOrder.type,
|
||||||
limitOrder.status,
|
limitOrder.status,
|
||||||
'5',
|
'5.00',
|
||||||
formatNumber(limitOrder.price, limitOrder.market?.decimalPlaces ?? 0),
|
formatNumber(limitOrder.price, limitOrder.market?.decimalPlaces ?? 0),
|
||||||
`${limitOrder.timeInForce}: ${getDateTimeFormat().format(
|
`${limitOrder.timeInForce}: ${getDateTimeFormat().format(
|
||||||
new Date(limitOrder.expiresAt ?? '')
|
new Date(limitOrder.expiresAt ?? '')
|
||||||
|
@ -1,11 +1,17 @@
|
|||||||
import { OrderTimeInForce, OrderStatus, Side } from '@vegaprotocol/types';
|
import { OrderTimeInForce, OrderStatus, Side } from '@vegaprotocol/types';
|
||||||
import type { Orders_party_orders } from './__generated__/Orders';
|
import type { Orders_party_orders } from './__generated__/Orders';
|
||||||
import { formatNumber, getDateTimeFormat } from '@vegaprotocol/react-helpers';
|
import {
|
||||||
|
addDecimal,
|
||||||
|
formatNumber,
|
||||||
|
getDateTimeFormat,
|
||||||
|
t,
|
||||||
|
} from '@vegaprotocol/react-helpers';
|
||||||
import { AgGridDynamic as AgGrid } from '@vegaprotocol/ui-toolkit';
|
import { AgGridDynamic as AgGrid } from '@vegaprotocol/ui-toolkit';
|
||||||
import type { ValueFormatterParams } from 'ag-grid-community';
|
import type { ValueFormatterParams } from 'ag-grid-community';
|
||||||
import type { AgGridReact } from 'ag-grid-react';
|
import type { AgGridReact } from 'ag-grid-react';
|
||||||
import { AgGridColumn } from 'ag-grid-react';
|
import { AgGridColumn } from 'ag-grid-react';
|
||||||
import { forwardRef } from 'react';
|
import { forwardRef } from 'react';
|
||||||
|
import BigNumber from 'bignumber.js';
|
||||||
|
|
||||||
interface OrderListProps {
|
interface OrderListProps {
|
||||||
data: Orders_party_orders[] | null;
|
data: Orders_party_orders[] | null;
|
||||||
@ -23,16 +29,18 @@ export const OrderList = forwardRef<AgGridReact, OrderListProps>(
|
|||||||
getRowId={({ data }) => data.id}
|
getRowId={({ data }) => data.id}
|
||||||
>
|
>
|
||||||
<AgGridColumn
|
<AgGridColumn
|
||||||
headerName="Market"
|
headerName={t('Market')}
|
||||||
field="market.tradableInstrument.instrument.code"
|
field="market.tradableInstrument.instrument.code"
|
||||||
/>
|
/>
|
||||||
<AgGridColumn
|
<AgGridColumn
|
||||||
headerName="Amount"
|
headerName={t('Amount')}
|
||||||
field="size"
|
field="size"
|
||||||
cellClass="font-mono"
|
cellClass="font-mono"
|
||||||
valueFormatter={({ value, data }: ValueFormatterParams) => {
|
valueFormatter={({ value, data }: ValueFormatterParams) => {
|
||||||
const prefix = data.side === Side.Buy ? '+' : '-';
|
const prefix = data.side === Side.Buy ? '+' : '-';
|
||||||
return prefix + value;
|
return (
|
||||||
|
prefix + addDecimal(value, data.market.positionDecimalPlaces)
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<AgGridColumn field="type" />
|
<AgGridColumn field="type" />
|
||||||
@ -47,11 +55,18 @@ export const OrderList = forwardRef<AgGridReact, OrderListProps>(
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<AgGridColumn
|
<AgGridColumn
|
||||||
headerName="Filled"
|
headerName={t('Filled')}
|
||||||
field="remaining"
|
field="remaining"
|
||||||
cellClass="font-mono"
|
cellClass="font-mono"
|
||||||
valueFormatter={({ data }: ValueFormatterParams) => {
|
valueFormatter={({ data }: ValueFormatterParams) => {
|
||||||
return `${Number(data.size) - Number(data.remaining)}/${data.size}`;
|
const dps = data.market.positionDecimalPlaces;
|
||||||
|
const size = new BigNumber(data.size);
|
||||||
|
const remaining = new BigNumber(data.remaining);
|
||||||
|
const fills = size.minus(remaining);
|
||||||
|
return `${addDecimal(fills.toString(), dps)}/${addDecimal(
|
||||||
|
size.toString(),
|
||||||
|
dps
|
||||||
|
)}`;
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<AgGridColumn
|
<AgGridColumn
|
||||||
|
@ -13,6 +13,7 @@ const ORDER_FRAGMENT = gql`
|
|||||||
id
|
id
|
||||||
name
|
name
|
||||||
decimalPlaces
|
decimalPlaces
|
||||||
|
positionDecimalPlaces
|
||||||
tradableInstrument {
|
tradableInstrument {
|
||||||
instrument {
|
instrument {
|
||||||
code
|
code
|
||||||
|
@ -136,6 +136,12 @@ export interface PositionDetails_market {
|
|||||||
* GBX (pence) 1 4 GBP 0.000001 ( 0.0001p)
|
* GBX (pence) 1 4 GBP 0.000001 ( 0.0001p)
|
||||||
*/
|
*/
|
||||||
decimalPlaces: number;
|
decimalPlaces: number;
|
||||||
|
/**
|
||||||
|
* positionDecimalPlaces indicated the number of decimal places that an integer must be shifted in order to get a correct size (uint64).
|
||||||
|
* i.e. 0 means there are no fractional orders for the market, and order sizes are always whole sizes.
|
||||||
|
* 2 means sizes given as 10^2 * desired size, e.g. a desired size of 1.23 is represented as 123 in this market.
|
||||||
|
*/
|
||||||
|
positionDecimalPlaces: number;
|
||||||
/**
|
/**
|
||||||
* An instance of or reference to a tradable instrument.
|
* An instance of or reference to a tradable instrument.
|
||||||
*/
|
*/
|
||||||
|
@ -136,6 +136,12 @@ export interface PositionSubscribe_positions_market {
|
|||||||
* GBX (pence) 1 4 GBP 0.000001 ( 0.0001p)
|
* GBX (pence) 1 4 GBP 0.000001 ( 0.0001p)
|
||||||
*/
|
*/
|
||||||
decimalPlaces: number;
|
decimalPlaces: number;
|
||||||
|
/**
|
||||||
|
* positionDecimalPlaces indicated the number of decimal places that an integer must be shifted in order to get a correct size (uint64).
|
||||||
|
* i.e. 0 means there are no fractional orders for the market, and order sizes are always whole sizes.
|
||||||
|
* 2 means sizes given as 10^2 * desired size, e.g. a desired size of 1.23 is represented as 123 in this market.
|
||||||
|
*/
|
||||||
|
positionDecimalPlaces: number;
|
||||||
/**
|
/**
|
||||||
* An instance of or reference to a tradable instrument.
|
* An instance of or reference to a tradable instrument.
|
||||||
*/
|
*/
|
||||||
|
@ -136,6 +136,12 @@ export interface Positions_party_positions_market {
|
|||||||
* GBX (pence) 1 4 GBP 0.000001 ( 0.0001p)
|
* GBX (pence) 1 4 GBP 0.000001 ( 0.0001p)
|
||||||
*/
|
*/
|
||||||
decimalPlaces: number;
|
decimalPlaces: number;
|
||||||
|
/**
|
||||||
|
* positionDecimalPlaces indicated the number of decimal places that an integer must be shifted in order to get a correct size (uint64).
|
||||||
|
* i.e. 0 means there are no fractional orders for the market, and order sizes are always whole sizes.
|
||||||
|
* 2 means sizes given as 10^2 * desired size, e.g. a desired size of 1.23 is represented as 123 in this market.
|
||||||
|
*/
|
||||||
|
positionDecimalPlaces: number;
|
||||||
/**
|
/**
|
||||||
* An instance of or reference to a tradable instrument.
|
* An instance of or reference to a tradable instrument.
|
||||||
*/
|
*/
|
||||||
|
@ -27,6 +27,7 @@ const POSITIONS_FRAGMENT = gql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
decimalPlaces
|
decimalPlaces
|
||||||
|
positionDecimalPlaces
|
||||||
tradableInstrument {
|
tradableInstrument {
|
||||||
instrument {
|
instrument {
|
||||||
id
|
id
|
||||||
|
@ -5,7 +5,7 @@ import { MarketTradingMode } from '@vegaprotocol/types';
|
|||||||
|
|
||||||
const singleRow: Positions_party_positions = {
|
const singleRow: Positions_party_positions = {
|
||||||
realisedPNL: '520000000',
|
realisedPNL: '520000000',
|
||||||
openVolume: '100',
|
openVolume: '10000',
|
||||||
unrealisedPNL: '895000',
|
unrealisedPNL: '895000',
|
||||||
averageEntryPrice: '1129935',
|
averageEntryPrice: '1129935',
|
||||||
market: {
|
market: {
|
||||||
@ -17,6 +17,7 @@ const singleRow: Positions_party_positions = {
|
|||||||
__typename: 'MarketData',
|
__typename: 'MarketData',
|
||||||
market: { __typename: 'Market', id: '123' },
|
market: { __typename: 'Market', id: '123' },
|
||||||
},
|
},
|
||||||
|
positionDecimalPlaces: 2,
|
||||||
decimalPlaces: 5,
|
decimalPlaces: 5,
|
||||||
tradableInstrument: {
|
tradableInstrument: {
|
||||||
instrument: {
|
instrument: {
|
||||||
@ -90,7 +91,7 @@ it('Correct formatting applied', async () => {
|
|||||||
const cells = screen.getAllByRole('gridcell');
|
const cells = screen.getAllByRole('gridcell');
|
||||||
const expectedValues = [
|
const expectedValues = [
|
||||||
singleRow.market.tradableInstrument.instrument.code,
|
singleRow.market.tradableInstrument.instrument.code,
|
||||||
'+100',
|
'+100.00',
|
||||||
'11.29935',
|
'11.29935',
|
||||||
'11.38885',
|
'11.38885',
|
||||||
'+5,200.000',
|
'+5,200.000',
|
||||||
|
@ -88,8 +88,11 @@ export const PositionsTable = forwardRef<AgGridReact, PositionsTableProps>(
|
|||||||
<AgGridColumn
|
<AgGridColumn
|
||||||
headerName={t('Amount')}
|
headerName={t('Amount')}
|
||||||
field="openVolume"
|
field="openVolume"
|
||||||
valueFormatter={({ value }: PositionsTableValueFormatterParams) =>
|
valueFormatter={({
|
||||||
volumePrefix(value)
|
value,
|
||||||
|
data,
|
||||||
|
}: PositionsTableValueFormatterParams) =>
|
||||||
|
volumePrefix(addDecimal(value, data.market.positionDecimalPlaces))
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<AgGridColumn
|
<AgGridColumn
|
||||||
|
@ -1,19 +1,6 @@
|
|||||||
import once from 'lodash/once';
|
import once from 'lodash/once';
|
||||||
import { getUserLocale } from './utils';
|
import { getUserLocale } from './utils';
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a number prefixed with either a '-' or a '+'. The open volume field
|
|
||||||
* already comes with a '-' if negative so we only need to actually prefix if
|
|
||||||
* its a positive value
|
|
||||||
*/
|
|
||||||
export function volumePrefix(value: string): string {
|
|
||||||
if (value === '0' || value.startsWith('-')) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return '+' + value;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getTimeFormat = once(
|
export const getTimeFormat = once(
|
||||||
() =>
|
() =>
|
||||||
new Intl.DateTimeFormat(getUserLocale(), {
|
new Intl.DateTimeFormat(getUserLocale(), {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
export * from './date';
|
export * from './date';
|
||||||
export * from './number';
|
export * from './number';
|
||||||
export * from './truncate';
|
export * from './truncate';
|
||||||
|
export * from './size';
|
||||||
export * from './utils';
|
export * from './utils';
|
||||||
|
12
libs/react-helpers/src/lib/format/size.ts
Normal file
12
libs/react-helpers/src/lib/format/size.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
/**
|
||||||
|
* Returns a number prefixed with either a '-' or a '+'. The open volume field
|
||||||
|
* already comes with a '-' if negative so we only need to actually prefix if
|
||||||
|
* its a positive value
|
||||||
|
*/
|
||||||
|
export function volumePrefix(value: string): string {
|
||||||
|
if (value === '0' || value.startsWith('-')) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return '+' + value;
|
||||||
|
}
|
@ -9,6 +9,7 @@ export enum VolumeType {
|
|||||||
}
|
}
|
||||||
export interface VolProps {
|
export interface VolProps {
|
||||||
value: number | bigint | null | undefined;
|
value: number | bigint | null | undefined;
|
||||||
|
valueFormatted: string;
|
||||||
relativeValue?: number;
|
relativeValue?: number;
|
||||||
type: VolumeType;
|
type: VolumeType;
|
||||||
testId?: string;
|
testId?: string;
|
||||||
@ -22,7 +23,7 @@ export const BID_COLOR = 'darkgreen';
|
|||||||
export const ASK_COLOR = 'maroon';
|
export const ASK_COLOR = 'maroon';
|
||||||
|
|
||||||
export const Vol = React.memo(
|
export const Vol = React.memo(
|
||||||
({ value, relativeValue, type, testId }: VolProps) => {
|
({ value, valueFormatted, relativeValue, type, testId }: VolProps) => {
|
||||||
if ((!value && value !== 0) || isNaN(Number(value))) {
|
if ((!value && value !== 0) || isNaN(Number(value))) {
|
||||||
return <div data-testid="vol">-</div>;
|
return <div data-testid="vol">-</div>;
|
||||||
}
|
}
|
||||||
@ -38,7 +39,7 @@ export const Vol = React.memo(
|
|||||||
backgroundColor: type === VolumeType.bid ? BID_COLOR : ASK_COLOR,
|
backgroundColor: type === VolumeType.bid ? BID_COLOR : ASK_COLOR,
|
||||||
}}
|
}}
|
||||||
></div>
|
></div>
|
||||||
<PriceCell value={value} valueFormatted={value.toString()} />
|
<PriceCell value={value} valueFormatted={valueFormatted} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
6
libs/trades/src/lib/__generated__/TradeFields.ts
generated
6
libs/trades/src/lib/__generated__/TradeFields.ts
generated
@ -30,6 +30,12 @@ export interface TradeFields_market {
|
|||||||
* GBX (pence) 1 4 GBP 0.000001 ( 0.0001p)
|
* GBX (pence) 1 4 GBP 0.000001 ( 0.0001p)
|
||||||
*/
|
*/
|
||||||
decimalPlaces: number;
|
decimalPlaces: number;
|
||||||
|
/**
|
||||||
|
* positionDecimalPlaces indicated the number of decimal places that an integer must be shifted in order to get a correct size (uint64).
|
||||||
|
* i.e. 0 means there are no fractional orders for the market, and order sizes are always whole sizes.
|
||||||
|
* 2 means sizes given as 10^2 * desired size, e.g. a desired size of 1.23 is represented as 123 in this market.
|
||||||
|
*/
|
||||||
|
positionDecimalPlaces: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TradeFields {
|
export interface TradeFields {
|
||||||
|
6
libs/trades/src/lib/__generated__/Trades.ts
generated
6
libs/trades/src/lib/__generated__/Trades.ts
generated
@ -30,6 +30,12 @@ export interface Trades_market_trades_market {
|
|||||||
* GBX (pence) 1 4 GBP 0.000001 ( 0.0001p)
|
* GBX (pence) 1 4 GBP 0.000001 ( 0.0001p)
|
||||||
*/
|
*/
|
||||||
decimalPlaces: number;
|
decimalPlaces: number;
|
||||||
|
/**
|
||||||
|
* positionDecimalPlaces indicated the number of decimal places that an integer must be shifted in order to get a correct size (uint64).
|
||||||
|
* i.e. 0 means there are no fractional orders for the market, and order sizes are always whole sizes.
|
||||||
|
* 2 means sizes given as 10^2 * desired size, e.g. a desired size of 1.23 is represented as 123 in this market.
|
||||||
|
*/
|
||||||
|
positionDecimalPlaces: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Trades_market_trades {
|
export interface Trades_market_trades {
|
||||||
|
6
libs/trades/src/lib/__generated__/TradesSub.ts
generated
6
libs/trades/src/lib/__generated__/TradesSub.ts
generated
@ -30,6 +30,12 @@ export interface TradesSub_trades_market {
|
|||||||
* GBX (pence) 1 4 GBP 0.000001 ( 0.0001p)
|
* GBX (pence) 1 4 GBP 0.000001 ( 0.0001p)
|
||||||
*/
|
*/
|
||||||
decimalPlaces: number;
|
decimalPlaces: number;
|
||||||
|
/**
|
||||||
|
* positionDecimalPlaces indicated the number of decimal places that an integer must be shifted in order to get a correct size (uint64).
|
||||||
|
* i.e. 0 means there are no fractional orders for the market, and order sizes are always whole sizes.
|
||||||
|
* 2 means sizes given as 10^2 * desired size, e.g. a desired size of 1.23 is represented as 123 in this market.
|
||||||
|
*/
|
||||||
|
positionDecimalPlaces: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TradesSub_trades {
|
export interface TradesSub_trades {
|
||||||
|
@ -16,6 +16,7 @@ const TRADES_FRAGMENT = gql`
|
|||||||
market {
|
market {
|
||||||
id
|
id
|
||||||
decimalPlaces
|
decimalPlaces
|
||||||
|
positionDecimalPlaces
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -7,12 +7,13 @@ const trade: TradeFields = {
|
|||||||
__typename: 'Trade',
|
__typename: 'Trade',
|
||||||
id: 'trade-id',
|
id: 'trade-id',
|
||||||
price: '111122200',
|
price: '111122200',
|
||||||
size: '20',
|
size: '2000',
|
||||||
createdAt: new Date('2022-04-06T19:00:00').toISOString(),
|
createdAt: new Date('2022-04-06T19:00:00').toISOString(),
|
||||||
market: {
|
market: {
|
||||||
__typename: 'Market',
|
__typename: 'Market',
|
||||||
id: 'market-id',
|
id: 'market-id',
|
||||||
decimalPlaces: 2,
|
decimalPlaces: 2,
|
||||||
|
positionDecimalPlaces: 2,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -34,7 +35,7 @@ it('Number and data columns are formatted', async () => {
|
|||||||
const cells = screen.getAllByRole('gridcell');
|
const cells = screen.getAllByRole('gridcell');
|
||||||
const expectedValues = [
|
const expectedValues = [
|
||||||
'1,111,222.00',
|
'1,111,222.00',
|
||||||
'20',
|
'20.00',
|
||||||
getDateTimeFormat().format(new Date(trade.createdAt)),
|
getDateTimeFormat().format(new Date(trade.createdAt)),
|
||||||
];
|
];
|
||||||
cells.forEach((cell, i) => {
|
cells.forEach((cell, i) => {
|
||||||
|
@ -4,6 +4,7 @@ import { forwardRef, useMemo } from 'react';
|
|||||||
import { AgGridDynamic as AgGrid } from '@vegaprotocol/ui-toolkit';
|
import { AgGridDynamic as AgGrid } from '@vegaprotocol/ui-toolkit';
|
||||||
import type { TradeFields } from './__generated__/TradeFields';
|
import type { TradeFields } from './__generated__/TradeFields';
|
||||||
import {
|
import {
|
||||||
|
addDecimal,
|
||||||
addDecimalsFormatNumber,
|
addDecimalsFormatNumber,
|
||||||
getDateTimeFormat,
|
getDateTimeFormat,
|
||||||
t,
|
t,
|
||||||
@ -73,6 +74,9 @@ export const TradesTable = forwardRef<AgGridReact, TradesTableProps>(
|
|||||||
<AgGridColumn
|
<AgGridColumn
|
||||||
headerName={t('Size')}
|
headerName={t('Size')}
|
||||||
field="size"
|
field="size"
|
||||||
|
valueFormatter={({ value, data }: ValueFormatterParams) => {
|
||||||
|
return addDecimal(value, data.market.positionDecimalPlaces);
|
||||||
|
}}
|
||||||
cellClass={changeCellClass('size')}
|
cellClass={changeCellClass('size')}
|
||||||
/>
|
/>
|
||||||
<AgGridColumn
|
<AgGridColumn
|
||||||
|
@ -87,27 +87,28 @@ export class RestConnector implements VegaConnector {
|
|||||||
|
|
||||||
async sendTx(body: TransactionSubmission) {
|
async sendTx(body: TransactionSubmission) {
|
||||||
try {
|
try {
|
||||||
return await this.service.commandSyncPost(body);
|
const res = await this.service.commandSyncPost(body);
|
||||||
|
return res;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return this.handleSendTxError(err);
|
return this.handleSendTxError(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleSendTxError(err: unknown) {
|
private handleSendTxError(err: unknown) {
|
||||||
if (typeof err === 'object' && err && 'body' in err) {
|
const unpexpectedError = { error: 'Something went wrong' };
|
||||||
|
|
||||||
|
if (isServiceError(err)) {
|
||||||
|
if (err.code === 401) {
|
||||||
|
return { error: 'User rejected' };
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// @ts-ignore Not sure why TS can't infer that 'body' does indeed exist on object
|
return JSON.parse(err.body ?? '');
|
||||||
return JSON.parse(err.body);
|
|
||||||
} catch {
|
} catch {
|
||||||
// Unexpected response
|
return unpexpectedError;
|
||||||
return {
|
|
||||||
error: 'Something went wrong',
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return {
|
return unpexpectedError;
|
||||||
error: 'Something went wrong',
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,3 +133,17 @@ export class RestConnector implements VegaConnector {
|
|||||||
LocalStorage.removeItem(this.configKey);
|
LocalStorage.removeItem(this.configKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ServiceError {
|
||||||
|
code: number;
|
||||||
|
body: string | undefined;
|
||||||
|
headers: object;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const isServiceError = (err: unknown): err is ServiceError => {
|
||||||
|
// Some responses don't contain body object
|
||||||
|
if (typeof err === 'object' && err !== null && 'code' in err) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
@ -2,7 +2,11 @@ import { act, renderHook } from '@testing-library/react-hooks';
|
|||||||
import type { VegaWalletContextShape } from './context';
|
import type { VegaWalletContextShape } from './context';
|
||||||
import { VegaWalletContext } from './context';
|
import { VegaWalletContext } from './context';
|
||||||
import type { ReactNode } from 'react';
|
import type { ReactNode } from 'react';
|
||||||
import { useVegaTransaction, VegaTxStatus } from './use-vega-transaction';
|
import {
|
||||||
|
initialState,
|
||||||
|
useVegaTransaction,
|
||||||
|
VegaTxStatus,
|
||||||
|
} from './use-vega-transaction';
|
||||||
import type { OrderSubmission } from './types';
|
import type { OrderSubmission } from './types';
|
||||||
|
|
||||||
const defaultWalletContext = {
|
const defaultWalletContext = {
|
||||||
@ -94,3 +98,14 @@ it('Returns the signature if successful', async () => {
|
|||||||
successObj.tx.signature.value
|
successObj.tx.signature.value
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Resets transaction state if user rejects', async () => {
|
||||||
|
const mockSendTx = jest
|
||||||
|
.fn()
|
||||||
|
.mockReturnValue(Promise.resolve({ error: 'User rejected' }));
|
||||||
|
const { result } = setup({ sendTx: mockSendTx });
|
||||||
|
await act(async () => {
|
||||||
|
result.current.send({} as OrderSubmission);
|
||||||
|
});
|
||||||
|
expect(result.current.transaction).toEqual(initialState);
|
||||||
|
});
|
||||||
|
@ -44,6 +44,10 @@ export const useVegaTransaction = () => {
|
|||||||
[setTransaction]
|
[setTransaction]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const reset = useCallback(() => {
|
||||||
|
setTransaction(initialState);
|
||||||
|
}, [setTransaction]);
|
||||||
|
|
||||||
const send = useCallback(
|
const send = useCallback(
|
||||||
async (tx: TransactionSubmission) => {
|
async (tx: TransactionSubmission) => {
|
||||||
setTransaction({
|
setTransaction({
|
||||||
@ -61,7 +65,12 @@ export const useVegaTransaction = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ('error' in res) {
|
if ('error' in res) {
|
||||||
handleError(res);
|
// Close dialog if user rejects the transaction
|
||||||
|
if (res.error === 'User rejected') {
|
||||||
|
reset();
|
||||||
|
} else {
|
||||||
|
handleError(res);
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
} else if ('errors' in res) {
|
} else if ('errors' in res) {
|
||||||
handleError(res);
|
handleError(res);
|
||||||
@ -79,12 +88,8 @@ export const useVegaTransaction = () => {
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
[sendTx, handleError, setTransaction]
|
[sendTx, handleError, setTransaction, reset]
|
||||||
);
|
);
|
||||||
|
|
||||||
const reset = useCallback(() => {
|
|
||||||
setTransaction(initialState);
|
|
||||||
}, [setTransaction]);
|
|
||||||
|
|
||||||
return { send, transaction, reset };
|
return { send, transaction, reset };
|
||||||
};
|
};
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
"@sentry/nextjs": "^6.19.3",
|
"@sentry/nextjs": "^6.19.3",
|
||||||
"@sentry/react": "^6.19.2",
|
"@sentry/react": "^6.19.2",
|
||||||
"@sentry/tracing": "^6.19.2",
|
"@sentry/tracing": "^6.19.2",
|
||||||
"@vegaprotocol/vegawallet-service-api-client": "^0.4.12",
|
"@vegaprotocol/vegawallet-service-api-client": "^0.4.13",
|
||||||
"@walletconnect/ethereum-provider": "^1.7.5",
|
"@walletconnect/ethereum-provider": "^1.7.5",
|
||||||
"@web3-react/core": "8.0.20-beta.0",
|
"@web3-react/core": "8.0.20-beta.0",
|
||||||
"@web3-react/metamask": "8.0.16-beta.0",
|
"@web3-react/metamask": "8.0.16-beta.0",
|
||||||
|
@ -6750,10 +6750,10 @@
|
|||||||
"@typescript-eslint/types" "5.22.0"
|
"@typescript-eslint/types" "5.22.0"
|
||||||
eslint-visitor-keys "^3.0.0"
|
eslint-visitor-keys "^3.0.0"
|
||||||
|
|
||||||
"@vegaprotocol/vegawallet-service-api-client@^0.4.12":
|
"@vegaprotocol/vegawallet-service-api-client@^0.4.13":
|
||||||
version "0.4.12"
|
version "0.4.13"
|
||||||
resolved "https://registry.yarnpkg.com/@vegaprotocol/vegawallet-service-api-client/-/vegawallet-service-api-client-0.4.12.tgz#65551b9a4d2e00b2c2e9ca9619d95453954a0dbf"
|
resolved "https://registry.yarnpkg.com/@vegaprotocol/vegawallet-service-api-client/-/vegawallet-service-api-client-0.4.13.tgz#fb98ec0179ea6cc27e991ef3d3338327eca4f3c4"
|
||||||
integrity sha512-Z680W8rsjz2U8R/gss7+hI0eik0euDJLlh7LzWGXUJxUC3XWO9rwJmzlqN/ZlEB4L9OzSLTSZsvlBAGwiHzUSQ==
|
integrity sha512-YK6DsDKgvb+n9QwvKYSBQ51TDon0lGpLsNdNUa4oywIjubzWGVE4g98GrEmcP+UB/AfZzLA6A9ul7F/+TSep5Q==
|
||||||
dependencies:
|
dependencies:
|
||||||
es6-promise "^4.2.4"
|
es6-promise "^4.2.4"
|
||||||
url-parse "^1.4.3"
|
url-parse "^1.4.3"
|
||||||
|
Loading…
Reference in New Issue
Block a user