Compare commits

...
Author SHA1 Message Date
maciek a96143f539 Merge remote-tracking branch 'origin/feat/3709-use-generated-transaction-types' into feat/3709-use-generated-transaction-types 2023-07-03 08:56:27 +02:00
maciek c2c3d352d7 chore: use generated types from vega protos - save last changes for history 2023-07-03 08:55:49 +02:00
Dariusz Majcherczyk 0d447ac416 test: changed assertion 2023-06-22 21:10:07 +02:00
Dariusz Majcherczyk fa8e5e18ee test: remove unused mock 2023-06-22 20:36:18 +02:00
Dariusz Majcherczyk 10e60090ef test: added wait for market 2023-06-22 17:58:05 +02:00
maciek 778bff5af4 chore: use generated types from vega protos - update cypress webpack configuration 2023-06-22 15:08:14 +02:00
maciek efced9db32 chore: use generated types from vega protos - update int tests 2023-06-22 13:59:16 +02:00
maciek 456287a159 chore: use generated types from vega protos - move back setup-test imports 2023-06-22 12:35:24 +02:00
maciek fa5b00f3d8 chore: use generated types from vega protos - move back setup-test imports 2023-06-22 12:21:41 +02:00
maciek 6df93cf7a4 chore: use generated types from vega protos - improvements 2023-06-22 11:58:45 +02:00
maciek 8f8f152050 chore: use generated types from vega protos - improvements 2023-06-22 11:58:10 +02:00
maciek 48d1e54cbd Merge remote-tracking branch 'origin/develop' into feat/3709-use-generated-transaction-types 2023-06-22 11:29:17 +02:00
maciek 1d7c60046e chore: use generated types from vega protos - fix int tests, clear some types 2023-06-22 11:26:34 +02:00
maciek 49d7ea2e40 chore: use generated types from vega protos - get rid of DealTicketSubmission 2023-06-21 18:21:08 +02:00
maciek 08cf3e9f62 chore: use generated types from vega protos - resolve lint err 2023-06-21 17:05:57 +02:00
maciek cee0050178 chore: use generated types from vega protos - resolce conflicts 2023-06-21 16:01:02 +02:00
maciek 992866e602 chore: use generated types from vega protos - let the cypress compile additional es6 lib 2023-06-21 15:58:48 +02:00
maciek bc0f697f3d chore: use generated types from vega protos - fix typo 2023-06-20 16:05:58 +02:00
maciek 135bcbc1d7 Merge remote-tracking branch 'origin/develop' into feat/3709-use-generated-transaction-types 2023-06-20 16:04:30 +02:00
maciek 0e828d1147 chore: use generated types from vega protos - revert changes enums from cypress 2023-06-20 16:04:16 +02:00
maciek b7e040efa3 chore: use generated types from vega protos - revert changes for proposals 2023-06-20 10:33:35 +02:00
maciek 1c31f338dd Merge remote-tracking branch 'origin/develop' into feat/3709-use-generated-transaction-types 2023-06-20 10:23:43 +02:00
maciek d7b63773cc chore: use generated types from vega protos - revert changes for proposals 2023-06-20 10:23:31 +02:00
maciek a22504baf6 Merge remote-tracking branch 'origin/develop' into feat/3709-use-generated-transaction-types 2023-06-19 18:07:47 +02:00
maciek 00ee275462 chore: use generated types from vega protos - fix failing build jobs 2023-06-19 18:07:23 +02:00
maciek 888f670691 chore: use generated types from vega protos - fix failing unit test 2023-06-19 16:52:00 +02:00
maciek 22072efb35 chore: use generated types from vega protos - fix compiling failures 2023-06-19 16:26:01 +02:00
maciek 6ec8b016c0 chore: use generated types from vega protos - fix compiling failures 2023-06-19 16:09:00 +02:00
maciek a45b198e44 chore: use generated types from vega protos - fix compiling failures 2023-06-19 16:08:55 +02:00
maciek f545d68895 chore: use generated types from vega protos - fix compiling failures 2023-06-19 16:03:24 +02:00
maciek 1396a2573a chore: use generated types from vega protos - fix compiling failures 2023-06-19 16:03:03 +02:00
maciek a729d0eec6 chore: use generated types from vega protos - fix test types 2023-06-19 14:09:24 +02:00
maciek 2152c7c73c chore: use generated types from vega protos - get rid of convertDealTicketToOrderAmendment 2023-06-19 13:27:52 +02:00
maciek 6a2319c20d chore: use generated types from vega protos - move out some type from wallet to deal-ticket module 2023-06-19 12:47:05 +02:00
maciek 5044764445 chore: use generated types from vega protos - fix account test 2023-06-19 09:53:16 +02:00
maciek a985bb4876 chore: use generated types from vega protos - fix after conflicts resolving 2023-06-18 22:29:02 +02:00
maciek 8ae9609022 chore: use generated types from vega protos - fix after conflicts resolving 2023-06-18 22:28:10 +02:00
maciek bf718dfb87 chore: use generated types from vega protos - resolve conflicts 2023-06-18 22:08:43 +02:00
maciek 3152289683 chore: use generated types from vega protos - adjust jest conf, fix failing unit tests 2023-06-18 21:57:44 +02:00
maciek e1eebe4afb chore: use generated types from vega protos - overwrite incompatible types 2023-06-16 10:29:35 +02:00
maciek 9e11c28697 Merge remote-tracking branch 'origin/develop' into feat/3709-use-generated-transaction-types 2023-06-15 18:28:31 +02:00
maciek 1c84086e18 chore: use generated types from vega protos - overwrite incompatible types 2023-06-15 18:28:10 +02:00
maciek 2b7fb5ea87 chore: use generated types from vega protos - remove redundant files 2023-06-15 15:45:36 +02:00
maciek d4f6fd7c58 Merge remote-tracking branch 'origin/develop' into feat/3709-use-generated-transaction-types 2023-06-15 15:39:42 +02:00
maciek 7d02dc97d6 chore: use generated types from vega protos - straighten the types, add conversion methods 2023-06-15 15:39:22 +02:00
maciek c2f7ddaeab Merge remote-tracking branch 'origin/develop' into feat/3709-use-generated-transaction-types 2023-06-14 10:37:18 +02:00
maciek 0e77e39848 chore: use generated types from vega protos - fix import paths 2023-06-14 10:35:48 +02:00
maciek d1ebd26e21 chore: use generated types from vega protos 2023-06-13 18:37:22 +02:00
70 changed files with 2537 additions and 988 deletions
+36
View File
@@ -1,4 +1,10 @@
const { defineConfig } = require('cypress');
const webpack = require('webpack');
const webpackPreprocessor = require('@cypress/webpack-batteries-included-preprocessor');
const path = require('path');
const dotenv = require('dotenv');
dotenv.config();
module.exports = defineConfig({
reporter: '../../node_modules/cypress-mochawesome-reporter',
@@ -7,6 +13,36 @@ module.exports = defineConfig({
setupNodeEvents(on, config) {
require('cypress-mochawesome-reporter/plugin')(on);
require('@cypress/grep/src/plugin')(config);
const defaultConfig = webpackPreprocessor.defaultOptions;
defaultConfig.webpackOptions.context = path.resolve(__dirname, './');
defaultConfig.webpackOptions.module.rules[1].test = /(\.tsx?|\.jsx?)$/;
defaultConfig.webpackOptions.module.rules[1].exclude = [
/node_modules\/(?!(@vegaprotocol\/protos|protobuf-codec))/,
/browserslist/,
];
defaultConfig.webpackOptions.module.rules.push({
test: /(\.css|\.s[ac]ss)$/i,
use: ['style-loader', 'css-loader', 'sass-loader'],
});
defaultConfig.webpackOptions.plugins =
defaultConfig.webpackOptions.plugins || [];
defaultConfig.webpackOptions.plugins.push(
new webpack.DefinePlugin({
'process.env': JSON.stringify(process.env),
})
);
defaultConfig.webpackOptions.cache = {
type: 'filesystem',
allowCollectingMemory: true,
buildDependencies: {
config: [__filename],
},
};
defaultConfig.typescript = require.resolve('typescript');
on('file:preprocessor', webpackPreprocessor(defaultConfig));
return config;
},
baseUrl: 'http://localhost:3000',
+1
View File
@@ -3,6 +3,7 @@
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom';
import '../../../../setup-test';
Object.defineProperty(window, 'ResizeObserver', {
writable: false,
+36
View File
@@ -1,4 +1,10 @@
const { defineConfig } = require('cypress');
const webpack = require('webpack');
const webpackPreprocessor = require('@cypress/webpack-batteries-included-preprocessor');
const path = require('path');
const dotenv = require('dotenv');
dotenv.config();
module.exports = defineConfig({
reporter: '../../node_modules/cypress-mochawesome-reporter',
@@ -7,6 +13,36 @@ module.exports = defineConfig({
setupNodeEvents(on, config) {
require('cypress-mochawesome-reporter/plugin')(on);
require('@cypress/grep/src/plugin')(config);
const defaultConfig = webpackPreprocessor.defaultOptions;
defaultConfig.webpackOptions.context = path.resolve(__dirname, './');
defaultConfig.webpackOptions.module.rules[1].test = /(\.tsx?|\.jsx?)$/;
defaultConfig.webpackOptions.module.rules[1].exclude = [
/node_modules\/(?!(@vegaprotocol\/protos|protobuf-codec))/,
/browserslist/,
];
defaultConfig.webpackOptions.module.rules.push({
test: /(\.css|\.s[ac]ss)$/i,
use: ['style-loader', 'css-loader', 'sass-loader'],
});
defaultConfig.webpackOptions.plugins =
defaultConfig.webpackOptions.plugins || [];
defaultConfig.webpackOptions.plugins.push(
new webpack.DefinePlugin({
'process.env': JSON.stringify(process.env),
})
);
defaultConfig.webpackOptions.cache = {
type: 'filesystem',
allowCollectingMemory: true,
buildDependencies: {
config: [__filename],
},
};
defaultConfig.typescript = require.resolve('typescript');
on('file:preprocessor', webpackPreprocessor(defaultConfig));
return config;
},
baseUrl: 'http://localhost:4210',
@@ -7,6 +7,7 @@ import type { BigNumber } from '../../../lib/bignumber';
import type { UndelegateSubmissionBody } from '@vegaprotocol/wallet';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { removeDecimal } from '@vegaprotocol/utils';
import { vega as VegaProtos } from '@vegaprotocol/protos';
interface PendingStakeProps {
pendingAmount: BigNumber;
@@ -38,7 +39,7 @@ export const PendingStake = ({
undelegateSubmission: {
nodeId,
amount: removeDecimal(pendingAmount.toString(), appState.decimals),
method: 'METHOD_NOW',
method: VegaProtos.commands.v1.UndelegateSubmission.Method.METHOD_NOW,
},
};
await sendTx(pubKey, command);
@@ -4,6 +4,7 @@ import React, { useCallback, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router-dom';
import { ENV } from '../../../config';
import { vega as VegaProtos } from '@vegaprotocol/protos';
import { usePartyDelegationsLazyQuery } from './__generated__/PartyDelegations';
import { TokenInput } from '../../../components/token-input';
import { useAppState } from '../../../contexts/app-state/app-state-context';
@@ -128,8 +129,9 @@ export const StakingForm = ({
amount: removeDecimal(amount, appState.decimals),
method:
removeType === RemoveType.Now
? 'METHOD_NOW'
: 'METHOD_AT_END_OF_EPOCH',
? VegaProtos.commands.v1.UndelegateSubmission.Method.METHOD_NOW
: VegaProtos.commands.v1.UndelegateSubmission.Method
.METHOD_AT_END_OF_EPOCH,
},
};
try {
+1
View File
@@ -7,6 +7,7 @@ import dev from './i18n/translations/dev.json';
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import ResizeObserver from 'resize-observer-polyfill';
import '../../../setup-test';
// Set up i18n instance so that components have the correct default
// en translations
+36
View File
@@ -1,4 +1,10 @@
const { defineConfig } = require('cypress');
const webpack = require('webpack');
const webpackPreprocessor = require('@cypress/webpack-batteries-included-preprocessor');
const path = require('path');
const dotenv = require('dotenv');
dotenv.config();
module.exports = defineConfig({
reporter: '../../node_modules/cypress-mochawesome-reporter',
@@ -6,6 +12,36 @@ module.exports = defineConfig({
setupNodeEvents(on, config) {
require('cypress-mochawesome-reporter/plugin')(on);
require('@cypress/grep/src/plugin')(config);
const defaultConfig = webpackPreprocessor.defaultOptions;
defaultConfig.webpackOptions.context = path.resolve(__dirname, './');
defaultConfig.webpackOptions.module.rules[1].test = /(\.tsx?|\.jsx?)$/;
defaultConfig.webpackOptions.module.rules[1].exclude = [
/node_modules\/(?!(@vegaprotocol\/protos|protobuf-codec))/,
/browserslist/,
];
defaultConfig.webpackOptions.module.rules.push({
test: /(\.css|\.s[ac]ss)$/i,
use: ['style-loader', 'css-loader', 'sass-loader'],
});
defaultConfig.webpackOptions.plugins =
defaultConfig.webpackOptions.plugins || [];
defaultConfig.webpackOptions.plugins.push(
new webpack.DefinePlugin({
'process.env': JSON.stringify(process.env),
})
);
defaultConfig.webpackOptions.cache = {
type: 'filesystem',
allowCollectingMemory: true,
buildDependencies: {
config: [__filename],
},
};
defaultConfig.typescript = require.resolve('typescript');
on('file:preprocessor', webpackPreprocessor(defaultConfig));
return config;
},
baseUrl: 'http://localhost:4200',
@@ -154,7 +154,7 @@ describe('markets all table', { tags: '@smoke' }, () => {
.find(dropdownContentItem)
.eq(2)
.should('have.text', 'View asset');
cy.getByTestId('market-actions-content').click();
cy.getByTestId('market-actions-content').should('be.visible');
});
it('able to open and sort full market list - market page', () => {
@@ -197,8 +197,8 @@ describe('no all markets', { tags: '@smoke', testIsolation: true }, () => {
cy.mockGQL((req) => {
aliasGQLQuery(req, 'Markets', markets);
});
cy.mockSubscription();
cy.visit('/#/markets/all');
cy.wait('@Markets');
});
it('can see no markets message', () => {
@@ -1,7 +1,7 @@
import * as Schema from '@vegaprotocol/types';
import { testOrderSubmission } from '../support/order-validation';
import type { OrderSubmission } from '@vegaprotocol/wallet';
import { createOrder } from '../support/create-order';
import type { OrderObj } from '@vegaprotocol/orders';
describe('must submit order', { tags: '@smoke' }, () => {
// 7002-SORD-039
@@ -22,7 +22,7 @@ describe('must submit order', { tags: '@smoke' }, () => {
// 0003-WTXN-012
// 0003-WTXN-003
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
const order: OrderObj = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_MARKET,
side: Schema.Side.SIDE_BUY,
@@ -37,7 +37,7 @@ describe('must submit order', { tags: '@smoke' }, () => {
it('successfully places market sell order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
const order: OrderObj = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_MARKET,
side: Schema.Side.SIDE_SELL,
@@ -53,7 +53,7 @@ describe('must submit order', { tags: '@smoke' }, () => {
it('successfully places limit buy order', () => {
// 7002-SORD-017
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
const order: OrderObj = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_BUY,
@@ -69,7 +69,7 @@ describe('must submit order', { tags: '@smoke' }, () => {
it('successfully places limit sell order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
const order: OrderObj = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_SELL,
@@ -86,7 +86,7 @@ describe('must submit order', { tags: '@smoke' }, () => {
it('successfully places GTT limit buy order', () => {
cy.mockVegaWalletTransaction();
const expiresAt = new Date(Date.now() + 24 * 60 * 60 * 1000);
const order: OrderSubmission = {
const order: OrderObj = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_SELL,
@@ -97,12 +97,10 @@ describe('must submit order', { tags: '@smoke' }, () => {
postOnly: false,
reduceOnly: false,
};
createOrder(order);
testOrderSubmission(order, {
price: '100000',
expiresAt:
new Date(order.expiresAt as string).getTime().toString() + '000000',
expiresAt: order.expiresAt as string,
postOnly: false,
reduceOnly: false,
});
@@ -5,8 +5,8 @@ import {
amendGeneralAccountBalance,
amendMarginAccountBalance,
} from '@vegaprotocol/mock';
import type { OrderSubmission } from '@vegaprotocol/wallet';
import { createOrder } from '../support/create-order';
import type { OrderObj } from '@vegaprotocol/orders';
describe(
'account validation',
@@ -94,7 +94,7 @@ describe(
it('must see a prompt to check connected vega wallet to approve transaction', () => {
// 0003-WTXN-002
cy.mockVegaWalletTransaction(1000);
const order: OrderSubmission = {
const order: OrderObj = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_MARKET,
side: Schema.Side.SIDE_BUY,
@@ -124,7 +124,7 @@ describe(
});
});
const order: OrderSubmission = {
const order: OrderObj = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_MARKET,
side: Schema.Side.SIDE_BUY,
@@ -160,7 +160,7 @@ describe(
});
});
const order: OrderSubmission = {
const order: OrderObj = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_MARKET,
side: Schema.Side.SIDE_BUY,
@@ -1,7 +1,7 @@
import * as Schema from '@vegaprotocol/types';
import { testOrderSubmission } from '../support/order-validation';
import type { OrderSubmission } from '@vegaprotocol/wallet';
import { createOrder } from '../support/create-order';
import type { OrderObj } from '@vegaprotocol/orders';
const displayTomorrow = () => {
const tomorrow = new Date();
@@ -31,7 +31,7 @@ describe(
it('successfully places limit buy order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
const order: OrderObj = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_BUY,
@@ -47,7 +47,7 @@ describe(
it('successfully places limit sell order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
const order: OrderObj = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_SELL,
@@ -63,7 +63,7 @@ describe(
it('successfully places GTT limit buy order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
const order: OrderObj = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_SELL,
@@ -79,8 +79,7 @@ describe(
price: '100000',
postOnly: false,
reduceOnly: false,
expiresAt:
new Date(order.expiresAt as string).getTime().toString() + '000000',
expiresAt: order.expiresAt as string,
});
});
}
@@ -1,7 +1,7 @@
import * as Schema from '@vegaprotocol/types';
import { testOrderSubmission } from '../support/order-validation';
import type { OrderSubmission } from '@vegaprotocol/wallet';
import { createOrder } from '../support/create-order';
import type { OrderObj } from '@vegaprotocol/orders';
const displayTomorrow = () => {
const tomorrow = new Date();
@@ -31,7 +31,7 @@ describe(
it('successfully places limit buy order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
const order: OrderObj = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_BUY,
@@ -47,7 +47,7 @@ describe(
it('successfully places limit sell order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
const order: OrderObj = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_SELL,
@@ -63,7 +63,7 @@ describe(
it('successfully places GTT limit buy order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
const order: OrderObj = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_SELL,
@@ -77,8 +77,7 @@ describe(
createOrder(order);
testOrderSubmission(order, {
price: '100000',
expiresAt:
new Date(order.expiresAt as string).getTime().toString() + '000000',
expiresAt: order.expiresAt as string,
});
});
}
@@ -1,7 +1,7 @@
import * as Schema from '@vegaprotocol/types';
import { testOrderSubmission } from '../support/order-validation';
import type { OrderSubmission } from '@vegaprotocol/wallet';
import { createOrder } from '../support/create-order';
import type { OrderObj } from '@vegaprotocol/orders';
const displayTomorrow = () => {
const tomorrow = new Date();
@@ -31,7 +31,7 @@ describe(
it('successfully places limit buy order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
const order: OrderObj = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_BUY,
@@ -47,7 +47,7 @@ describe(
it('successfully places limit sell order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
const order: OrderObj = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_SELL,
@@ -63,7 +63,7 @@ describe(
it('successfully places GTT limit buy order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
const order: OrderObj = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_SELL,
@@ -77,8 +77,7 @@ describe(
createOrder(order);
testOrderSubmission(order, {
price: '100000',
expiresAt:
new Date(order.expiresAt as string).getTime().toString() + '000000',
expiresAt: order.expiresAt as string,
});
});
}
@@ -0,0 +1,406 @@
import {
getSubscriptionMocks,
updateOrder,
} from '../support/order-update-subscription';
import * as Schema from '@vegaprotocol/types';
const orderSymbol = 'market.tradableInstrument.instrument.code';
const orderSize = 'size';
const orderType = 'type';
const orderStatus = 'status';
const orderRemaining = 'remaining';
const orderPrice = 'price';
const orderTimeInForce = 'timeInForce';
const orderCreatedAt = 'createdAt';
const cancelOrderBtn = 'cancel';
const cancelAllOrdersBtn = 'cancelAll';
const editOrderBtn = 'edit';
describe('orders list', { tags: '@smoke', testIsolation: true }, () => {
beforeEach(() => {
const subscriptionMocks = getSubscriptionMocks();
cy.spy(subscriptionMocks, 'OrdersUpdate');
cy.mockTradingPage();
cy.mockSubscription(subscriptionMocks);
cy.setVegaWallet();
cy.visit('/#/markets/market-0');
cy.getByTestId('All').click();
cy.wait('@Markets');
});
it('renders orders', () => {
cy.getByTestId('tab-orders').should('be.visible');
cy.getByTestId(cancelAllOrdersBtn).should('be.visible');
cy.getByTestId(cancelOrderBtn).should('have.length.at.least', 1);
cy.getByTestId(editOrderBtn).should('have.length.at.least', 1);
cy.getByTestId('tab-orders').within(() => {
cy.get(`[role='rowgroup']`)
.first()
.within(() => {
cy.get(`[col-id='${orderSymbol}']`).each(($symbol) => {
cy.wrap($symbol).invoke('text').should('not.be.empty');
});
cy.get(`[col-id='${orderSize}']`).each(($size) => {
cy.wrap($size).invoke('text').should('not.be.empty');
});
cy.get(`[col-id='${orderType}']`).each(($type) => {
cy.wrap($type).invoke('text').should('not.be.empty');
});
cy.get(`[col-id='${orderStatus}']`).each(($status) => {
cy.wrap($status).invoke('text').should('not.be.empty');
});
cy.get(`[col-id='${orderRemaining}']`).each(($remaining) => {
cy.wrap($remaining).invoke('text').should('not.be.empty');
});
cy.get(`[col-id='${orderPrice}']`).each(($price) => {
cy.wrap($price).invoke('text').should('not.be.empty');
});
cy.get(`[col-id='${orderTimeInForce}']`).each(($timeInForce) => {
cy.wrap($timeInForce).invoke('text').should('not.be.empty');
});
cy.get(`[col-id='${orderCreatedAt}']`).each(($dateTime) => {
cy.wrap($dateTime).invoke('text').should('not.be.empty');
});
});
});
});
it('partially filled orders should not show close/edit buttons', () => {
const partiallyFilledId =
'94aead3ca92dc932efcb503631b03a410e2a5d4606cae6083e2406dc38e52f78';
cy.getByTestId('tab-orders').should('be.visible');
cy.get('.ag-header-container').within(() => {
cy.get('[col-id="status"]').realHover();
cy.get('[col-id="status"] .ag-icon-menu').click();
});
cy.contains('Partially Filled').click();
cy.getByTestId('All').click();
cy.get(`[row-id="${partiallyFilledId}"]`)
.eq(1)
.within(() => {
cy.get(`[col-id='${orderStatus}']`).should(
'have.text',
'Partially Filled'
);
cy.get(`[col-id='${orderRemaining}']`).should('have.text', '7/10');
cy.getByTestId(cancelOrderBtn).should('not.exist');
cy.getByTestId(editOrderBtn).should('not.exist');
});
});
it('orders are sorted by most recent order', () => {
// 7003-MORD-002
const expectedOrderList = [
'BTCUSD.MF21',
'SOLUSD',
'AAPL.MF21',
'BTCUSD.MF21',
'BTCUSD.MF21',
];
cy.get('.ag-header-container').within(() => {
cy.get('[col-id="status"]').realHover();
cy.get('[col-id="status"] .ag-icon-menu').click();
});
cy.contains('Reset').click();
cy.getByTestId('All').click();
cy.getByTestId('tab-orders')
.get(`.ag-center-cols-container [col-id='${orderSymbol}']`)
.should('have.length.at.least', expectedOrderList.length)
.then(($symbols) => {
const symbolNames: string[] = [];
cy.wrap($symbols)
.each(($symbol) => {
cy.wrap($symbol)
.invoke('text')
.then((text) => {
symbolNames.push(text);
});
})
.then(() => {
expect(symbolNames).to.include.ordered.members(expectedOrderList);
});
});
});
});
describe('subscribe orders', { tags: '@smoke' }, () => {
let orderId = '0';
beforeEach(() => {
const subscriptionMocks = getSubscriptionMocks();
cy.spy(subscriptionMocks, 'OrdersUpdate');
cy.mockTradingPage();
cy.mockSubscription(subscriptionMocks);
cy.setVegaWallet();
cy.visit('/#/markets/market-0');
cy.getByTestId('All').click();
cy.getByTestId('tab-orders').within(() => {
cy.get('[col-id="status"][role="columnheader"]')
.focus()
.find('.ag-header-cell-menu-button')
.click();
cy.get('.ag-filter-apply-panel-button').click();
});
orderId = (parseInt(orderId, 10) + 1).toString();
});
// 7002-SORD-053
// 7002-SORD-040
// 7003-MORD-001
it('must see an active order', () => {
// 7002-SORD-041
updateOrder({
id: orderId,
status: Schema.OrderStatus.STATUS_ACTIVE,
});
cy.getByTestId(`order-status-${orderId}`).should('have.text', 'Active');
});
it('must see an expired order', () => {
// 7002-SORD-042
updateOrder({
id: orderId,
status: Schema.OrderStatus.STATUS_EXPIRED,
});
cy.getByTestId(`order-status-${orderId}`).should('have.text', 'Expired');
});
it('must see a cancelled order', () => {
// 7002-SORD-043
// NOT COVERED: see the txn that cancelled it and a link to the block explorer, if cancelled by a user transaction.
updateOrder({
id: orderId,
status: Schema.OrderStatus.STATUS_CANCELLED,
});
cy.getByTestId(`order-status-${orderId}`).should('have.text', 'Cancelled');
});
it('must see a stopped order', () => {
// 7002-SORD-044
// NOT COVERED: see an explanation of why stopped
updateOrder({
id: orderId,
status: Schema.OrderStatus.STATUS_STOPPED,
});
cy.getByTestId(`order-status-${orderId}`).should('have.text', 'Stopped');
});
it('must see a partially filled order', () => {
// 7002-SORD-045
updateOrder({
id: orderId,
status: Schema.OrderStatus.STATUS_PARTIALLY_FILLED,
size: '5',
remaining: '1',
});
cy.getByTestId(`order-status-${orderId}`).should(
'have.text',
'Partially Filled'
);
cy.getByTestId(`order-status-${orderId}`)
.parentsUntil(`.ag-row`)
.siblings(`[col-id=${orderRemaining}]`)
.should('have.text', '4/5');
});
it('must see a filled order', () => {
// 7002-SORD-046
// NOT COVERED: Must be able to see/link to all trades that were created from this order
updateOrder({
id: orderId,
status: Schema.OrderStatus.STATUS_FILLED,
});
cy.getByTestId(`order-status-${orderId}`).should('have.text', 'Filled');
});
it('must see a rejected order', () => {
// 7002-SORD-047
updateOrder({
id: orderId,
status: Schema.OrderStatus.STATUS_REJECTED,
rejectionReason: Schema.OrderRejectionReason.ORDER_ERROR_INTERNAL_ERROR,
});
cy.getByTestId(`order-status-${orderId}`).should(
'have.text',
'Rejected: Internal error'
);
});
it('must see a parked order', () => {
// 7002-SORD-048
updateOrder({
id: orderId,
status: Schema.OrderStatus.STATUS_PARKED,
});
cy.getByTestId(`order-status-${orderId}`).should(
'have.text',
'Parked: Internal error'
);
});
it('must see the size of the order and direction/side -', () => {
// 7003-MORD-003
// 7003-MORD-004
updateOrder({
id: orderId,
size: '15',
side: Schema.Side.SIDE_SELL,
status: Schema.OrderStatus.STATUS_ACTIVE,
});
cy.get(`[row-id=${orderId}]`)
.find('[col-id="size"]')
.should('have.text', '-15');
});
it('must see the size of the order and direction/side +', () => {
// 7003-MORD-003
// 7003-MORD-004
updateOrder({
id: orderId,
size: '5',
side: Schema.Side.SIDE_BUY,
status: Schema.OrderStatus.STATUS_ACTIVE,
});
cy.get(`[row-id=${orderId}]`)
.find('[col-id="size"]')
.should('have.text', '+5');
});
it('for limit typy must see the Limit price that was set on the order', () => {
// 7003-MORD-005
updateOrder({
id: orderId,
status: Schema.OrderStatus.STATUS_ACTIVE,
});
cy.get(`[row-id=${orderId}]`)
.find('[col-id="price"]')
.should('have.text', '200.00');
});
it('must see a pegged order - ask', () => {
updateOrder({
id: orderId,
side: Schema.Side.SIDE_BUY,
peggedOrder: {
__typename: 'PeggedOrder',
reference: Schema.PeggedReference.PEGGED_REFERENCE_BEST_ASK,
offset: '250000',
},
});
cy.get(`[row-id=${orderId}]`)
.find('[col-id="type"]')
.should('have.text', 'Ask - 2.50 Peg limit');
});
it('must see a pegged order - bid', () => {
updateOrder({
id: orderId,
side: Schema.Side.SIDE_SELL,
peggedOrder: {
__typename: 'PeggedOrder',
reference: Schema.PeggedReference.PEGGED_REFERENCE_BEST_BID,
offset: '100',
},
});
cy.get(`[row-id=${orderId}]`)
.find('[col-id="type"]')
.should('have.text', 'Bid + 0.001 Peg limit');
});
it('must see a pegged order - mid', () => {
updateOrder({
id: orderId,
side: Schema.Side.SIDE_SELL,
peggedOrder: {
__typename: 'PeggedOrder',
reference: Schema.PeggedReference.PEGGED_REFERENCE_MID,
offset: '0.5',
},
});
cy.get(`[row-id=${orderId}]`)
.find('[col-id="type"]')
.should('have.text', 'Mid + 0.00001 Peg limit');
});
it('for market typy must not see a price for active or parked orders', () => {
// 7003-MORD-005
updateOrder({
id: orderId,
type: Schema.OrderType.TYPE_MARKET,
status: Schema.OrderStatus.STATUS_PARKED,
peggedOrder: null,
});
cy.get(`[row-id=${orderId}]`)
.find('[col-id="price"]')
.should('have.text', '-');
});
it('must see the time in force applied to the order', () => {
// 7003-MORD-006
updateOrder({
id: orderId,
type: Schema.OrderType.TYPE_MARKET,
status: Schema.OrderStatus.STATUS_ACTIVE,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
});
cy.get(`[row-id=${orderId}]`)
.find(`[col-id='${orderTimeInForce}']`)
.should('have.text', "Good 'til Cancelled (GTC)");
});
it('for Active order when is part of a liquidity or peg shape, must not see an option to amend the individual order ', () => {
// 7003-MORD-008
updateOrder({
id: orderId,
status: Schema.OrderStatus.STATUS_ACTIVE,
peggedOrder: {},
liquidityProvisionId: '6536',
});
cy.get(`[row-id=${orderId}]`)
.find(`[data-testid="cancel"]`)
.should('not.exist');
cy.get(`[row-id=${orderId}]`)
.find(`[data-testid="edit"]`)
.should('not.exist');
});
it('for Active order when is part of a liquidity, must not see an option to amend the individual order ', () => {
// 7003-MORD-008
updateOrder({
id: orderId,
status: Schema.OrderStatus.STATUS_ACTIVE,
peggedOrder: {},
liquidityProvisionId: '6536',
});
cy.get(`[row-id=${orderId}]`)
.find(`[data-testid="cancel"]`)
.should('not.exist');
cy.get(`[row-id=${orderId}]`)
.find(`[data-testid="edit"]`)
.should('not.exist');
});
it('for Active order when is part of a peg shape, must not see an option to amend the individual order ', () => {
// 7003-MORD-008
updateOrder({
id: orderId,
status: Schema.OrderStatus.STATUS_ACTIVE,
peggedOrder: {},
});
cy.get(`[row-id=${orderId}]`)
.find(`[data-testid="cancel"]`)
.should('not.exist');
cy.get(`[row-id=${orderId}]`)
.find(`[data-testid="edit"]`)
.should('not.exist');
});
});
@@ -8,407 +8,7 @@ import {
testOrderCancellation,
testOrderAmendment,
} from '../support/order-validation';
const orderSymbol = 'market.tradableInstrument.instrument.code';
const orderSize = 'size';
const orderType = 'type';
const orderStatus = 'status';
const orderRemaining = 'remaining';
const orderPrice = 'price';
const orderTimeInForce = 'timeInForce';
const orderCreatedAt = 'createdAt';
const cancelOrderBtn = 'cancel';
const cancelAllOrdersBtn = 'cancelAll';
const editOrderBtn = 'edit';
describe('orders list', { tags: '@smoke', testIsolation: true }, () => {
beforeEach(() => {
const subscriptionMocks = getSubscriptionMocks();
cy.spy(subscriptionMocks, 'OrdersUpdate');
cy.mockTradingPage();
cy.mockSubscription(subscriptionMocks);
cy.setVegaWallet();
cy.visit('/#/markets/market-0');
cy.getByTestId('All').click();
cy.wait('@Markets');
});
it('renders orders', () => {
cy.getByTestId('tab-orders').should('be.visible');
cy.getByTestId(cancelAllOrdersBtn).should('be.visible');
cy.getByTestId(cancelOrderBtn).should('have.length.at.least', 1);
cy.getByTestId(editOrderBtn).should('have.length.at.least', 1);
cy.getByTestId('tab-orders').within(() => {
cy.get(`[role='rowgroup']`)
.first()
.within(() => {
cy.get(`[col-id='${orderSymbol}']`).each(($symbol) => {
cy.wrap($symbol).invoke('text').should('not.be.empty');
});
cy.get(`[col-id='${orderSize}']`).each(($size) => {
cy.wrap($size).invoke('text').should('not.be.empty');
});
cy.get(`[col-id='${orderType}']`).each(($type) => {
cy.wrap($type).invoke('text').should('not.be.empty');
});
cy.get(`[col-id='${orderStatus}']`).each(($status) => {
cy.wrap($status).invoke('text').should('not.be.empty');
});
cy.get(`[col-id='${orderRemaining}']`).each(($remaining) => {
cy.wrap($remaining).invoke('text').should('not.be.empty');
});
cy.get(`[col-id='${orderPrice}']`).each(($price) => {
cy.wrap($price).invoke('text').should('not.be.empty');
});
cy.get(`[col-id='${orderTimeInForce}']`).each(($timeInForce) => {
cy.wrap($timeInForce).invoke('text').should('not.be.empty');
});
cy.get(`[col-id='${orderCreatedAt}']`).each(($dateTime) => {
cy.wrap($dateTime).invoke('text').should('not.be.empty');
});
});
});
});
it('partially filled orders should not show close/edit buttons', () => {
const partiallyFilledId =
'94aead3ca92dc932efcb503631b03a410e2a5d4606cae6083e2406dc38e52f78';
cy.getByTestId('tab-orders').should('be.visible');
cy.get('.ag-header-container').within(() => {
cy.get('[col-id="status"]').realHover();
cy.get('[col-id="status"] .ag-icon-menu').click();
});
cy.contains('Partially Filled').click();
cy.getByTestId('All').click();
cy.get(`[row-id="${partiallyFilledId}"]`)
.eq(1)
.within(() => {
cy.get(`[col-id='${orderStatus}']`).should(
'have.text',
'Partially Filled'
);
cy.get(`[col-id='${orderRemaining}']`).should('have.text', '7/10');
cy.getByTestId(cancelOrderBtn).should('not.exist');
cy.getByTestId(editOrderBtn).should('not.exist');
});
});
it('orders are sorted by most recent order', () => {
// 7003-MORD-002
const expectedOrderList = [
'BTCUSD.MF21',
'SOLUSD',
'AAPL.MF21',
'BTCUSD.MF21',
'BTCUSD.MF21',
];
cy.get('.ag-header-container').within(() => {
cy.get('[col-id="status"]').realHover();
cy.get('[col-id="status"] .ag-icon-menu').click();
});
cy.contains('Reset').click();
cy.getByTestId('All').click();
cy.getByTestId('tab-orders')
.get(`.ag-center-cols-container [col-id='${orderSymbol}']`)
.should('have.length.at.least', expectedOrderList.length)
.then(($symbols) => {
const symbolNames: string[] = [];
cy.wrap($symbols)
.each(($symbol) => {
cy.wrap($symbol)
.invoke('text')
.then((text) => {
symbolNames.push(text);
});
})
.then(() => {
expect(symbolNames).to.include.ordered.members(expectedOrderList);
});
});
});
});
describe('subscribe orders', { tags: '@smoke' }, () => {
let orderId = '0';
beforeEach(() => {
const subscriptionMocks = getSubscriptionMocks();
cy.spy(subscriptionMocks, 'OrdersUpdate');
cy.mockTradingPage();
cy.mockSubscription(subscriptionMocks);
cy.setVegaWallet();
cy.visit('/#/markets/market-0');
cy.getByTestId('All').click();
cy.getByTestId('tab-orders').within(() => {
cy.get('[col-id="status"][role="columnheader"]')
.focus()
.find('.ag-header-cell-menu-button')
.click();
cy.get('.ag-filter-apply-panel-button').click();
});
orderId = (parseInt(orderId, 10) + 1).toString();
});
// 7002-SORD-053
// 7002-SORD-040
// 7003-MORD-001
it('must see an active order', () => {
// 7002-SORD-041
updateOrder({
id: orderId,
status: Schema.OrderStatus.STATUS_ACTIVE,
});
cy.getByTestId(`order-status-${orderId}`).should('have.text', 'Active');
});
it('must see an expired order', () => {
// 7002-SORD-042
updateOrder({
id: orderId,
status: Schema.OrderStatus.STATUS_EXPIRED,
});
cy.getByTestId(`order-status-${orderId}`).should('have.text', 'Expired');
});
it('must see a cancelled order', () => {
// 7002-SORD-043
// NOT COVERED: see the txn that cancelled it and a link to the block explorer, if cancelled by a user transaction.
updateOrder({
id: orderId,
status: Schema.OrderStatus.STATUS_CANCELLED,
});
cy.getByTestId(`order-status-${orderId}`).should('have.text', 'Cancelled');
});
it('must see a stopped order', () => {
// 7002-SORD-044
// NOT COVERED: see an explanation of why stopped
updateOrder({
id: orderId,
status: Schema.OrderStatus.STATUS_STOPPED,
});
cy.getByTestId(`order-status-${orderId}`).should('have.text', 'Stopped');
});
it('must see a partially filled order', () => {
// 7002-SORD-045
updateOrder({
id: orderId,
status: Schema.OrderStatus.STATUS_PARTIALLY_FILLED,
size: '5',
remaining: '1',
});
cy.getByTestId(`order-status-${orderId}`).should(
'have.text',
'Partially Filled'
);
cy.getByTestId(`order-status-${orderId}`)
.parentsUntil(`.ag-row`)
.siblings(`[col-id=${orderRemaining}]`)
.should('have.text', '4/5');
});
it('must see a filled order', () => {
// 7002-SORD-046
// NOT COVERED: Must be able to see/link to all trades that were created from this order
updateOrder({
id: orderId,
status: Schema.OrderStatus.STATUS_FILLED,
});
cy.getByTestId(`order-status-${orderId}`).should('have.text', 'Filled');
});
it('must see a rejected order', () => {
// 7002-SORD-047
updateOrder({
id: orderId,
status: Schema.OrderStatus.STATUS_REJECTED,
rejectionReason: Schema.OrderRejectionReason.ORDER_ERROR_INTERNAL_ERROR,
});
cy.getByTestId(`order-status-${orderId}`).should(
'have.text',
'Rejected: Internal error'
);
});
it('must see a parked order', () => {
// 7002-SORD-048
updateOrder({
id: orderId,
status: Schema.OrderStatus.STATUS_PARKED,
});
cy.getByTestId(`order-status-${orderId}`).should(
'have.text',
'Parked: Internal error'
);
});
it('must see the size of the order and direction/side -', () => {
// 7003-MORD-003
// 7003-MORD-004
updateOrder({
id: orderId,
size: '15',
side: Schema.Side.SIDE_SELL,
status: Schema.OrderStatus.STATUS_ACTIVE,
});
cy.get(`[row-id=${orderId}]`)
.find('[col-id="size"]')
.should('have.text', '-15');
});
it('must see the size of the order and direction/side +', () => {
// 7003-MORD-003
// 7003-MORD-004
updateOrder({
id: orderId,
size: '5',
side: Schema.Side.SIDE_BUY,
status: Schema.OrderStatus.STATUS_ACTIVE,
});
cy.get(`[row-id=${orderId}]`)
.find('[col-id="size"]')
.should('have.text', '+5');
});
it('for limit typy must see the Limit price that was set on the order', () => {
// 7003-MORD-005
updateOrder({
id: orderId,
status: Schema.OrderStatus.STATUS_ACTIVE,
});
cy.get(`[row-id=${orderId}]`)
.find('[col-id="price"]')
.should('have.text', '200.00');
});
it('must see a pegged order - ask', () => {
updateOrder({
id: orderId,
side: Schema.Side.SIDE_BUY,
peggedOrder: {
__typename: 'PeggedOrder',
reference: Schema.PeggedReference.PEGGED_REFERENCE_BEST_ASK,
offset: '250000',
},
});
cy.get(`[row-id=${orderId}]`)
.find('[col-id="type"]')
.should('have.text', 'Ask - 2.50 Peg limit');
});
it('must see a pegged order - bid', () => {
updateOrder({
id: orderId,
side: Schema.Side.SIDE_SELL,
peggedOrder: {
__typename: 'PeggedOrder',
reference: Schema.PeggedReference.PEGGED_REFERENCE_BEST_BID,
offset: '100',
},
});
cy.get(`[row-id=${orderId}]`)
.find('[col-id="type"]')
.should('have.text', 'Bid + 0.001 Peg limit');
});
it('must see a pegged order - mid', () => {
updateOrder({
id: orderId,
side: Schema.Side.SIDE_SELL,
peggedOrder: {
__typename: 'PeggedOrder',
reference: Schema.PeggedReference.PEGGED_REFERENCE_MID,
offset: '0.5',
},
});
cy.get(`[row-id=${orderId}]`)
.find('[col-id="type"]')
.should('have.text', 'Mid + 0.00001 Peg limit');
});
it('for market typy must not see a price for active or parked orders', () => {
// 7003-MORD-005
updateOrder({
id: orderId,
type: Schema.OrderType.TYPE_MARKET,
status: Schema.OrderStatus.STATUS_PARKED,
peggedOrder: null,
});
cy.get(`[row-id=${orderId}]`)
.find('[col-id="price"]')
.should('have.text', '-');
});
it('must see the time in force applied to the order', () => {
// 7003-MORD-006
updateOrder({
id: orderId,
type: Schema.OrderType.TYPE_MARKET,
status: Schema.OrderStatus.STATUS_ACTIVE,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
});
cy.get(`[row-id=${orderId}]`)
.find(`[col-id='${orderTimeInForce}']`)
.should('have.text', "Good 'til Cancelled (GTC)");
});
it('for Active order when is part of a liquidity or peg shape, must not see an option to amend the individual order ', () => {
// 7003-MORD-008
updateOrder({
id: orderId,
status: Schema.OrderStatus.STATUS_ACTIVE,
peggedOrder: {},
liquidityProvisionId: '6536',
});
cy.get(`[row-id=${orderId}]`)
.find(`[data-testid="cancel"]`)
.should('not.exist');
cy.get(`[row-id=${orderId}]`)
.find(`[data-testid="edit"]`)
.should('not.exist');
});
it('for Active order when is part of a liquidity, must not see an option to amend the individual order ', () => {
// 7003-MORD-008
updateOrder({
id: orderId,
status: Schema.OrderStatus.STATUS_ACTIVE,
peggedOrder: {},
liquidityProvisionId: '6536',
});
cy.get(`[row-id=${orderId}]`)
.find(`[data-testid="cancel"]`)
.should('not.exist');
cy.get(`[row-id=${orderId}]`)
.find(`[data-testid="edit"]`)
.should('not.exist');
});
it('for Active order when is part of a peg shape, must not see an option to amend the individual order ', () => {
// 7003-MORD-008
updateOrder({
id: orderId,
status: Schema.OrderStatus.STATUS_ACTIVE,
peggedOrder: {},
});
cy.get(`[row-id=${orderId}]`)
.find(`[data-testid="cancel"]`)
.should('not.exist');
cy.get(`[row-id=${orderId}]`)
.find(`[data-testid="edit"]`)
.should('not.exist');
});
});
import { vega as vegaProtos } from '@vegaprotocol/protos';
describe('amend and cancel order', { tags: '@smoke' }, () => {
beforeEach(() => {
@@ -453,8 +53,8 @@ describe('amend and cancel order', { tags: '@smoke' }, () => {
orderId: orderId,
marketId: 'market-0',
price: '10000000',
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
sizeDelta: 0,
timeInForce: vegaProtos.Order.TimeInForce.TIME_IN_FORCE_GTC,
sizeDelta: BigInt(0),
};
testOrderAmendment(order);
});
+2 -2
View File
@@ -1,11 +1,11 @@
import type { OrderSubmission } from '@vegaprotocol/wallet';
import type { OrderObj } from '@vegaprotocol/orders';
const orderSizeField = 'order-size';
const orderPriceField = 'order-price';
const orderTIFDropDown = 'order-tif';
const placeOrderBtn = 'place-order';
export const createOrder = (order: OrderSubmission): void => {
export const createOrder = (order: OrderObj): void => {
cy.log('Placing order', order);
const { type, side, size, price, timeInForce, expiresAt } = order;
@@ -3,14 +3,15 @@ import type {
OrderAmendmentBody,
OrderCancellation,
OrderCancellationBody,
OrderSubmission,
OrderSubmissionBody,
Transaction,
} from '@vegaprotocol/wallet';
import { normalizeOrderSubmission } from '@vegaprotocol/deal-ticket';
import type { OrderObj } from '@vegaprotocol/orders';
export const testOrderSubmission = (
order: OrderSubmission,
expected?: Partial<OrderSubmission>
order: OrderObj,
expected?: Partial<OrderObj>
) => {
const expectedOrder = {
...order,
@@ -18,7 +19,7 @@ export const testOrderSubmission = (
};
const transaction: OrderSubmissionBody = {
orderSubmission: expectedOrder,
orderSubmission: normalizeOrderSubmission(expectedOrder, 0, 0),
};
vegaWalletTransaction(transaction);
verifyToast();
@@ -63,7 +64,7 @@ const vegaWalletTransaction = (transaction: Transaction) => {
expect(req.body.params).to.deep.equal({
publicKey: Cypress.env('VEGA_PUBLIC_KEY'),
sendingMode: 'TYPE_SYNC',
transaction,
transaction: JSON.parse(JSON.stringify(transaction)), // this is because BigInt needs to be serialized
});
expect(req.headers.authorization).to.equal(
`VWT ${Cypress.env('VEGA_WALLET_API_TOKEN')}`
+1
View File
@@ -2,6 +2,7 @@ import '@testing-library/jest-dom';
import 'jest-canvas-mock';
import ResizeObserver from 'resize-observer-polyfill';
import { defaultFallbackInView } from 'react-intersection-observer';
import '../../setup-test';
defaultFallbackInView(true);
global.ResizeObserver = ResizeObserver;
+9 -1
View File
@@ -1,3 +1,11 @@
{
"babelrcRoots": ["*"]
"babelrcRoots": ["*"],
"env": {
"test": {
"presets": [
["@babel/preset-env", { "targets": { "node": "current" } }],
"@babel/preset-typescript"
]
}
}
}
+7 -1
View File
@@ -1,3 +1,9 @@
const nxPreset = require('@nrwl/jest/preset').default;
module.exports = { ...nxPreset };
module.exports = {
...nxPreset,
transformIgnorePatterns: [
...(nxPreset?.transformIgnorePatterns || []),
'node_modules/(?!(@vegaprotocol/protos|protobuf-codec))',
],
};
+1 -1
View File
@@ -8,7 +8,7 @@ export default {
},
},
transform: {
'^.+\\.[tj]sx?$': 'ts-jest',
'^.+\\.[tj]sx?$': 'babel-jest',
},
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
coverageDirectory: '../../coverage/libs/positions',
@@ -23,8 +23,8 @@ const margins: MarginFieldsFragment = {
},
};
const getMargins = jest.fn(() => margins);
const getBalance = jest.fn(() => '0');
const mockGetMargins = jest.fn(() => margins);
const mockGetBalance = jest.fn(() => '0');
jest.mock('./margin-data-provider', () => ({}));
@@ -49,7 +49,7 @@ jest.mock('@vegaprotocol/wallet', () => ({
jest.mock('@vegaprotocol/data-provider', () => ({
useDataProvider: () => {
return {
data: getMargins(),
data: mockGetMargins(),
};
},
}));
@@ -57,7 +57,7 @@ jest.mock('@vegaprotocol/data-provider', () => ({
jest.mock('./use-account-balance', () => ({
useAccountBalance: () => {
return {
accountBalance: getBalance(),
accountBalance: mockGetBalance(),
};
},
}));
@@ -88,7 +88,7 @@ describe('MarginHealthChart', () => {
});
it('should use correct scale', async () => {
getBalance.mockReturnValueOnce('1300');
mockGetBalance.mockReturnValueOnce('1300');
await act(async () => {
render(<MarginHealthChart marketId="marketId" assetId="assetId" />);
});
+42 -32
View File
@@ -7,10 +7,13 @@ import {
} from '@testing-library/react';
import BigNumber from 'bignumber.js';
import { AddressField, TransferFee, TransferForm } from './transfer-form';
import { AccountType } from '@vegaprotocol/types';
import { vega as vegaProtos } from '@vegaprotocol/protos';
import { formatNumber, removeDecimal } from '@vegaprotocol/utils';
describe('TransferForm', () => {
beforeEach(() => {
jest.clearAllMocks();
});
const submit = () => fireEvent.submit(screen.getByTestId('transfer-form'));
const amount = '100';
const pubKey =
@@ -126,12 +129,14 @@ describe('TransferForm', () => {
await waitFor(() => {
expect(props.submitTransfer).toHaveBeenCalledTimes(1);
expect(props.submitTransfer).toHaveBeenCalledWith({
fromAccountType: AccountType.ACCOUNT_TYPE_GENERAL,
toAccountType: AccountType.ACCOUNT_TYPE_GENERAL,
fromAccountType: vegaProtos.AccountType.ACCOUNT_TYPE_GENERAL,
toAccountType: vegaProtos.AccountType.ACCOUNT_TYPE_GENERAL,
to: props.pubKeys[1],
asset: asset.id,
amount: removeDecimal(amount, asset.decimals),
oneOff: {},
kind: null,
reference: '',
});
});
});
@@ -149,21 +154,23 @@ describe('TransferForm', () => {
]);
submit();
expect(await screen.findAllByText('Required')).toHaveLength(3);
// Select a pubkey
fireEvent.change(screen.getByLabelText('Vega key'), {
target: { value: props.pubKeys[1] },
await act(() => {
// Select a pubkey
fireEvent.change(screen.getByLabelText('Vega key'), {
target: { value: props.pubKeys[1] },
});
// Select asset
fireEvent.change(
// Bypass RichSelect and target hidden native select
// eslint-disable-next-line
document.querySelector('select[name="asset"]')!,
{ target: { value: asset.id } }
);
});
// Select asset
fireEvent.change(
// Bypass RichSelect and target hidden native select
// eslint-disable-next-line
document.querySelector('select[name="asset"]')!,
{ target: { value: asset.id } }
);
// assert rich select as updated
expect(await screen.findByTestId('select-asset')).toHaveTextContent(
asset.name
@@ -175,7 +182,7 @@ describe('TransferForm', () => {
const amountInput = screen.getByLabelText('Amount');
const checkbox = screen.getByTestId('include-transfer-fee');
expect(checkbox).not.toBeChecked();
act(() => {
await act(() => {
/* fire events that update state */
// set valid amount
fireEvent.change(amountInput, {
@@ -197,18 +204,20 @@ describe('TransferForm', () => {
expect(screen.getByTestId('total-transfer-fee')).toHaveTextContent(
amount
);
expect(props.submitTransfer).toHaveBeenCalledTimes(0);
submit();
await waitFor(() => {
expect(props.submitTransfer).toHaveBeenCalledTimes(1);
expect(props.submitTransfer).toHaveBeenCalledWith({
fromAccountType: AccountType.ACCOUNT_TYPE_GENERAL,
toAccountType: AccountType.ACCOUNT_TYPE_GENERAL,
fromAccountType: vegaProtos.AccountType.ACCOUNT_TYPE_GENERAL,
toAccountType: vegaProtos.AccountType.ACCOUNT_TYPE_GENERAL,
to: props.pubKeys[1],
asset: asset.id,
amount: removeDecimal(amount, asset.decimals),
amount: removeDecimal(expectedAmount, asset.decimals),
oneOff: {},
kind: null,
reference: '',
});
});
});
@@ -226,20 +235,21 @@ describe('TransferForm', () => {
submit();
expect(await screen.findAllByText('Required')).toHaveLength(3);
await act(() => {
// Select a pubkey
fireEvent.change(screen.getByLabelText('Vega key'), {
target: { value: props.pubKeys[1] },
});
// Select a pubkey
fireEvent.change(screen.getByLabelText('Vega key'), {
target: { value: props.pubKeys[1] },
// Select asset
fireEvent.change(
// Bypass RichSelect and target hidden native select
// eslint-disable-next-line
document.querySelector('select[name="asset"]')!,
{ target: { value: asset.id } }
);
});
// Select asset
fireEvent.change(
// Bypass RichSelect and target hidden native select
// eslint-disable-next-line
document.querySelector('select[name="asset"]')!,
{ target: { value: asset.id } }
);
// assert rich select as updated
expect(await screen.findByTestId('select-asset')).toHaveTextContent(
asset.name
@@ -251,7 +261,7 @@ describe('TransferForm', () => {
const amountInput = screen.getByLabelText('Amount');
const checkbox = screen.getByTestId('include-transfer-fee');
expect(checkbox).not.toBeChecked();
act(() => {
await act(() => {
/* fire events that update state */
// set valid amount
fireEvent.change(amountInput, {
+26 -1
View File
@@ -5,6 +5,7 @@ import {
vegaPublicKey,
addDecimal,
formatNumber,
removeDecimal,
} from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n';
import {
@@ -19,11 +20,12 @@ import {
Checkbox,
} from '@vegaprotocol/ui-toolkit';
import type { Transfer } from '@vegaprotocol/wallet';
import { normalizeTransfer } from '@vegaprotocol/wallet';
import BigNumber from 'bignumber.js';
import type { ReactNode } from 'react';
import { useCallback, useMemo, useState } from 'react';
import { Controller, useForm } from 'react-hook-form';
import type { Exact } from 'type-fest';
import { vega as vegaProtos } from '@vegaprotocol/protos';
interface FormFields {
toAddress: string;
@@ -46,6 +48,29 @@ interface TransferFormProps {
submitTransfer: (transfer: Transfer) => void;
}
export const normalizeTransfer = <T extends Exact<Transfer, T>>(
address: string,
amount: string,
asset: {
id: string;
decimals: number;
}
): Transfer => {
return {
fromAccountType: vegaProtos.AccountType.ACCOUNT_TYPE_GENERAL,
to: address,
toAccountType: vegaProtos.AccountType.ACCOUNT_TYPE_GENERAL,
asset: asset.id,
amount: removeDecimal(amount, asset.decimals),
// oneOff or recurring required otherwise wallet will error
// default oneOff is immediate transfer
oneOff: {},
// to be consistent with proto types
kind: null,
reference: '',
};
};
export const TransferForm = ({
pubKey,
pubKeys,
+1
View File
@@ -1,6 +1,7 @@
import '@testing-library/jest-dom';
import ResizeObserver from 'resize-observer-polyfill';
import { defaultFallbackInView } from 'react-intersection-observer';
import '../../../setup-test';
defaultFallbackInView(true);
global.ResizeObserver = ResizeObserver;
+1
View File
@@ -1 +1,2 @@
import '@testing-library/jest-dom';
import '../../../setup-test';
+2
View File
@@ -1,5 +1,7 @@
import '@testing-library/jest-dom';
import 'jest-canvas-mock';
import '../../../setup-test';
import ResizeObserver from 'resize-observer-polyfill';
global.ResizeObserver = ResizeObserver;
@@ -1,4 +1,4 @@
import * as Schema from '@vegaprotocol/types';
import { vega as vegaProtos } from '@vegaprotocol/protos';
import { determineId } from '../utils';
import { setGraphQLEndpoint } from './request';
import { vote } from './vote';
@@ -63,7 +63,7 @@ export async function createMarket(cfg: {
const proposal = await waitForProposal(proposalId);
// Vote on new market proposal
await vote(proposal.id, Schema.VoteValue.VALUE_YES, cfg.vegaPubKey);
await vote(proposal.id, vegaProtos.Vote.Value.VALUE_YES, cfg.vegaPubKey);
// Wait for the market to be enacted and go into opening auction
await waitForEnactment();
+3 -3
View File
@@ -1,4 +1,4 @@
import type * as Schema from '@vegaprotocol/types';
import type { Value as ProtoOrderTypeValue } from '@vegaprotocol/protos/dist/vega/Vote/Value';
import { createLog } from './logging';
import { sendVegaTx } from './wallet-client';
@@ -6,7 +6,7 @@ const log = createLog('vote');
export async function vote(
proposalId: string,
voteValue: Schema.VoteValue,
voteValue: ProtoOrderTypeValue,
publicKey: string
) {
log(`voting ${voteValue} on ${proposalId}`);
@@ -17,7 +17,7 @@ export async function vote(
return voteResult.result;
}
function createVote(proposalId: string, value: Schema.VoteValue) {
function createVote(proposalId: string, value: ProtoOrderTypeValue) {
return {
voteSubmission: {
value,
@@ -1,4 +1,4 @@
import { PeggedReference } from '@vegaprotocol/types';
import { vega as vegaProtos } from '@vegaprotocol/protos';
import type { LiquidityProvisionSubmission } from '@vegaprotocol/wallet';
import { createWalletClient, sendVegaTx } from '../capsule/wallet-client';
@@ -31,27 +31,28 @@ export const addVegaWalletSubmitLiquidityProvision = () => {
buys: [
{
offset: '10',
proportion: '1',
reference: PeggedReference.PEGGED_REFERENCE_MID,
proportion: 1,
reference: vegaProtos.PeggedReference.PEGGED_REFERENCE_MID,
},
{
offset: '12',
proportion: '2',
reference: PeggedReference.PEGGED_REFERENCE_MID,
proportion: 2,
reference: vegaProtos.PeggedReference.PEGGED_REFERENCE_MID,
},
],
sells: [
{
offset: '10',
proportion: '2',
reference: PeggedReference.PEGGED_REFERENCE_MID,
proportion: 2,
reference: vegaProtos.PeggedReference.PEGGED_REFERENCE_MID,
},
{
offset: '12',
proportion: '2',
reference: PeggedReference.PEGGED_REFERENCE_MID,
proportion: 2,
reference: vegaProtos.PeggedReference.PEGGED_REFERENCE_MID,
},
],
reference: '',
},
pubKey: vegaPubKey,
propagate: true,
@@ -1,4 +1,4 @@
import { AccountType } from '@vegaprotocol/types';
import { vega as vegaProtos } from '@vegaprotocol/protos';
import type { TransferBody } from '@vegaprotocol/wallet';
import { createWalletClient, sendVegaTx } from '../capsule/wallet-client';
@@ -39,15 +39,15 @@ export function addVegaWalletTopUpRewardsPool() {
const transactionBody: TransferBody = {
transfer: {
fromAccountType: AccountType.ACCOUNT_TYPE_GENERAL,
toAccountType: AccountType.ACCOUNT_TYPE_GLOBAL_REWARD,
fromAccountType: vegaProtos.AccountType.ACCOUNT_TYPE_GENERAL,
toAccountType: vegaProtos.AccountType.ACCOUNT_TYPE_GLOBAL_REWARD,
to: '0000000000000000000000000000000000000000000000000000000000000000',
asset: assetAddress,
amount: '1000000000000000000',
recurring: {
factor: '1',
startEpoch: transferStartEpoch,
endEpoch: transferEndEpoch,
startEpoch: BigInt(transferStartEpoch),
endEpoch: BigInt(transferEndEpoch),
},
},
};
@@ -1,6 +1,7 @@
import { AsyncRenderer, Splash } from '@vegaprotocol/ui-toolkit';
import { t } from '@vegaprotocol/i18n';
import { useThrottledDataProvider } from '@vegaprotocol/data-provider';
import type { OrderSubmission } from '@vegaprotocol/wallet';
import { useVegaTransactionStore } from '@vegaprotocol/wallet';
import { useMarket, marketDataProvider } from '@vegaprotocol/markets';
import { DealTicket } from './deal-ticket';
@@ -47,7 +48,11 @@ export const DealTicketContainer = ({
<DealTicket
market={market}
marketData={marketData}
submit={(orderSubmission) => create({ orderSubmission })}
submit={(dealTicketOrder: OrderSubmission) =>
create({
orderSubmission: dealTicketOrder,
})
}
onClickCollateral={onClickCollateral}
onMarketClick={onMarketClick}
/>
@@ -3,10 +3,11 @@ import { VegaWalletContext } from '@vegaprotocol/wallet';
import { act, render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { generateMarket, generateMarketData } from '../../test-helpers';
import { DealTicket } from './deal-ticket';
import { DealTicket, normalizeOrderSubmission } from './deal-ticket';
import * as Schema from '@vegaprotocol/types';
import { MockedProvider } from '@apollo/client/testing';
import { addDecimal } from '@vegaprotocol/utils';
import type { OrderObj } from '@vegaprotocol/orders';
import { useOrderStore } from '@vegaprotocol/orders';
jest.mock('zustand');
@@ -335,4 +336,57 @@ describe('DealTicket', () => {
Object.keys(Schema.OrderTimeInForce).length
);
});
describe('normalizeOrderSubmission', () => {
it('sets and formats price only for limit orders', () => {
expect(
normalizeOrderSubmission({ price: '100' } as unknown as OrderObj, 2, 1)
.price
).toEqual('');
expect(
normalizeOrderSubmission(
{
price: '100',
type: Schema.OrderType.TYPE_LIMIT,
} as unknown as OrderObj,
2,
1
).price
).toEqual('10000');
});
it('sets and formats expiresAt only for time in force orders', () => {
expect(
normalizeOrderSubmission(
{
expiresAt: '2022-01-01T00:00:00.000Z',
} as OrderObj,
2,
1
).expiresAt
).toEqual(BigInt(0));
expect(
normalizeOrderSubmission(
{
expiresAt: '2022-01-01T00:00:00.000Z',
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTT,
} as OrderObj,
2,
1
).expiresAt
).toEqual(BigInt('1640995200000000000'));
});
it('formats size', () => {
expect(
normalizeOrderSubmission(
{
size: '100',
} as OrderObj,
2,
1
).size
).toEqual(BigInt('1000'));
});
});
});
@@ -1,5 +1,5 @@
import { t } from '@vegaprotocol/i18n';
import * as Schema from '@vegaprotocol/types';
import { t } from '@vegaprotocol/i18n';
import { memo, useCallback, useEffect, useState, useRef, useMemo } from 'react';
import { Controller } from 'react-hook-form';
import { DealTicketAmount } from './deal-ticket-amount';
@@ -11,7 +11,10 @@ import { TimeInForceSelector } from './time-in-force-selector';
import { TypeSelector } from './type-selector';
import type { OrderSubmission } from '@vegaprotocol/wallet';
import {
normalizeOrderSubmission,
SideMap,
SideRevertMap,
TimeInForceMap,
TypeMap,
useVegaWallet,
useVegaWalletDialogStore,
} from '@vegaprotocol/wallet';
@@ -24,17 +27,21 @@ import {
Tooltip,
TinyScroll,
} from '@vegaprotocol/ui-toolkit';
import {
useEstimatePositionQuery,
useOpenVolume,
} from '@vegaprotocol/positions';
import { toBigNum, removeDecimal } from '@vegaprotocol/utils';
import {
toBigNum,
removeDecimal,
toNanoSeconds,
isNumeric,
} from '@vegaprotocol/utils';
import type { OrderObj } from '@vegaprotocol/orders';
import { activeOrdersProvider } from '@vegaprotocol/orders';
import { useEstimateFees } from '../../hooks/use-estimate-fees';
import { getDerivedPrice } from '../../utils/get-price';
import type { OrderInfo } from '@vegaprotocol/types';
import {
validateExpiration,
validateMarketState,
@@ -50,10 +57,40 @@ import {
useMarketAccountBalance,
useAccountBalance,
} from '@vegaprotocol/accounts';
import { OrderTimeInForce, OrderType } from '@vegaprotocol/types';
import { useOrderForm } from '../../hooks/use-order-form';
import { useDataProvider } from '@vegaprotocol/data-provider';
import { vega as vegaProtos } from '@vegaprotocol/protos';
export const normalizeOrderSubmission = (
order: OrderObj,
decimalPlaces: number,
positionDecimalPlaces: number
): OrderSubmission => ({
marketId: order.marketId,
type: TypeMap[order.type],
side: SideMap[order.side],
timeInForce: TimeInForceMap[order.timeInForce],
price:
order.type === OrderType.TYPE_LIMIT && order.price
? removeDecimal(order.price, decimalPlaces)
: '',
size: BigInt(removeDecimal(order.size, positionDecimalPlaces)),
expiresAt: BigInt(
order.expiresAt &&
order.timeInForce === OrderTimeInForce.TIME_IN_FORCE_GTT &&
isNumeric(new Date(order.expiresAt).getTime())
? toNanoSeconds(order.expiresAt)
: 0
),
postOnly: Boolean(order.postOnly),
reduceOnly: Boolean(order.reduceOnly),
peggedOrder: {
offset: '',
reference: vegaProtos.PeggedReference.PEGGED_REFERENCE_UNSPECIFIED,
},
reference: '',
});
export interface DealTicketProps {
market: Market;
@@ -121,7 +158,7 @@ export const DealTicket = ({
if (price && normalizedOrder?.size) {
return removeDecimal(
toBigNum(
normalizedOrder.size,
String(normalizedOrder.size),
market.positionDecimalPlaces
).multipliedBy(toBigNum(price, market.decimalPlaces)),
asset.decimals
@@ -136,9 +173,7 @@ export const DealTicket = ({
asset.decimals,
]);
const feeEstimate = useEstimateFees(
normalizedOrder && { ...normalizedOrder, price }
);
const feeEstimate = useEstimateFees(order && { ...order, price });
const { data: activeOrders } = useDataProvider({
dataProvider: activeOrdersProvider,
variables: { partyId: pubKey || '' },
@@ -155,10 +190,10 @@ export const DealTicket = ({
: [];
if (normalizedOrder) {
orders.push({
isMarketOrder: normalizedOrder.type === OrderType.TYPE_MARKET,
isMarketOrder: normalizedOrder.type === TypeMap[OrderType.TYPE_MARKET],
price: normalizedOrder.price ?? '0',
remaining: normalizedOrder.size,
side: normalizedOrder.side,
remaining: String(normalizedOrder.size),
side: SideRevertMap[normalizedOrder.side],
});
}
const { data: positionEstimate } = useEstimatePositionQuery({
@@ -246,7 +281,7 @@ export const DealTicket = ({
}, [order]);
const onSubmit = useCallback(
(order: OrderSubmission) => {
(order: OrderObj) => {
const now = new Date().getTime();
if (lastSubmitTime.current && now - lastSubmitTime.current < 1000) {
return;
+1
View File
@@ -1,2 +1,3 @@
export * from './__generated__/EstimateOrder';
export * from './use-estimate-fees';
export * from './use-order-form';
@@ -1,11 +1,9 @@
import { useVegaWallet } from '@vegaprotocol/wallet';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import { useEstimateFeesQuery } from './__generated__/EstimateOrder';
import type { OrderObj } from '@vegaprotocol/orders';
export const useEstimateFees = (
order?: OrderSubmissionBody['orderSubmission']
) => {
export const useEstimateFees = (order?: OrderObj) => {
const { pubKey } = useVegaWallet();
const { data } = useEstimateFeesQuery({
+1 -5
View File
@@ -3,8 +3,6 @@ import type { OrderObj } from '@vegaprotocol/orders';
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,9 +49,7 @@ export const useOrderForm = (marketId: string) => {
}
}, [order, isSubmitted, getValues, setValue]);
const handleSubmitWrapper = (
cb: <T>(o: Exact<OrderSubmission, T>) => void
) => {
const handleSubmitWrapper = (cb: (o: OrderObj) => void) => {
return handleSubmit(() => {
// remove the persist key from the order in the store, the wallet will reject
// an order that contains unrecognized additional keys
+1
View File
@@ -2,6 +2,7 @@ import '@testing-library/jest-dom';
import 'jest-canvas-mock';
import ResizeObserver from 'resize-observer-polyfill';
import { defaultFallbackInView } from 'react-intersection-observer';
import '../../../setup-test';
defaultFallbackInView(true);
global.ResizeObserver = ResizeObserver;
@@ -1,11 +1,11 @@
import { toDecimal } from '@vegaprotocol/utils';
import * as Schema from '@vegaprotocol/types';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import type { OrderObj } from '@vegaprotocol/orders';
export const getDefaultOrder = (market: {
id: string;
positionDecimalPlaces: number;
}): OrderSubmissionBody['orderSubmission'] => ({
}): Partial<OrderObj> => ({
marketId: market.id,
type: Schema.OrderType.TYPE_MARKET,
side: Schema.Side.SIDE_BUY,
+4 -4
View File
@@ -1,7 +1,7 @@
import * as Schema from '@vegaprotocol/types';
import { isMarketInAuction } from './is-market-in-auction';
import type { MarketData } from '@vegaprotocol/markets';
import { vega as vegaProtos } from '@vegaprotocol/protos';
import type { Type as OrderType } from '@vegaprotocol/protos/dist/vega/Order';
/**
* Get the market price based on market mode (auction or not auction)
*/
@@ -30,7 +30,7 @@ export const getMarketPrice = (marketData: MarketData) => {
*/
export const getDerivedPrice = (
order: {
type: Schema.OrderType;
type: OrderType.Type;
price?: string | undefined;
},
marketData: MarketData
@@ -41,7 +41,7 @@ export const getDerivedPrice = (
// Use the market price if order is a market order
let price;
if (order.type === Schema.OrderType.TYPE_LIMIT && order.price) {
if (order.type === vegaProtos.Order.Type.TYPE_LIMIT && order.price) {
price = order.price;
} else {
price = getMarketPrice(marketData);
+1
View File
@@ -1,4 +1,5 @@
import '@testing-library/jest-dom';
import ResizeObserver from 'resize-observer-polyfill';
import '../../../setup-test';
global.ResizeObserver = ResizeObserver;
+1
View File
@@ -1,5 +1,6 @@
import '@testing-library/jest-dom';
import 'jest-canvas-mock';
import '../../../setup-test';
Object.defineProperty(window, 'matchMedia', {
writable: true,
+1
View File
@@ -1,4 +1,5 @@
import '@testing-library/jest-dom';
import ResizeObserver from 'resize-observer-polyfill';
import '../../../setup-test';
global.ResizeObserver = ResizeObserver;
@@ -1,5 +1,9 @@
import { render, screen, act } from '@testing-library/react';
import { OrderListManager } from './order-list-manager';
import * as Schema from '@vegaprotocol/types';
import {
OrderListManager,
normalizeOrderAmendment,
} from './order-list-manager';
import * as useDataProviderHook from '@vegaprotocol/data-provider';
import type { OrderFieldsFragment } from '../';
import * as orderListMock from '../order-list/order-list';
@@ -7,6 +11,7 @@ import { forwardRef } from 'react';
import type { VegaWalletContextShape } from '@vegaprotocol/wallet';
import { VegaWalletContext } from '@vegaprotocol/wallet';
import { MockedProvider } from '@apollo/client/testing';
import { vega as vegaProtos } from '@vegaprotocol/protos';
// @ts-ignore OrderList is read only but we need to override with the forwardRef to
// avoid warnings about padding refs
@@ -39,3 +44,57 @@ describe('OrderListManager', () => {
expect(await screen.findByText('OrderList')).toBeInTheDocument();
});
});
describe('normalizeOrderAmendment', () => {
type Order = Parameters<typeof normalizeOrderAmendment>[0];
type Market = Parameters<typeof normalizeOrderAmendment>[1];
const order: Order = {
id: '123',
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTT,
size: '100',
expiresAt: '2022-01-01T00:00:00.000Z',
};
const market: Market = {
id: '456',
decimalPlaces: 1,
positionDecimalPlaces: 1,
};
it('sets and formats order id, market id, expires and timeInForce as given', () => {
const orderAmendment = normalizeOrderAmendment(order, market, '1', '1');
expect(orderAmendment.orderId).toEqual('123');
expect(orderAmendment.marketId).toEqual('456');
expect(orderAmendment.expiresAt).toEqual(BigInt('1640995200000000000'));
expect(orderAmendment.timeInForce).toEqual(
vegaProtos.Order.TimeInForce.TIME_IN_FORCE_GTT
);
});
it.each([
['1.1', 1, '11'],
['1.1', 2, '110'],
['0.001', 8, '100000'],
])('sets and formats price', (price, decimalPlaces, output) => {
const orderAmendment = normalizeOrderAmendment(
order,
{ ...market, decimalPlaces },
price,
'1'
);
expect(orderAmendment.price).toEqual(output);
});
it.each([
['9', 1, BigInt(-10)],
['90', 2, BigInt(8900)],
['0.001', 8, BigInt(99900)],
])('sets and formats size delta', (size, positionDecimalPlaces, output) => {
const orderAmendment = normalizeOrderAmendment(
order,
{ ...market, positionDecimalPlaces },
'1',
size
);
expect(orderAmendment.sizeDelta).toEqual(output);
});
});
@@ -3,20 +3,21 @@ import { useCallback, useRef, useState } from 'react';
import { Button } from '@vegaprotocol/ui-toolkit';
import type { AgGridReact } from 'ag-grid-react';
import type { GridReadyEvent, FilterChangedEvent } from 'ag-grid-community';
import { OrderListTable } from '../order-list/order-list';
import { useHasAmendableOrder } from '../../order-hooks/use-has-amendable-order';
import { useBottomPlaceholder } from '@vegaprotocol/datagrid';
import { useDataProvider } from '@vegaprotocol/data-provider';
import { ordersWithMarketProvider } from '../order-data-provider/order-data-provider';
import {
normalizeOrderAmendment,
useVegaTransactionStore,
} from '@vegaprotocol/wallet';
import type { Transaction, OrderAmendment } from '@vegaprotocol/wallet';
import { TimeInForceMap, useVegaTransactionStore } from '@vegaprotocol/wallet';
import type { OrderTxUpdateFieldsFragment } from '@vegaprotocol/wallet';
import { OrderEditDialog } from '../order-list/order-edit-dialog';
import type { Order } from '../order-data-provider';
import { OrderStatus } from '@vegaprotocol/types';
import type { Exact } from 'type-fest';
import { isNumeric, removeDecimal, toNanoSeconds } from '@vegaprotocol/utils';
import BigNumber from 'bignumber.js';
import * as Schema from '@vegaprotocol/types';
import { vega as vegaProtos } from '@vegaprotocol/protos';
export enum Filter {
'Open',
@@ -25,15 +26,18 @@ export enum Filter {
}
const FilterStatusValue = {
[Filter.Open]: [OrderStatus.STATUS_ACTIVE, OrderStatus.STATUS_PARKED],
[Filter.Closed]: [
OrderStatus.STATUS_CANCELLED,
OrderStatus.STATUS_EXPIRED,
OrderStatus.STATUS_FILLED,
OrderStatus.STATUS_PARTIALLY_FILLED,
OrderStatus.STATUS_STOPPED,
[Filter.Open]: [
Schema.OrderStatus.STATUS_ACTIVE,
Schema.OrderStatus.STATUS_PARKED,
],
[Filter.Rejected]: [OrderStatus.STATUS_REJECTED],
[Filter.Closed]: [
Schema.OrderStatus.STATUS_CANCELLED,
Schema.OrderStatus.STATUS_EXPIRED,
Schema.OrderStatus.STATUS_FILLED,
Schema.OrderStatus.STATUS_PARTIALLY_FILLED,
Schema.OrderStatus.STATUS_STOPPED,
],
[Filter.Rejected]: [Schema.OrderStatus.STATUS_REJECTED],
};
export interface OrderListManagerProps {
@@ -47,6 +51,32 @@ export interface OrderListManagerProps {
storeKey?: string;
}
export const normalizeOrderAmendment = <T extends Exact<OrderAmendment, T>>(
order: Pick<Order, 'id' | 'timeInForce' | 'size' | 'expiresAt'>,
market: Pick<Schema.Market, 'id' | 'decimalPlaces' | 'positionDecimalPlaces'>,
price: string,
size: string
): OrderAmendment => ({
orderId: order.id,
marketId: market.id,
price: removeDecimal(price, market.decimalPlaces),
timeInForce: TimeInForceMap[order.timeInForce],
sizeDelta: BigInt(
size
? new BigNumber(removeDecimal(size, market.positionDecimalPlaces))
.minus(order.size)
.toNumber()
: 0
),
expiresAt: BigInt(
order.expiresAt && isNumeric(new Date(order.expiresAt).getTime())
? toNanoSeconds(order.expiresAt) // Wallet expects timestamp in nanoseconds
: 0
),
peggedOffset: '',
peggedReference: vegaProtos.PeggedReference.PEGGED_REFERENCE_UNSPECIFIED,
});
const CancelAllOrdersButton = ({ onClick }: { onClick: () => void }) => (
<div className="dark:bg-black/75 bg-white/75 h-auto flex justify-end px-[11px] py-2 absolute bottom-0 right-3 rounded">
<Button
@@ -135,7 +165,7 @@ export const OrderListManager = ({
const cancelAll = useCallback(() => {
create({
orderCancellation: {},
});
} as Transaction);
}, [create]);
return (
@@ -190,7 +220,12 @@ export const OrderListManager = ({
side: editOrder.side,
marketId: editOrder.market.id,
};
create({ orderAmendment }, originalOrder);
create(
{
orderAmendment,
},
originalOrder
);
setEditOrder(null);
}}
/>
@@ -12,7 +12,7 @@ export type OrderObj = {
timeInForce: OrderTimeInForce;
price?: string;
expiresAt?: string | undefined;
persist: boolean; // key used to determine if order should be kept in localStorage
persist?: boolean; // key used to determine if order should be kept in localStorage
postOnly?: boolean;
reduceOnly?: boolean;
};
+1
View File
@@ -1,4 +1,5 @@
import '@testing-library/jest-dom';
import ResizeObserver from 'resize-observer-polyfill';
import '../../../setup-test';
global.ResizeObserver = ResizeObserver;
+8 -7
View File
@@ -2,11 +2,12 @@ import { useRef } from 'react';
import { usePositionsData } from './use-positions-data';
import { PositionsTable } from './positions-table';
import type { AgGridReact } from 'ag-grid-react';
import * as Schema from '@vegaprotocol/types';
import type { Transaction } from '@vegaprotocol/wallet';
import { useVegaTransactionStore } from '@vegaprotocol/wallet';
import { t } from '@vegaprotocol/i18n';
import { useBottomPlaceholder } from '@vegaprotocol/datagrid';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { vega as vegaProtos } from '@vegaprotocol/protos';
interface PositionsManagerProps {
partyIds: string[];
@@ -45,17 +46,17 @@ export const PositionsManager = ({
submissions: [
{
marketId: marketId,
type: Schema.OrderType.TYPE_MARKET as const,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_IOC as const,
type: vegaProtos.Order.Type.TYPE_MARKET,
timeInForce: vegaProtos.Order.TimeInForce.TIME_IN_FORCE_IOC,
side: openVolume.startsWith('-')
? Schema.Side.SIDE_BUY
: Schema.Side.SIDE_SELL,
size: openVolume.replace('-', ''),
? vegaProtos.Side.SIDE_BUY
: vegaProtos.Side.SIDE_SELL,
size: BigInt(openVolume.replace('-', '')),
reduceOnly: true,
},
],
},
});
} as Transaction);
const bottomPlaceholderProps = useBottomPlaceholder({
gridRef,
+1
View File
@@ -1,4 +1,5 @@
import '@testing-library/jest-dom';
import ResizeObserver from 'resize-observer-polyfill';
import '../../../setup-test';
global.ResizeObserver = ResizeObserver;
@@ -2,8 +2,9 @@ import { useCallback, useState } from 'react';
import * as Sentry from '@sentry/react';
import { useVegaTransaction, useVegaWallet } from '@vegaprotocol/wallet';
import { useVoteEvent } from './use-vote-event';
import type { VoteValue } from '@vegaprotocol/types';
import { VoteValue } from '@vegaprotocol/types';
import type { VoteEventFieldsFragment } from './__generated__/VoteSubsciption';
import { vega as vegaProtos } from '@vegaprotocol/protos';
export type FinalizedVote = VoteEventFieldsFragment & { pubKey: string };
@@ -27,7 +28,10 @@ export const useVoteSubmit = () => {
try {
const res = await send(pubKey, {
voteSubmission: {
value: voteValue,
value:
voteValue === VoteValue.VALUE_NO
? vegaProtos.Vote.Value.VALUE_NO
: vegaProtos.Vote.Value.VALUE_YES,
proposalId,
},
});
+1
View File
@@ -1,4 +1,5 @@
import '@testing-library/jest-dom';
import ResizeObserver from 'resize-observer-polyfill';
import '../../../setup-test';
global.ResizeObserver = ResizeObserver;
@@ -164,10 +164,9 @@ export const DropdownMenuSeparator = forwardRef<
/**
* Container element for submenus
*/
export const DropdownMenuSub = forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Sub>,
React.ComponentProps<typeof DropdownMenuPrimitive.Sub>
>(({ ...subProps }) => <DropdownMenuPrimitive.Sub {...subProps} />);
export const DropdownMenuSub = ({ ...subProps }) => (
<DropdownMenuPrimitive.Sub {...subProps} />
);
/**
* Container within a DropdownMenuSub specifically for the content
@@ -201,10 +200,9 @@ export const DropdownMenuSubTrigger = forwardRef<
* Portal to ensure menu portions are rendered outwith where they appear in the
* DOM.
*/
export const DropdownMenuPortal = forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Portal>,
React.ComponentProps<typeof DropdownMenuPrimitive.Portal>
>(({ ...portalProps }) => <DropdownMenuPrimitive.Portal {...portalProps} />);
export const DropdownMenuPortal = ({ ...portalProps }) => (
<DropdownMenuPrimitive.Portal {...portalProps} />
);
/**
* Wraps a regular DropdownMenuItem with copy to clip board functionality
+7
View File
@@ -45,6 +45,13 @@
"options": {
"command": "yarn tsc --project ./libs/wallet/tsconfig.spec.json"
}
},
"generate": {
"executor": "nx:run-commands",
"outputs": [],
"options": {
"command": "protoc --plugin=./node_modules/.bin/protoc-gen-ts_proto --ts_proto_out=./libs/wallet/src/__generated__ $WALLET_TRANSACTIONS_SOURCE --proto_path=$WALLET_TRANSACTIONS_ROOT --ts_proto_opt=onlyTypes=true"
}
}
}
}
+81 -131
View File
@@ -1,98 +1,29 @@
import { WalletClientError } from '@vegaprotocol/wallet-client';
import type * as Schema from '@vegaprotocol/types';
import type { PeggedReference } from '@vegaprotocol/types';
import type { SetOptional } from 'type-fest';
import type { vega as vegaProtos } from '@vegaprotocol/protos';
import type { RecurringTransfer } from '@vegaprotocol/protos/dist/vega/commands/v1/RecurringTransfer';
export interface LiquidityProvisionSubmission {
liquidityProvisionSubmission: LiquidityProvisionBody;
pubKey: string;
propagate: boolean;
}
export interface LiquidityProvisionBody {
marketId: string;
commitmentAmount: string;
fee: string;
buys?: PeggedOrders[];
sells?: PeggedOrders[];
}
export type OrderSubmission =
vegaProtos.commands.v1.OrderSubmission.OrderSubmission;
export type OriginalOrderCancellation =
vegaProtos.commands.v1.OrderCancellation.OrderCancellation;
export type LiquidityProvisionBody =
vegaProtos.commands.v1.LiquidityProvisionSubmission.LiquidityProvisionSubmission;
export type DelegateSubmission =
vegaProtos.commands.v1.DelegateSubmission.DelegateSubmission;
export type UndelegateSubmission =
vegaProtos.commands.v1.UndelegateSubmission.UndelegateSubmission;
export type OrderAmendment =
vegaProtos.commands.v1.OrderAmendment.OrderAmendment;
export type VoteSubmission =
vegaProtos.commands.v1.VoteSubmission.VoteSubmission;
export type OriginalWithdrawSubmission =
vegaProtos.commands.v1.WithdrawSubmission.WithdrawSubmission;
export type OriginalBatchMarketInstructions =
vegaProtos.commands.v1.BatchMarketInstructions.BatchMarketInstructions;
export type OriginalTransfer = vegaProtos.commands.v1.Transfer.Transfer;
export interface PeggedOrders {
offset: string;
proportion: string;
reference: PeggedReference;
}
export interface DelegateSubmissionBody {
delegateSubmission: {
nodeId: string;
amount: string;
};
}
export interface UndelegateSubmissionBody {
undelegateSubmission: {
nodeId: string;
amount: string;
method: 'METHOD_NOW' | 'METHOD_AT_END_OF_EPOCH';
};
}
export interface OrderSubmission {
marketId: string;
reference?: string;
type: Schema.OrderType;
side: Schema.Side;
timeInForce: Schema.OrderTimeInForce;
size: string;
price?: string;
expiresAt?: string;
postOnly?: boolean;
reduceOnly?: boolean;
}
export interface OrderCancellation {
orderId?: string;
marketId?: string;
}
export interface OrderAmendment {
marketId: string;
orderId: string;
reference?: string;
timeInForce: Schema.OrderTimeInForce;
sizeDelta?: number;
price?: string;
expiresAt?: string;
}
export interface OrderSubmissionBody {
orderSubmission: OrderSubmission;
}
export interface OrderCancellationBody {
orderCancellation: OrderCancellation;
}
export interface OrderAmendmentBody {
orderAmendment: OrderAmendment;
}
export interface VoteSubmissionBody {
voteSubmission: {
value: Schema.VoteValue;
proposalId: string;
};
}
export interface WithdrawSubmissionBody {
withdrawSubmission: {
amount: string;
asset: string;
ext: {
erc20: {
receiverAddress: string;
};
};
};
}
type WithdrawExt = vegaProtos.WithdrawExt.WithdrawExt;
interface ProposalNewMarketTerms {
newMarket: {
@@ -302,52 +233,71 @@ export interface ProposalSubmission {
| ProposalUpdateAssetTerms;
}
// generated type doesn't match in many places with current implementation. It has to be overwrite here
// and re-exported for saving consistency.
export type WithdrawSubmission = Omit<OriginalWithdrawSubmission, 'ext'> &
WithdrawExt;
export type OrderCancellation = SetOptional<
OriginalOrderCancellation,
'orderId' | 'marketId'
>;
export type BatchMarketInstructions = SetOptional<
OriginalBatchMarketInstructions,
'submissions' | 'amendments' | 'cancellations'
> & {
submissions?: OrderSubmission[];
};
export type Transfer = SetOptional<OriginalTransfer, 'reference' | 'kind'> & {
oneOff?: {
deliverOn?: number; // omit for immediate
};
recurring?: SetOptional<RecurringTransfer, 'dispatchStrategy'>;
};
export interface LiquidityProvisionSubmission {
liquidityProvisionSubmission: LiquidityProvisionBody;
pubKey: string;
propagate: boolean;
}
export interface DelegateSubmissionBody {
delegateSubmission: DelegateSubmission;
}
export interface UndelegateSubmissionBody {
undelegateSubmission: UndelegateSubmission;
}
export interface OrderSubmissionBody {
orderSubmission: OrderSubmission;
}
export interface OrderCancellationBody {
orderCancellation: OrderCancellation;
}
export interface OrderAmendmentBody {
orderAmendment: OrderAmendment;
}
export interface VoteSubmissionBody {
voteSubmission: VoteSubmission;
}
export interface WithdrawSubmissionBody {
withdrawSubmission: WithdrawSubmission;
}
export interface ProposalSubmissionBody {
proposalSubmission: ProposalSubmission;
}
export interface BatchMarketInstructionSubmissionBody {
batchMarketInstructions: {
// Will be processed in this order and the total amount of instructions is
// restricted by the net param spam.protection.max.batchSize
cancellations?: OrderCancellation[];
amendments?: OrderAmendment[];
// Note: If multiple orders are submitted the first order ID is determined by hashing the signature of the transaction
// (see determineId function). For each subsequent order's ID, a hash of the previous orders ID is used
submissions?: OrderSubmission[];
};
batchMarketInstructions: BatchMarketInstructions;
}
interface TransferBase {
fromAccountType: Schema.AccountType;
to: string;
toAccountType: Schema.AccountType;
asset: string;
amount: string;
reference?: string;
}
export interface OneOffTransfer extends TransferBase {
oneOff: {
deliverOn?: number; // omit for immediate
};
}
export interface RecurringTransfer extends TransferBase {
recurring: {
factor: string;
startEpoch: number;
endEpoch?: number;
dispatchStrategy?: {
assetForMetric: string;
metric: Schema.DispatchMetric;
markets?: string[];
};
};
}
export type Transfer = OneOffTransfer | RecurringTransfer;
export interface TransferBody {
transfer: Transfer;
}
+1
View File
@@ -1,4 +1,5 @@
import '@testing-library/jest-dom';
import ResizeObserver from 'resize-observer-polyfill';
import '../../../setup-test';
global.ResizeObserver = ResizeObserver;
@@ -5,6 +5,11 @@ import { ClientErrors } from './connectors';
import { VegaTxStatus, orderErrorResolve } from './use-vega-transaction';
import { useVegaTransactionStore } from './use-vega-transaction-store';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(BigInt.prototype as any).toJSON = function () {
return this.toString();
};
export const useVegaTransactionManager = () => {
const { sendTx, pubKey, disconnect } = useVegaWallet();
const processed = useRef<Set<number>>(new Set());
@@ -1,17 +1,20 @@
import { useVegaTransactionStore } from './use-vega-transaction-store';
import { VegaTxStatus } from './use-vega-transaction';
import type { VegaStoredTxState } from './use-vega-transaction-store';
import type {
OrderAmendmentBody,
OrderCancellationBody,
WithdrawSubmissionBody,
} from './connectors/vega-connector';
import {
OrderStatus,
OrderTimeInForce,
OrderType,
Side,
} from '@vegaprotocol/types';
import { vega as vegaProtos } from '@vegaprotocol/protos';
import type {
WithdrawSubmission,
OrderCancellation,
OrderCancellationBody,
WithdrawSubmissionBody,
OrderAmendment,
} from './connectors';
jest.mock('./utils', () => ({
...jest.requireActual('./utils'),
@@ -19,7 +22,9 @@ jest.mock('./utils', () => ({
}));
describe('useVegaTransactionStore', () => {
const orderCancellation: OrderCancellationBody = { orderCancellation: {} };
const orderCancellation: OrderCancellationBody = {
orderCancellation: {} as OrderCancellation,
};
const withdrawSubmission: WithdrawSubmissionBody = {
withdrawSubmission: {
amount: 'amount',
@@ -29,19 +34,16 @@ describe('useVegaTransactionStore', () => {
receiverAddress: 'receiverAddress',
},
},
},
} as unknown as WithdrawSubmission,
};
const orderAmendment: OrderAmendmentBody = {
orderAmendment: {
orderId:
'6a4fcd0ba478df2f284ef5f6d3c64a478cb8043d3afe36f66f92c0ed92631e64',
marketId:
'3aa2a828687cc3d59e92445d294891cbbd40e2165bbfb15674158ef5d4e8848d',
price: '1122',
timeInForce: OrderTimeInForce.TIME_IN_FORCE_GTC,
sizeDelta: 0,
},
const orderAmendment: OrderAmendment = {
orderId: '6a4fcd0ba478df2f284ef5f6d3c64a478cb8043d3afe36f66f92c0ed92631e64',
marketId:
'3aa2a828687cc3d59e92445d294891cbbd40e2165bbfb15674158ef5d4e8848d',
price: '1122',
timeInForce: vegaProtos.Order.TimeInForce.TIME_IN_FORCE_GTC,
sizeDelta: BigInt(0),
};
const originalOrder = {
@@ -99,9 +101,15 @@ describe('useVegaTransactionStore', () => {
});
it('updates an order with order amendment', () => {
useVegaTransactionStore.getState().create(orderAmendment, originalOrder);
useVegaTransactionStore.getState().create(orderAmendment, originalOrder);
useVegaTransactionStore.getState().create(orderAmendment, originalOrder);
useVegaTransactionStore
.getState()
.create({ orderAmendment }, originalOrder);
useVegaTransactionStore
.getState()
.create({ orderAmendment }, originalOrder);
useVegaTransactionStore
.getState()
.create({ orderAmendment }, originalOrder);
const transaction = useVegaTransactionStore.getState().transactions[1];
useVegaTransactionStore
.getState()
@@ -127,8 +135,8 @@ describe('useVegaTransactionStore', () => {
orderId:
'6a4fcd0ba478df2f284ef5f6d3c64a478cb8043d3afe36f66f92c0ed92631e64',
price: '1122',
sizeDelta: 0,
timeInForce: OrderTimeInForce.TIME_IN_FORCE_GTC,
sizeDelta: BigInt(0),
timeInForce: vegaProtos.Order.TimeInForce.TIME_IN_FORCE_GTC,
},
};
expect(
@@ -131,30 +131,34 @@ export const useVegaTransactionStore = create<VegaTransactionStore>()(
set(
produce((state: VegaTransactionStore) => {
const transaction = state.transactions.find((transaction) => {
if (!transaction || transaction.status !== VegaTxStatus.Pending) {
if (
!transaction ||
transaction.status !== VegaTxStatus.Pending ||
!transaction?.body
) {
return false;
}
if (
isOrderSubmissionTransaction(transaction?.body) &&
isOrderSubmissionTransaction(transaction.body) &&
transaction.signature &&
order.id === determineId(transaction.signature)
) {
return true;
}
if (
isOrderCancellationTransaction(transaction?.body) &&
isOrderCancellationTransaction(transaction.body) &&
order.id === transaction.body.orderCancellation.orderId
) {
return true;
}
if (
isOrderAmendmentTransaction(transaction?.body) &&
isOrderAmendmentTransaction(transaction.body) &&
order.id === transaction.body.orderAmendment.orderId
) {
return true;
}
if (
isBatchMarketInstructionsTransaction(transaction?.body) &&
isBatchMarketInstructionsTransaction(transaction.body) &&
transaction.signature &&
order.id === determineId(transaction.signature)
) {
+2 -117
View File
@@ -1,10 +1,5 @@
import {
determineId,
normalizeOrderAmendment,
normalizeOrderSubmission,
} from './utils';
import type { OrderSubmissionBody } from './connectors/vega-connector';
import * as Schema from '@vegaprotocol/types';
import { determineId } from './utils';
describe('determineId', () => {
it('produces a known result for an ID', () => {
const res = determineId(
@@ -15,113 +10,3 @@ describe('determineId', () => {
);
});
});
describe('normalizeOrderSubmission', () => {
it('sets and formats price only for limit orders', () => {
expect(
normalizeOrderSubmission(
{ price: '100' } as unknown as OrderSubmissionBody['orderSubmission'],
2,
1
).price
).toBeUndefined();
expect(
normalizeOrderSubmission(
{
price: '100',
type: Schema.OrderType.TYPE_LIMIT,
} as unknown as OrderSubmissionBody['orderSubmission'],
2,
1
).price
).toEqual('10000');
});
it('sets and formats expiresAt only for time in force orders', () => {
expect(
normalizeOrderSubmission(
{
expiresAt: '2022-01-01T00:00:00.000Z',
} as OrderSubmissionBody['orderSubmission'],
2,
1
).expiresAt
).toBeUndefined();
expect(
normalizeOrderSubmission(
{
expiresAt: '2022-01-01T00:00:00.000Z',
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTT,
} as OrderSubmissionBody['orderSubmission'],
2,
1
).expiresAt
).toEqual('1640995200000000000');
});
it('formats size', () => {
expect(
normalizeOrderSubmission(
{
size: '100',
} as OrderSubmissionBody['orderSubmission'],
2,
1
).size
).toEqual('1000');
});
});
describe('normalizeOrderAmendment', () => {
type Order = Parameters<typeof normalizeOrderAmendment>[0];
type Market = Parameters<typeof normalizeOrderAmendment>[1];
const order: Order = {
id: '123',
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTT,
size: '100',
expiresAt: '2022-01-01T00:00:00.000Z',
};
const market: Market = {
id: '456',
decimalPlaces: 1,
positionDecimalPlaces: 1,
};
it('sets and formats order id, market id, expires and timeInForce as given', () => {
const orderAmendment = normalizeOrderAmendment(order, market, '1', '1');
expect(orderAmendment.orderId).toEqual('123');
expect(orderAmendment.marketId).toEqual('456');
expect(orderAmendment.expiresAt).toEqual('1640995200000000000');
expect(orderAmendment.timeInForce).toEqual(
Schema.OrderTimeInForce.TIME_IN_FORCE_GTT
);
});
it.each([
['1.1', 1, '11'],
['1.1', 2, '110'],
['0.001', 8, '100000'],
])('sets and formats price', (price, decimalPlaces, output) => {
const orderAmendment = normalizeOrderAmendment(
order,
{ ...market, decimalPlaces },
price,
'1'
);
expect(orderAmendment.price).toEqual(output);
});
it.each([
['9', 1, -10],
['90', 2, 8900],
['0.001', 8, 99900],
])('sets and formats size delta', (size, positionDecimalPlaces, output) => {
const orderAmendment = normalizeOrderAmendment(
order,
{ ...market, positionDecimalPlaces },
'1',
size
);
expect(orderAmendment.sizeDelta).toEqual(output);
});
});
+55 -72
View File
@@ -1,16 +1,11 @@
import { removeDecimal, toNanoSeconds } from '@vegaprotocol/utils';
import type { Market, Order } from '@vegaprotocol/types';
import { OrderTimeInForce, OrderType, AccountType } from '@vegaprotocol/types';
import BigNumber from 'bignumber.js';
import * as Schema from '@vegaprotocol/types';
import { ethers } from 'ethers';
import { sha3_256 } from 'js-sha3';
import type {
OrderAmendment,
OrderSubmission,
Transaction,
Transfer,
} from './connectors';
import type { Exact } from 'type-fest';
import type { Transaction } from './connectors';
import { vega as vegaProtos } from '@vegaprotocol/protos';
import type { Side } from '@vegaprotocol/protos/dist/vega/Side';
import type { TimeInForce } from '@vegaprotocol/protos/dist/vega/Order/TimeInForce';
import type { Type as ProtoOrderType } from '@vegaprotocol/protos/dist/vega/Order';
/**
* Creates an ID in the same way that core does on the backend. This way we
@@ -29,65 +24,53 @@ export const encodeTransaction = (tx: Transaction): string => {
);
};
export const normalizeOrderSubmission = (
order: OrderSubmission,
decimalPlaces: number,
positionDecimalPlaces: number
): OrderSubmission => ({
marketId: order.marketId,
reference: order.reference,
type: order.type,
side: order.side,
timeInForce: order.timeInForce,
price:
order.type === OrderType.TYPE_LIMIT && order.price
? removeDecimal(order.price, decimalPlaces)
: undefined,
size: removeDecimal(order.size, positionDecimalPlaces),
expiresAt:
order.expiresAt && order.timeInForce === OrderTimeInForce.TIME_IN_FORCE_GTT
? toNanoSeconds(order.expiresAt)
: undefined,
postOnly: order.postOnly,
reduceOnly: order.reduceOnly,
});
export const normalizeOrderAmendment = <T extends Exact<OrderAmendment, T>>(
order: Pick<Order, 'id' | 'timeInForce' | 'size' | 'expiresAt'>,
market: Pick<Market, 'id' | 'decimalPlaces' | 'positionDecimalPlaces'>,
price: string,
size: string
): OrderAmendment => ({
orderId: order.id,
marketId: market.id,
price: removeDecimal(price, market.decimalPlaces),
timeInForce: order.timeInForce,
sizeDelta: size
? new BigNumber(removeDecimal(size, market.positionDecimalPlaces))
.minus(order.size)
.toNumber()
: 0,
expiresAt: order.expiresAt
? toNanoSeconds(order.expiresAt) // Wallet expects timestamp in nanoseconds
: undefined,
});
export const normalizeTransfer = <T extends Exact<Transfer, T>>(
address: string,
amount: string,
asset: {
id: string;
decimals: number;
}
): Transfer => {
return {
fromAccountType: AccountType.ACCOUNT_TYPE_GENERAL,
to: address,
toAccountType: AccountType.ACCOUNT_TYPE_GENERAL,
asset: asset.id,
amount: removeDecimal(amount, asset.decimals),
// oneOff or recurring required otherwise wallet will error
// default oneOff is immediate transfer
oneOff: {},
};
export const SideMap: Readonly<Record<Schema.Side, Side>> = {
[Schema.Side.SIDE_BUY]: vegaProtos.Side.SIDE_BUY,
[Schema.Side.SIDE_SELL]: vegaProtos.Side.SIDE_SELL,
[Schema.Side.SIDE_UNSPECIFIED]: vegaProtos.Side.SIDE_UNSPECIFIED,
};
export const SideRevertMap: Record<Side, Schema.Side> = Object.entries(
SideMap
).reduce((agg, item) => {
agg[item[1]] = item[0] as Schema.Side;
return agg;
}, {} as Record<Side, Schema.Side>);
export const TimeInForceMap: Readonly<
Record<Schema.OrderTimeInForce, TimeInForce>
> = {
[Schema.OrderTimeInForce.TIME_IN_FORCE_FOK]:
vegaProtos.Order.TimeInForce.TIME_IN_FORCE_FOK,
[Schema.OrderTimeInForce.TIME_IN_FORCE_GFA]:
vegaProtos.Order.TimeInForce.TIME_IN_FORCE_GFA,
[Schema.OrderTimeInForce.TIME_IN_FORCE_GFN]:
vegaProtos.Order.TimeInForce.TIME_IN_FORCE_GFN,
[Schema.OrderTimeInForce.TIME_IN_FORCE_GTC]:
vegaProtos.Order.TimeInForce.TIME_IN_FORCE_GTC,
[Schema.OrderTimeInForce.TIME_IN_FORCE_GTT]:
vegaProtos.Order.TimeInForce.TIME_IN_FORCE_GTT,
[Schema.OrderTimeInForce.TIME_IN_FORCE_IOC]:
vegaProtos.Order.TimeInForce.TIME_IN_FORCE_IOC,
};
export const TimeInForceRevertMap: Record<
TimeInForce,
Schema.OrderTimeInForce
> = Object.entries(TimeInForceMap).reduce((agg, item) => {
agg[item[1]] = item[0] as Schema.OrderTimeInForce;
return agg;
}, {} as Record<TimeInForce, Schema.OrderTimeInForce>);
export const TypeMap: Readonly<Record<Schema.OrderType, ProtoOrderType.Type>> =
{
[Schema.OrderType.TYPE_LIMIT]: vegaProtos.Order.Type.TYPE_LIMIT,
[Schema.OrderType.TYPE_MARKET]: vegaProtos.Order.Type.TYPE_MARKET,
[Schema.OrderType.TYPE_NETWORK]: vegaProtos.Order.Type.TYPE_NETWORK,
};
export const TypeRevertMap: Record<ProtoOrderType.Type, Schema.OrderType> =
Object.entries(TypeMap).reduce((agg, item) => {
agg[item[1]] = item[0] as Schema.OrderType;
return agg;
}, {} as Record<ProtoOrderType.Type, Schema.OrderType>);
@@ -5,7 +5,12 @@ import {
OrderType,
Side,
} from '@vegaprotocol/types';
import type { VegaStoredTxState } from '@vegaprotocol/wallet';
import { vega as vegaProtos } from '@vegaprotocol/protos';
import type {
Transaction,
VegaStoredTxState,
OrderSubmission,
} from '@vegaprotocol/wallet';
import { VegaTxStatus } from '@vegaprotocol/wallet';
import {
VegaTransactionDetails,
@@ -118,11 +123,19 @@ const submitOrder: VegaStoredTxState = {
body: {
orderSubmission: {
marketId: 'market-1',
side: Side.SIDE_BUY,
size: '10',
timeInForce: OrderTimeInForce.TIME_IN_FORCE_FOK,
type: OrderType.TYPE_MARKET,
side: vegaProtos.Side.SIDE_BUY,
size: BigInt(10),
timeInForce: vegaProtos.Order.TimeInForce.TIME_IN_FORCE_FOK,
type: vegaProtos.Order.Type.TYPE_MARKET,
price: '1234',
expiresAt: BigInt(0),
postOnly: false,
reduceOnly: false,
peggedOrder: {
offset: '',
reference: vegaProtos.PeggedReference.PEGGED_REFERENCE_UNSPECIFIED,
},
reference: '',
},
},
status: VegaTxStatus.Default,
@@ -151,9 +164,9 @@ const editOrder: VegaStoredTxState = {
orderAmendment: {
marketId: 'market-1',
orderId: '0',
timeInForce: OrderTimeInForce.TIME_IN_FORCE_FOK,
timeInForce: vegaProtos.Order.TimeInForce.TIME_IN_FORCE_FOK,
price: '1000',
sizeDelta: 1,
sizeDelta: BigInt(1),
},
},
status: VegaTxStatus.Default,
@@ -200,7 +213,7 @@ const cancelAll: VegaStoredTxState = {
marketId: undefined,
orderId: undefined,
},
},
} as Transaction,
status: VegaTxStatus.Default,
error: null,
txHash: null,
@@ -218,15 +231,15 @@ const closePosition: VegaStoredTxState = {
submissions: [
{
marketId: 'market-1',
side: Side.SIDE_BUY,
size: '10',
timeInForce: OrderTimeInForce.TIME_IN_FORCE_FOK,
type: OrderType.TYPE_MARKET,
side: vegaProtos.Side.SIDE_BUY,
size: BigInt(10),
timeInForce: vegaProtos.Order.TimeInForce.TIME_IN_FORCE_FOK,
type: vegaProtos.Order.Type.TYPE_MARKET,
price: '1234',
},
} as OrderSubmission,
],
},
},
} as Transaction,
status: VegaTxStatus.Default,
error: null,
txHash: null,
@@ -243,15 +256,15 @@ const batch: VegaStoredTxState = {
submissions: [
{
marketId: 'market-1',
side: Side.SIDE_BUY,
size: '10',
timeInForce: OrderTimeInForce.TIME_IN_FORCE_FOK,
type: OrderType.TYPE_MARKET,
side: vegaProtos.Side.SIDE_BUY,
size: BigInt(10),
timeInForce: vegaProtos.Order.TimeInForce.TIME_IN_FORCE_FOK,
type: vegaProtos.Order.Type.TYPE_MARKET,
price: '1234',
},
],
},
},
} as Transaction,
status: VegaTxStatus.Default,
error: null,
txHash: null,
@@ -1,12 +1,11 @@
import { useCallback } from 'react';
import first from 'lodash/first';
import compact from 'lodash/compact';
import type { OrderSubmission, OrderAmendment } from '@vegaprotocol/wallet';
import type {
BatchMarketInstructionSubmissionBody,
OrderAmendment,
OrderTxUpdateFieldsFragment,
OrderCancellationBody,
OrderSubmission,
VegaStoredTxState,
WithdrawalBusEventFieldsFragment,
} from '@vegaprotocol/wallet';
@@ -22,6 +21,7 @@ import {
isWithdrawTransaction,
useVegaTransactionStore,
VegaTxStatus,
SideRevertMap,
} from '@vegaprotocol/wallet';
import type { Toast, ToastContent } from '@vegaprotocol/ui-toolkit';
import { ToastHeading } from '@vegaprotocol/ui-toolkit';
@@ -134,8 +134,8 @@ const SubmitOrderDetails = ({
if (!market) return null;
const price = order ? order.price : data.price;
const size = order ? order.size : data.size;
const side = order ? order.side : data.side;
const size = order ? order.size : String(data.size);
const side = order ? order.side : SideRevertMap[data.side];
return (
<Panel>
@@ -201,8 +201,8 @@ const EditOrderDetails = ({
const edited = (
<SizeAtPrice
side={originalOrder.side}
size={String(Number(originalOrder.size) + (data.sizeDelta || 0))}
price={data.price}
size={String(Number(originalOrder.size) + Number(data.sizeDelta || 0))}
price={String(data.price)}
meta={{
positionDecimalPlaces: market.positionDecimalPlaces,
decimalPlaces: market.decimalPlaces,
+1
View File
@@ -1 +1,2 @@
import '@testing-library/jest-dom';
import '../../../setup-test';
+1 -1
View File
@@ -4,7 +4,7 @@ export default {
preset: '../../jest.preset.js',
transform: {
'^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nrwl/react/plugins/jest',
'^.+\\.[tj]sx?$': 'ts-jest',
'^.+\\.[tj]sx?$': 'babel-jest',
},
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
coverageDirectory: '../../coverage/libs/withdraws',
@@ -22,7 +22,7 @@ export const CreateWithdrawalDialog = () => {
>
<WithdrawFormContainer
assetId={assetId}
partyId={pubKey ? pubKey : undefined}
partyId={pubKey || undefined}
submit={({ amount, asset, receiverAddress }) => {
createTransaction({
withdrawSubmission: {
@@ -12,7 +12,7 @@ jest.mock('@web3-react/core', () => ({
useWeb3React: () => ({ account: ethereumAddress }),
}));
const withdrawAsset = {
const mockWithdrawAsset = {
asset,
balance: new BigNumber(1),
min: new BigNumber(0.0000001),
@@ -22,7 +22,7 @@ const withdrawAsset = {
};
jest.mock('./use-withdraw-asset', () => ({
useWithdrawAsset: () => withdrawAsset,
useWithdrawAsset: () => mockWithdrawAsset,
}));
jest.mock('@vegaprotocol/accounts', () => ({
@@ -30,10 +30,11 @@ jest.mock('@vegaprotocol/accounts', () => ({
useAccountBalance: jest.fn(() => ({ accountBalance: 0, accountDecimals: 0 })),
}));
const mockWithdrawThreshold = new BigNumber(100);
jest.mock('@vegaprotocol/web3', () => ({
...jest.requireActual('@vegaprotocol/web3'),
useGetWithdrawThreshold: () => {
return () => Promise.resolve(new BigNumber(100));
return () => Promise.resolve(mockWithdrawThreshold);
},
useGetWithdrawDelay: () => {
return () => Promise.resolve(10000);
@@ -128,7 +129,7 @@ describe('WithdrawManager', () => {
});
it('shows withdraw delay notification if threshold is 0', async () => {
withdrawAsset.threshold = new BigNumber(0);
mockWithdrawAsset.threshold = new BigNumber(0);
render(generateJsx(props));
fireEvent.change(screen.getByLabelText('Amount'), {
target: { value: '0.01' },
+2
View File
@@ -1,5 +1,7 @@
import '@testing-library/jest-dom';
import ResizeObserver from 'resize-observer-polyfill';
import '../../../setup-test';
global.ResizeObserver = ResizeObserver;
declare global {
+10 -1
View File
@@ -39,6 +39,7 @@
"@sentry/nextjs": "^6.19.3",
"@sentry/react": "^6.19.2",
"@sentry/tracing": "^6.19.2",
"@vegaprotocol/protos": "^0.4.0",
"@vegaprotocol/wallet-client": "0.1.9",
"@walletconnect/ethereum-provider": "^2.6.0",
"@web3-react/coinbase-wallet": "8.1.2-beta.0",
@@ -99,11 +100,14 @@
"@babel/core": "7.12.13",
"@babel/plugin-proposal-export-default-from": "^7.18.10",
"@babel/preset-env": "^7.18.10",
"@babel/preset-react": "^7.22.5",
"@babel/preset-typescript": "7.12.13",
"@commitlint/cli": "^16.2.4",
"@commitlint/config-conventional": "^16.2.4",
"@commitlint/config-nx-scopes": "^17.4.2",
"@cypress/grep": "^3.1.0",
"@cypress/webpack-batteries-included-preprocessor": "^2.4.1",
"@cypress/webpack-preprocessor": "^5.17.1",
"@ethersproject/experimental": "^5.6.0",
"@graphql-codegen/cli": "^2.11.8",
"@graphql-codegen/near-operation-file-preset": "^2.4.1",
@@ -158,7 +162,8 @@
"@typescript-eslint/parser": "5.35.1",
"autoprefixer": "10.4.8",
"babel-jest": "27.5.1",
"babel-loader": "8.1.0",
"babel-loader": "^9.1.2",
"css-loader": "^6.8.1",
"cypress": "^12.9.0",
"cypress-mochawesome-reporter": "^3.3.0",
"cypress-real-events": "^1.8.1",
@@ -195,10 +200,14 @@
"replace-in-file": "^6.3.2",
"resize-observer-polyfill": "^1.5.1",
"sass": "1.54.0",
"sass-loader": "^13.3.2",
"storybook-addon-themes": "^6.1.0",
"style-loader": "^3.3.3",
"tailwindcss": "^3.2.4",
"ts-jest": "27.1.4",
"ts-node": "10.9.1",
"ts-proto": "^1.148.2",
"ts-protoc-gen": "^0.15.0",
"tslib": "^2.0.0",
"type-fest": "^3.8.0",
"typescript": "^5.0.4",
+8
View File
@@ -0,0 +1,8 @@
import { TextEncoder, TextDecoder } from 'util';
(global as any).TextEncoder = TextEncoder;
(global as any).TextDecoder = TextDecoder;
(BigInt.prototype as any).toJSON = function () {
return this.toString();
};
+1346 -37
View File
File diff suppressed because it is too large Load Diff