Feat/470 edit order (#742)

* feat: 470 edit orders hook and @vegaprotocol/vegawallet-service-api-client@0.4.14

* fix: 470 add methods for dialog intent and title

* fix: #657 rename order-list lib to orders

* chore: #657 move hooks to orders lib

* chore: #657 vega tx dialog used for order cancellation and order submission

* chore: #657 use client subscribe and unsubscribe on reset, refactor vegatxdialog

* fix: #657 revert script src=./env-config.js ending

* fix: #657 format project.json

* Update project.json

* fix: #657 cancel all subs and async tasks in useffect cleanup function

* feat: #657 styling updates on vega order dialog

* fix: #657 rename set dialog open and awaiting confirmation dialog update

* fix: #657 updates on cancel order id check

* fix:  #657 fix vega tx dialog test

* fix:  #657 fix cypress trading-deal-tciket test

* fix:  #657 fix data-testid market test

* fix: #470  add use order edit hook

* fix:  #470 edit order button

* Update libs/orders/README.md

Co-authored-by: Dexter Edwards <dexter.edwards93@gmail.com>

* Update libs/wallet/src/vega-order-transaction-dialog/vega-order-transaction-dialog.tsx

Co-authored-by: Dexter Edwards <dexter.edwards93@gmail.com>

* Update libs/wallet/src/vega-transaction-dialog/vega-transaction-dialog.tsx

Co-authored-by: Dexter Edwards <dexter.edwards93@gmail.com>

* Update libs/wallet/src/vega-order-transaction-dialog/vega-order-transaction-dialog.tsx

Co-authored-by: Dexter Edwards <dexter.edwards93@gmail.com>

* Update libs/wallet/src/vega-order-transaction-dialog/vega-order-transaction-dialog.tsx

Co-authored-by: Dexter Edwards <dexter.edwards93@gmail.com>

* fix: #657 remove the magic string and use the ordertype enum from types package

* fix: #657 guarantee that order.id is present at this point or we need to determine the id of the order

* fix: #657 fix translation in dialog

* fix: #657 rename wallet types, delete ticket query, set finalized order null in submit

* fix: #657 fix deal ticket steps test

* fix: #657 remove settings.json

* fix: #657 use order submit in orders lib

* fix: #470 open edit order modal and update storybook

* feat:  #470 edit modals set up

* fix: #463 final modal links to block explorer

* fix: #745 long/short instead of buy/sell

* fix: #657 use only one vega tx dialog

* fix: #657 keep ref of subscription and unsubscribe

* fix:  #657 hide cancelled orders

* fix: #657 sub only when id set

* fix: WIP: trying to unsub when order updated

* fix: #745 long/short instead of buy/sell

* fix: ensure observable defined

* fix: #657 remove redundant test

* fix: #470 merge with new order hooks

* fix: #470 fix use-order-edit no red update order-list with code

* fix:  #470 invert order show price last in dialog

* fix: #470 able to edit order

* fix: #470 fix dialog transition

* fix: #656  #609 show Continuous trading and market state from trade grid header

* fix: #603 filter out rejected markets

* fix: #603 filter out rejected markets

* fix:  #470 revert to 17.0.2 react

* fix:  #470 revert to 17.0.2 react

* fix: #603 filter out rejected markets & dialog lg width

* fix: #609 show trading mode Continuous Trading and hide market state

* fix: #656 modify order validation to trade when suspended

* fix: #656 fix use order validation tests

* fix: #656 format volume no

* fix: format volume with positionDecimalPlaces

* fix: tests don't need to be async

* fix: md:w-[720px] to prevent dialog overflow

* fix: add market state translations

* fix: imprt type validation props

* fix: #470 working edit submit on GTC not on GTT as it is missing expiresAt

* Update libs/orders/src/lib/order-hooks/use-order-validation.tsx

Co-authored-by: candida-d <62548908+candida-d@users.noreply.github.com>

* Update libs/orders/src/lib/order-hooks/use-order-validation.tsx

Co-authored-by: candida-d <62548908+candida-d@users.noreply.github.com>

* Update libs/orders/src/lib/order-hooks/use-order-validation.tsx

Co-authored-by: candida-d <62548908+candida-d@users.noreply.github.com>

* Update libs/orders/src/lib/order-hooks/use-order-validation.tsx

Co-authored-by: candida-d <62548908+candida-d@users.noreply.github.com>

* Update libs/orders/src/lib/order-hooks/use-order-validation.tsx

Co-authored-by: candida-d <62548908+candida-d@users.noreply.github.com>

* Update libs/orders/src/lib/order-hooks/use-order-validation.spec.tsx

Co-authored-by: candida-d <62548908+candida-d@users.noreply.github.com>

* Update apps/trading/pages/markets/__generated__/Market.ts

Co-authored-by: candida-d <62548908+candida-d@users.noreply.github.com>

* fix: fix warning messages based on feedback

* fix: capitalize trading mode

* fix: capitalize trading mode

* fix: remove line 72 on markets.cy.ts

* fix: don't show trigger if unspecified

* fix: format last price and shrink 0 on warning icon

* fix: order sizes must be whole numbers for this market and input warning size 20

* fix: order sizes must be whole numbers for this market and input warning size 20

* fix: format market list

* fix: #470 fix expiresAt and price unmarshall values

* fix: #470 fix expiresAt and price unmarshall values

* fix: #470 add extra test on editing order

* fix: pass child react node for order edit on vega tx default

* fix: status and rejection reason optional

* fix: add header transalations and remove commented line

* fix: simplify get list of markets

* fix: check if order.market undefined

* fix: remove cast and check market id

Co-authored-by: Dexter Edwards <dexter.edwards93@gmail.com>
Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
Co-authored-by: candida-d <62548908+candida-d@users.noreply.github.com>
This commit is contained in:
m.ray 2022-07-20 18:40:28 +02:00 committed by GitHub
parent 4670d5e6cf
commit c0532a8507
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 618 additions and 49 deletions

View File

@ -1,5 +1,4 @@
import { gql, useQuery } from '@apollo/client';
import { MarketTradingMode } from '@vegaprotocol/types';
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import orderBy from 'lodash/orderBy';
import { useRouter } from 'next/router';
@ -20,15 +19,13 @@ const MARKETS_QUERY = gql`
}
`;
const marketList = ({ markets }: MarketsLanding) =>
orderBy(
markets?.filter(
({ marketTimestamps, tradingMode }) =>
marketTimestamps.open && tradingMode === MarketTradingMode.Continuous
) || [],
['state', 'marketTimestamps.open', 'id'],
const getMarketList = ({ markets = [] }: MarketsLanding) => {
return orderBy(
markets,
['marketTimestamps.open', 'id'],
['asc', 'asc', 'asc']
);
};
export function Index() {
const { replace } = useRouter();
@ -39,7 +36,7 @@ export function Index() {
useEffect(() => {
if (data) {
const marketId = marketList(data)[0]?.id;
const marketId = getMarketList(data)[0]?.id;
// If a default market is found, go to it with the landing dialog open
if (marketId) {

View File

@ -0,0 +1,102 @@
import {
addDecimal,
t,
addDecimalsFormatNumber,
} from '@vegaprotocol/react-helpers';
import { OrderType } from '@vegaprotocol/types';
import { FormGroup, Input, InputError, Button } from '@vegaprotocol/ui-toolkit';
import { useForm } from 'react-hook-form';
import Icon from 'react-syntax-highlighter';
import { OrderDialogWrapper } from '@vegaprotocol/wallet';
import type { Order } from '@vegaprotocol/wallet';
interface OrderEditDialogProps {
title: string;
order: Order | null;
edit: (body: Order) => Promise<unknown>;
}
interface FormFields {
entryPrice: string;
}
export const OrderEditDialog = ({
order,
title,
edit,
}: OrderEditDialogProps) => {
const headerClassName = 'text-h5 font-bold text-black dark:text-white';
const {
register,
formState: { errors },
handleSubmit,
} = useForm<FormFields>({
defaultValues: {
entryPrice: order?.price
? addDecimal(order?.price, order?.market?.decimalPlaces ?? 0)
: '',
},
});
if (!order) return null;
return (
<OrderDialogWrapper title={title} icon={<Icon name="hand-up" size={20} />}>
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
{order.market && (
<div>
<p className={headerClassName}>{t(`Market`)}</p>
<p>{t(`${order.market.name}`)}</p>
</div>
)}
{order.type === OrderType.Limit && order.market && (
<div>
<p className={headerClassName}>{t(`Last price`)}</p>
<p>
{addDecimalsFormatNumber(order.price, order.market.decimalPlaces)}
</p>
</div>
)}
<div>
<p className={headerClassName}>{t(`Amount remaining`)}</p>
<p
className={
order.side === 'Buy'
? 'text-dark-green dark:text-vega-green'
: 'text-red dark:text-vega-red'
}
>
{order.side === 'Buy' ? '+' : '-'}
{order.size}
</p>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 py-12">
<form
onSubmit={handleSubmit(async (data) => {
await edit({
...order,
price: data.entryPrice,
});
})}
data-testid="edit-order"
>
<FormGroup label={t('Entry price')} labelFor="entryPrice">
<Input
{...register('entryPrice', { required: t('Required') })}
id="entryPrice"
type="text"
/>
{errors.entryPrice?.message && (
<InputError intent="danger" className="mt-4">
{errors.entryPrice.message}
</InputError>
)}
</FormGroup>
<Button variant="primary" type="submit">
{t('Update')}
</Button>
</form>
</div>
</OrderDialogWrapper>
);
};

View File

@ -16,7 +16,12 @@ const generateJsx = (
return (
<MockedProvider>
<VegaWalletContext.Provider value={context as VegaWalletContextShape}>
<OrderListTable data={orders} cancel={jest.fn()} />
<OrderListTable
data={orders}
cancel={jest.fn()}
setEditOrderDialogOpen={jest.fn()}
setEditOrder={jest.fn()}
/>
</VegaWalletContext.Provider>
</MockedProvider>
);
@ -36,7 +41,7 @@ describe('OrderListTable', () => {
});
const headers = screen.getAllByRole('columnheader');
expect(headers).toHaveLength(10);
expect(headers).toHaveLength(11);
expect(headers.map((h) => h.textContent?.trim())).toEqual([
'Market',
'Amount',
@ -47,6 +52,7 @@ describe('OrderListTable', () => {
'Time In Force',
'Created At',
'Updated At',
'Edit',
'Cancel',
]);
});
@ -67,6 +73,7 @@ describe('OrderListTable', () => {
marketOrder.timeInForce,
getDateTimeFormat().format(new Date(marketOrder.createdAt)),
'-',
'Edit',
'Cancel',
];
cells.forEach((cell, i) =>
@ -92,6 +99,7 @@ describe('OrderListTable', () => {
)}`,
getDateTimeFormat().format(new Date(limitOrder.createdAt)),
'-',
'Edit',
'Cancel',
];
cells.forEach((cell, i) =>

View File

@ -1,5 +1,5 @@
import type { Story, Meta } from '@storybook/react';
import { OrderType, OrderStatus } from '@vegaprotocol/types';
import { OrderType, OrderStatus, OrderTimeInForce } from '@vegaprotocol/types';
import { OrderList, OrderListTable } from './order-list';
import { useState } from 'react';
import type { Order, VegaTxState } from '@vegaprotocol/wallet';
@ -15,7 +15,16 @@ const Template: Story = (args) => {
const cancel = () => Promise.resolve();
return (
<div style={{ height: 1000 }}>
<OrderListTable data={args.data} cancel={cancel} />
<OrderListTable
data={args.data}
cancel={cancel}
setEditOrderDialogOpen={() => {
return;
}}
setEditOrder={() => {
return;
}}
/>
</div>
);
};
@ -39,12 +48,22 @@ const Template2: Story = (args) => {
price: '1000',
market: { name: 'ETH/DAI (30 Jun 2022)', decimalPlaces: 5 },
type: OrderType.Limit,
timeInForce: OrderTimeInForce.GTC,
};
const reset = () => null;
return (
<>
<div style={{ height: 1000 }}>
<OrderListTable data={args.data} cancel={cancel} />
<OrderListTable
data={args.data}
cancel={cancel}
setEditOrderDialogOpen={() => {
return;
}}
setEditOrder={() => {
return;
}}
/>
</div>
<VegaTransactionDialog
orderDialogOpen={open}

View File

@ -12,6 +12,8 @@ import { forwardRef, useState } from 'react';
import BigNumber from 'bignumber.js';
import { useOrderCancel } from '../../order-hooks/use-order-cancel';
import { VegaTransactionDialog } from '@vegaprotocol/wallet';
import { useOrderEdit } from '../../order-hooks/use-order-edit';
import { OrderEditDialog } from './order-edit-dialog';
interface OrderListProps {
data: Orders_party_orders[] | null;
@ -21,11 +23,22 @@ interface OrderListProps {
export const OrderList = forwardRef<AgGridReact, OrderListProps>(
({ data, showCancelled = true }, ref) => {
const [cancelOrderDialogOpen, setCancelOrderDialogOpen] = useState(false);
const [editOrderDialogOpen, setEditOrderDialogOpen] = useState(false);
const [editOrder, setEditOrder] = useState<Orders_party_orders | null>(
null
);
const { transaction, updatedOrder, reset, cancel } = useOrderCancel();
const {
transaction: editTransaction,
updatedOrder: editedOrder,
reset: resetEdit,
edit,
} = useOrderEdit();
const ordersData = showCancelled
? data
: data?.filter((o) => o.status !== OrderStatus.Cancelled) || null;
const getDialogTitle = (status?: string) => {
const getCancelDialogTitle = (status?: string) => {
switch (status) {
case OrderStatus.Cancelled:
return 'Order cancelled';
@ -37,18 +50,51 @@ export const OrderList = forwardRef<AgGridReact, OrderListProps>(
return 'Cancellation failed';
}
};
const getEditDialogTitle = () =>
editedOrder
? t(
`Order ${
editOrder?.market?.tradableInstrument.instrument.code ?? ''
} updated`
)
: t(
`Edit ${
editOrder?.market?.tradableInstrument.instrument.code ?? ''
} order`
);
return (
<>
<OrderListTable data={ordersData} cancel={cancel} ref={ref} />
<OrderListTable
data={ordersData}
cancel={cancel}
ref={ref}
setEditOrderDialogOpen={setEditOrderDialogOpen}
setEditOrder={setEditOrder}
/>
<VegaTransactionDialog
key={`cancel-order-dialog-${transaction.txHash}`}
orderDialogOpen={cancelOrderDialogOpen}
setOrderDialogOpen={setCancelOrderDialogOpen}
finalizedOrder={updatedOrder}
transaction={transaction}
reset={reset}
title={getDialogTitle(updatedOrder?.status)}
title={getCancelDialogTitle(updatedOrder?.status)}
finalizedOrder={updatedOrder}
/>
<VegaTransactionDialog
key={`edit-order-dialog-${transaction.txHash}`}
orderDialogOpen={editOrderDialogOpen}
setOrderDialogOpen={setEditOrderDialogOpen}
transaction={editTransaction}
reset={resetEdit}
title={getEditDialogTitle()}
finalizedOrder={editedOrder}
>
<OrderEditDialog
title={getEditDialogTitle()}
order={editOrder}
edit={edit}
/>
</VegaTransactionDialog>
</>
);
}
@ -57,10 +103,12 @@ export const OrderList = forwardRef<AgGridReact, OrderListProps>(
interface OrderListTableProps {
data: Orders_party_orders[] | null;
cancel: (body?: unknown) => Promise<unknown>;
setEditOrderDialogOpen: (value: boolean) => void;
setEditOrder: (order: Orders_party_orders | null) => void;
}
export const OrderListTable = forwardRef<AgGridReact, OrderListTableProps>(
({ data, cancel }, ref) => {
({ data, cancel, setEditOrderDialogOpen, setEditOrder }, ref) => {
return (
<AgGrid
ref={ref}
@ -147,6 +195,34 @@ export const OrderListTable = forwardRef<AgGridReact, OrderListTableProps>(
return value ? getDateTimeFormat().format(new Date(value)) : '-';
}}
/>
<AgGridColumn
field="edit"
cellRenderer={({ data }: ICellRendererParams) => {
if (
![
OrderStatus.Cancelled,
OrderStatus.Rejected,
OrderStatus.Expired,
OrderStatus.Filled,
OrderStatus.Stopped,
].includes(data.status)
) {
return (
<Button
data-testid="edit"
variant="secondary"
onClick={() => {
setEditOrderDialogOpen(true);
setEditOrder(data);
}}
>
Edit
</Button>
);
}
return null;
}}
/>
<AgGridColumn
field="cancel"
cellRenderer={({ data }: ICellRendererParams) => {

View File

@ -15,6 +15,10 @@ export interface OrderEvent_busEvents_event_TimeUpdate {
export interface OrderEvent_busEvents_event_Order_market {
__typename: "Market";
/**
* Market ID
*/
id: string;
/**
* Market full name
*/

View File

@ -14,8 +14,10 @@ export const ORDER_EVENT_SUB = gql`
size
price
timeInForce
expiresAt
side
market {
id
name
decimalPlaces
}

View File

@ -67,7 +67,7 @@ export const useOrderCancel = () => {
if (res?.signature) {
const resId = order.id ?? determineId(res.signature);
setUpdatedOrder(null);
// setId(resId);
if (resId) {
// Start a subscription looking for the newly created order
subRef.current = client

View File

@ -0,0 +1,221 @@
import { act, renderHook } from '@testing-library/react-hooks';
import type {
VegaKeyExtended,
VegaWalletContextShape,
} from '@vegaprotocol/wallet';
import {
VegaWalletOrderSide,
VegaWalletOrderTimeInForce,
VegaWalletOrderType,
} from '@vegaprotocol/wallet';
import { VegaTxStatus, VegaWalletContext } from '@vegaprotocol/wallet';
import type { ReactNode } from 'react';
import { useOrderEdit } from './use-order-edit';
import type {
OrderEvent,
OrderEvent_busEvents,
} from './__generated__/OrderEvent';
import { ORDER_EVENT_SUB } from './order-event-query';
import type { MockedResponse } from '@apollo/client/testing';
import { MockedProvider } from '@apollo/client/testing';
import {
MarketTradingMode,
MarketState,
OrderTimeInForce,
} from '@vegaprotocol/types';
import type {
OrderAmendmentBodyOrderAmendment,
OrderAmendmentBody,
} from '@vegaprotocol/vegawallet-service-api-client';
const defaultWalletContext = {
keypair: null,
keypairs: [],
sendTx: jest.fn().mockReturnValue(Promise.resolve(null)),
connect: jest.fn(),
disconnect: jest.fn(),
selectPublicKey: jest.fn(),
connector: null,
};
function setup(context?: Partial<VegaWalletContextShape>) {
const mocks: MockedResponse<OrderEvent> = {
request: {
query: ORDER_EVENT_SUB,
variables: {
partyId: context?.keypair?.pub || '',
},
},
result: {
data: {
busEvents: [
{
type: 'Order',
event: {
type: 'Limit',
id: '9c70716f6c3698ac7bbcddc97176025b985a6bb9a0c4507ec09c9960b3216b62',
status: 'Active',
rejectionReason: null,
createdAt: '2022-07-05T14:25:47.815283706Z',
size: '10',
price: '300000',
timeInForce: 'GTC',
side: 'Buy',
market: {
name: 'UNIDAI Monthly (30 Jun 2022)',
decimalPlaces: 5,
__typename: 'Market',
},
__typename: 'Order',
},
__typename: 'BusEvent',
} as OrderEvent_busEvents,
],
},
},
};
const filterMocks: MockedResponse<OrderEvent> = {
request: {
query: ORDER_EVENT_SUB,
variables: {
partyId: context?.keypair?.pub || '',
},
},
result: {
data: {
busEvents: [
{
type: 'Order',
event: {
type: 'Limit',
id: '9c70716f6c3698ac7bbcddc97176025b985a6bb9a0c4507ec09c9960b3216b62',
status: 'Active',
rejectionReason: null,
createdAt: '2022-07-05T14:25:47.815283706Z',
size: '10',
price: '300000',
timeInForce: 'GTC',
side: 'Buy',
market: {
name: 'UNIDAI Monthly (30 Jun 2022)',
decimalPlaces: 5,
__typename: 'Market',
},
__typename: 'Order',
},
__typename: 'BusEvent',
} as OrderEvent_busEvents,
],
},
},
};
const wrapper = ({ children }: { children: ReactNode }) => (
<MockedProvider mocks={[mocks, filterMocks]}>
<VegaWalletContext.Provider
value={{ ...defaultWalletContext, ...context }}
>
{children}
</VegaWalletContext.Provider>
</MockedProvider>
);
return renderHook(() => useOrderEdit(), { wrapper });
}
const defaultMarket = {
__typename: 'Market',
id: 'market-id',
decimalPlaces: 2,
positionDecimalPlaces: 1,
tradingMode: MarketTradingMode.Continuous,
state: MarketState.Active,
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
__typename: 'Instrument',
product: {
__typename: 'Future',
quoteName: 'quote-name',
},
},
},
depth: {
__typename: 'MarketDepth',
lastTrade: {
__typename: 'Trade',
price: '100',
},
},
};
const order = {
id: 'order-id',
type: VegaWalletOrderType.Limit,
size: '10',
timeInForce: OrderTimeInForce.GTT, // order timeInForce is transformed to wallet timeInForce
side: VegaWalletOrderSide.Buy,
price: '1234567.89',
expiration: new Date('2022-01-01'),
expiresAt: new Date('2022-01-01'),
status: VegaTxStatus.Pending,
rejectionReason: null,
market: {
id: 'market-id',
decimalPlaces: 2,
name: 'ETHDAI',
positionDecimalPlaces: 2,
},
};
describe('useOrderEdit', () => {
it('should edit a correctly formatted order', async () => {
const mockSendTx = jest.fn().mockReturnValue(Promise.resolve({}));
const keypair = {
pub: '0x123',
} as VegaKeyExtended;
const { result } = setup({
sendTx: mockSendTx,
keypairs: [keypair],
keypair,
});
await act(async () => {
result.current.edit(order);
});
expect(mockSendTx).toHaveBeenCalledWith({
pubKey: keypair.pub,
propagate: true,
orderAmendment: {
orderId: 'order-id',
marketId: defaultMarket.id, // Market provided from hook argument
timeInForce: VegaWalletOrderTimeInForce.GTT,
price: { value: '123456789' }, // Decimal removed
sizeDelta: 0,
expiresAt: { value: order.expiration?.getTime() + '000000' }, // Nanoseconds append
} as unknown as OrderAmendmentBodyOrderAmendment,
} as OrderAmendmentBody);
});
it('has the correct default state', () => {
const { result } = setup();
expect(typeof result.current.edit).toEqual('function');
expect(typeof result.current.reset).toEqual('function');
expect(result.current.transaction.status).toEqual(VegaTxStatus.Default);
expect(result.current.transaction.txHash).toEqual(null);
expect(result.current.transaction.error).toEqual(null);
});
it('should not sendTx if no keypair', async () => {
const mockSendTx = jest.fn();
const { result } = setup({
sendTx: mockSendTx,
keypairs: [],
keypair: null,
});
await act(async () => {
result.current.edit(order);
});
expect(mockSendTx).not.toHaveBeenCalled();
});
});

View File

@ -0,0 +1,119 @@
import { useApolloClient } from '@apollo/client';
import { determineId, removeDecimal } from '@vegaprotocol/react-helpers';
import { useState, useCallback, useEffect, useRef } from 'react';
import type { Order } from '@vegaprotocol/wallet';
import { VegaWalletOrderTimeInForce } from '@vegaprotocol/wallet';
import { useVegaTransaction, useVegaWallet } from '@vegaprotocol/wallet';
import { ORDER_EVENT_SUB } from './order-event-query';
import type { Subscription } from 'zen-observable-ts';
import type {
OrderEvent_busEvents_event_Order,
OrderEvent,
OrderEventVariables,
} from './__generated__';
import * as Sentry from '@sentry/react';
export const useOrderEdit = () => {
const { keypair } = useVegaWallet();
const { send, transaction, reset: resetTransaction } = useVegaTransaction();
const [updatedOrder, setUpdatedOrder] =
useState<OrderEvent_busEvents_event_Order | null>(null);
const client = useApolloClient();
const subRef = useRef<Subscription | null>(null);
const reset = useCallback(() => {
resetTransaction();
setUpdatedOrder(null);
subRef.current?.unsubscribe();
}, [resetTransaction]);
useEffect(() => {
return () => {
resetTransaction();
setUpdatedOrder(null);
subRef.current?.unsubscribe();
};
}, [resetTransaction]);
const edit = useCallback(
async (order: Order) => {
if (!keypair || !order.market || !order.market.id) {
return;
}
setUpdatedOrder(null);
try {
const res = await send({
pubKey: keypair.pub,
propagate: true,
orderAmendment: {
orderId: order.id,
marketId: order.market.id,
price: {
value: removeDecimal(order.price, order.market?.decimalPlaces),
},
timeInForce: VegaWalletOrderTimeInForce[order.timeInForce],
sizeDelta: 0,
expiresAt: order.expiresAt
? {
value:
// Wallet expects timestamp in nanoseconds,
// we don't have that level of accuracy so just append 6 zeroes
new Date(order.expiresAt).getTime().toString() + '000000',
}
: undefined,
},
});
if (res?.signature) {
const resId = order.id ?? determineId(res.signature);
setUpdatedOrder(null);
if (resId) {
// Start a subscription looking for the newly created order
subRef.current = client
.subscribe<OrderEvent, OrderEventVariables>({
query: ORDER_EVENT_SUB,
variables: { partyId: keypair?.pub || '' },
})
.subscribe(({ data }) => {
if (!data?.busEvents?.length) {
return;
}
// No types available for the subscription result
const matchingOrderEvent = data.busEvents.find((e) => {
if (e.event.__typename !== 'Order') {
return false;
}
return e.event.id === resId;
});
if (
matchingOrderEvent &&
matchingOrderEvent.event.__typename === 'Order'
) {
setUpdatedOrder(matchingOrderEvent.event);
subRef.current?.unsubscribe();
}
});
}
}
return res;
} catch (e) {
Sentry.captureException(e);
return;
}
},
[client, keypair, send]
);
return {
transaction,
updatedOrder,
edit,
reset,
};
};

View File

@ -5,6 +5,7 @@ import {
} from '@vegaprotocol/wallet';
import { toDecimal } from '@vegaprotocol/react-helpers';
import type { Market } from '../market';
import type { OrderStatus } from '@vegaprotocol/types';
export type Order =
| {
@ -14,6 +15,9 @@ export type Order =
side: VegaWalletOrderSide;
price?: never;
expiration?: never;
rejectionReason: string | null;
status?: OrderStatus;
market?: Market | null;
}
| {
size: string;
@ -22,6 +26,9 @@ export type Order =
side: VegaWalletOrderSide;
price?: string;
expiration?: Date;
rejectionReason: string | null;
status?: OrderStatus;
market?: Market | null;
};
export const getDefaultOrder = (market: Market): Order => ({
@ -29,4 +36,6 @@ export const getDefaultOrder = (market: Market): Order => ({
side: VegaWalletOrderSide.Buy,
timeInForce: VegaWalletOrderTimeInForce.IOC,
size: String(toDecimal(market.positionDecimalPlaces)),
rejectionReason: null,
market: null,
});

View File

@ -293,16 +293,6 @@ export enum WithdrawalStatus {
Rejected = "Rejected",
}
/**
* Pagination constructs to support cursor based pagination in the API
*/
export interface Pagination {
first?: number | null;
after?: string | null;
last?: number | null;
before?: string | null;
}
//==============================================================
// END Enums and Input Objects
//==============================================================

View File

@ -1,2 +1,3 @@
export * from './__generated__/globalTypes';
export * from './candle';
export * from './pagination';

View File

@ -0,0 +1,6 @@
export interface Pagination {
first?: number;
after?: string;
last?: number;
before?: string;
}

View File

@ -17,6 +17,7 @@ export interface VegaTransactionDialogProps {
transaction: VegaTxState;
reset: () => void;
title?: string;
children?: ReactNode;
}
const getDialogIntent = (
@ -45,6 +46,7 @@ export const VegaTransactionDialog = ({
transaction,
reset,
title = '',
children,
}: VegaTransactionDialogProps) => {
// open / close dialog
useEffect(() => {
@ -75,6 +77,7 @@ export const VegaTransactionDialog = ({
transaction={transaction}
finalizedOrder={finalizedOrder}
title={title}
children={children}
/>
</Dialog>
);
@ -84,15 +87,22 @@ interface VegaDialogProps {
transaction: VegaTxState;
finalizedOrder: Order | null;
title: string;
children?: ReactNode;
}
export const VegaDialog = ({
transaction,
finalizedOrder,
title,
children,
}: VegaDialogProps) => {
const { VEGA_EXPLORER_URL } = useEnvironment();
const headerClassName = 'text-h5 font-bold text-black dark:text-white';
if (children && transaction.status === VegaTxStatus.Default) {
return <div>{children}</div>;
}
// Rejected by wallet
if (transaction.status === VegaTxStatus.Requested) {
return (
@ -178,6 +188,17 @@ export const VegaDialog = ({
<p className={headerClassName}>{t(`Status`)}</p>
<p>{t(`${finalizedOrder.status}`)}</p>
</div>
{finalizedOrder.type === OrderType.Limit && finalizedOrder.market && (
<div>
<p className={headerClassName}>{t(`Price`)}</p>
<p>
{addDecimalsFormatNumber(
finalizedOrder.price,
finalizedOrder.market.decimalPlaces
)}
</p>
</div>
)}
<div>
<p className={headerClassName}>{t(`Amount`)}</p>
<p
@ -193,17 +214,6 @@ export const VegaDialog = ({
`}
</p>
</div>
{finalizedOrder.type === OrderType.Limit && finalizedOrder.market && (
<div>
<p className={headerClassName}>{t(`Price`)}</p>
<p>
{addDecimalsFormatNumber(
finalizedOrder.price,
finalizedOrder.market.decimalPlaces
)}
</p>
</div>
)}
</div>
<div className="grid grid-cols-1 gap-8">
{transaction.txHash && (
@ -231,7 +241,7 @@ interface OrderDialogWrapperProps {
title: string;
}
const OrderDialogWrapper = ({
export const OrderDialogWrapper = ({
children,
icon,
title,

View File

@ -1,3 +1,4 @@
import type { OrderTimeInForce } from '@vegaprotocol/types';
import type {
DelegateSubmissionBody,
OrderCancellationBody,
@ -41,14 +42,18 @@ export interface Market {
name: string;
positionDecimalPlaces?: number;
decimalPlaces: number;
id?: string;
}
export interface Order {
status: string;
rejectionReason: string | null;
id?: string;
status?: string;
rejectionReason?: string | null;
size: string;
price: string;
market: Market | null;
type: string | null;
side?: string;
timeInForce: OrderTimeInForce;
expiresAt?: Date | string | null;
}

View File

@ -30,7 +30,7 @@
"@sentry/react": "^6.19.2",
"@sentry/tracing": "^6.19.2",
"@testing-library/user-event": "^14.2.1",
"@vegaprotocol/vegawallet-service-api-client": "0.4.14",
"@vegaprotocol/vegawallet-service-api-client": "0.4.15",
"@walletconnect/ethereum-provider": "^1.7.5",
"@web3-react/core": "8.0.20-beta.0",
"@web3-react/metamask": "8.0.16-beta.0",

View File

@ -6693,10 +6693,10 @@
"@typescript-eslint/types" "5.22.0"
eslint-visitor-keys "^3.0.0"
"@vegaprotocol/vegawallet-service-api-client@0.4.14":
version "0.4.14"
resolved "https://registry.yarnpkg.com/@vegaprotocol/vegawallet-service-api-client/-/vegawallet-service-api-client-0.4.14.tgz#cdec296644380f95397688e10b753af328c38147"
integrity sha512-xQ/Dg4Bg+3LSHybYHV83i3G7i407Jj8ROElblZ2TTHTW9iHbBhbd/EHtWfUF2C6R6U27+JUZExnFPcZlvNXprA==
"@vegaprotocol/vegawallet-service-api-client@^0.4.15":
version "0.4.15"
resolved "https://registry.yarnpkg.com/@vegaprotocol/vegawallet-service-api-client/-/vegawallet-service-api-client-0.4.15.tgz#b303fec121b9b334a678161a6f66b360aeed5f0d"
integrity sha512-YwJkUgFvFqpA1xPYQ30ILGddgzjwD9lclsu1GvwK2AUX/8e3iUcXyr37wLd/t8mDZ7P3Zb2AsuLJP8uZ6E1GHQ==
dependencies:
es6-promise "^4.2.4"
url-parse "^1.4.3"