Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b4ba1fa90 | ||
|
|
ede5146c36 | ||
|
|
a5d53eee77 | ||
|
|
4dd63da62b | ||
|
|
2e8dd294de | ||
|
|
8917ceb08a | ||
|
|
87f116daee | ||
|
|
9e91746488 | ||
|
|
5b4ed1a0c3 | ||
|
|
56731e34cc | ||
|
|
026e5f5679 | ||
|
|
e75c160579 |
@@ -50,6 +50,20 @@ jobs:
|
||||
projects=[${projects// /,}]
|
||||
echo PROJECTS=$projects >> $GITHUB_ENV
|
||||
|
||||
# Rename required because some of the files contains the colon character (in the dates)
|
||||
- name: Rename files to allow archive
|
||||
if: ${{ always() }}
|
||||
run: |
|
||||
while read -r file; do
|
||||
mv "${file}" "$(echo ${file} | sed 's|:|-|g')"
|
||||
done< <(find /home/runner/.vegacapsule/testnet/logs -type f)
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
if: ${{ always() }}
|
||||
with:
|
||||
name: logs-${{ matrix.project }}
|
||||
path: /home/runner/.vegacapsule/testnet/logs
|
||||
|
||||
outputs:
|
||||
projects: ${{ env.PROJECTS }}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useExplorerDeterministicOrderQuery } from '../order-details/__generated__/Order';
|
||||
import PriceInMarket from '../price-in-market/price-in-market';
|
||||
import { sideText } from '../order-details/lib/order-labels';
|
||||
import SizeInMarket from '../size-in-market/size-in-market';
|
||||
|
||||
// Note: Edited has no style currently
|
||||
export type OrderSummaryModifier = 'cancelled' | 'edited';
|
||||
@@ -41,7 +42,8 @@ const OrderSummary = ({ id, modifier }: OrderSummaryProps) => {
|
||||
return (
|
||||
<div data-testid="order-summary" className={getClassName(modifier)}>
|
||||
<span>{sideText[order.side]}</span>
|
||||
<span>{order.size}</span> <i>@</i>
|
||||
<SizeInMarket marketId={order.market.id} size={order.size} />
|
||||
<i>@</i>
|
||||
<PriceInMarket marketId={order.market.id} price={order.price} />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -112,13 +112,14 @@ describe('Order TX Summary component', () => {
|
||||
const res = renderComponent(o, [mock]);
|
||||
expect(res.queryByTestId('order-summary')).toBeInTheDocument();
|
||||
expect(res.getByText('Buy')).toBeInTheDocument();
|
||||
expect(res.getByText('10')).toBeInTheDocument();
|
||||
|
||||
// Initially renders price alone
|
||||
// Initially renders price and size unformatted
|
||||
expect(res.getByText('333')).toBeInTheDocument();
|
||||
expect(res.getByText('10')).toBeInTheDocument();
|
||||
|
||||
// After fetch renders formatted price and asset quotename
|
||||
expect(await res.findByText('3.33')).toBeInTheDocument();
|
||||
expect(await res.findByText('TEST')).toBeInTheDocument();
|
||||
expect(await res.getByText('0.10')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { components } from '../../../types/explorer';
|
||||
|
||||
import PriceInMarket from '../price-in-market/price-in-market';
|
||||
import { sideText } from '../order-details/lib/order-labels';
|
||||
import SizeInMarket from '../size-in-market/size-in-market';
|
||||
|
||||
export type OrderSummaryProps = {
|
||||
order: components['schemas']['v1OrderSubmission'];
|
||||
@@ -29,7 +30,12 @@ const OrderTxSummary = ({ order }: OrderSummaryProps) => {
|
||||
return (
|
||||
<div data-testid="order-summary">
|
||||
<span>{sideText[order.side]}</span>
|
||||
<span>{order.size}</span> <i className="text-xs">@</i>
|
||||
{order.size ? (
|
||||
<SizeInMarket size={order.size} marketId={order.marketId} />
|
||||
) : (
|
||||
'-'
|
||||
)}
|
||||
<i className="text-xs">@</i>
|
||||
<PriceInMarket
|
||||
marketId={order.marketId}
|
||||
price={order.price}
|
||||
|
||||
@@ -7,7 +7,7 @@ import type { DecimalSource } from './size-in-market';
|
||||
import { ExplorerMarketDocument } from '../links/market-link/__generated__/Market';
|
||||
|
||||
function renderComponent(
|
||||
price: string,
|
||||
size: string | undefined,
|
||||
marketId: string,
|
||||
mocks: MockedResponse[],
|
||||
decimalSource: DecimalSource = 'MARKET'
|
||||
@@ -17,7 +17,7 @@ function renderComponent(
|
||||
<MemoryRouter>
|
||||
<SizeInMarket
|
||||
marketId={marketId}
|
||||
size={price}
|
||||
size={size}
|
||||
decimalSource={decimalSource}
|
||||
/>
|
||||
</MemoryRouter>
|
||||
@@ -57,6 +57,11 @@ const fullMock = {
|
||||
};
|
||||
|
||||
describe('Size in Market component', () => {
|
||||
it('Renders a dash size when there is no size', () => {
|
||||
const res = render(renderComponent(undefined, '123', []));
|
||||
expect(res.getByText('-')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Renders the raw size when there is no market data', () => {
|
||||
const res = render(renderComponent('100', '123', []));
|
||||
expect(res.getByText('100')).toBeInTheDocument();
|
||||
|
||||
@@ -5,7 +5,7 @@ export type DecimalSource = 'MARKET';
|
||||
|
||||
export type PriceInMarketProps = {
|
||||
marketId: string;
|
||||
size: string | number;
|
||||
size?: string | number;
|
||||
decimalSource?: DecimalSource;
|
||||
};
|
||||
|
||||
@@ -22,6 +22,9 @@ const SizeInMarket = ({
|
||||
variables: { id: marketId },
|
||||
fetchPolicy: 'cache-first',
|
||||
});
|
||||
if (!size) {
|
||||
return <span>-</span>;
|
||||
}
|
||||
|
||||
let label = size;
|
||||
|
||||
|
||||
+2
-4
@@ -39,10 +39,8 @@ export const MarketList = () => {
|
||||
|
||||
const getRowId = useCallback(({ data }: GetRowIdParams) => data.id, []);
|
||||
|
||||
const localData = data?.markets;
|
||||
|
||||
return (
|
||||
<AsyncRenderer loading={loading} error={error} data={localData}>
|
||||
<AsyncRenderer loading={loading} error={error} data={data}>
|
||||
<div
|
||||
className="grow w-full"
|
||||
style={{ minHeight: 500, overflow: 'hidden' }}
|
||||
@@ -57,7 +55,7 @@ export const MarketList = () => {
|
||||
);
|
||||
},
|
||||
}}
|
||||
rowData={localData}
|
||||
rowData={data}
|
||||
defaultColDef={{
|
||||
resizable: true,
|
||||
sortable: true,
|
||||
|
||||
@@ -115,7 +115,7 @@
|
||||
"tranche_end": "2023-12-05T00:00:00.000Z",
|
||||
"total_added": "86666.297",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "71112.3321837696257405828",
|
||||
"locked_amount": "70875.3107442288190769439",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "86666.297",
|
||||
@@ -181,7 +181,7 @@
|
||||
"tranche_end": "2023-06-01T00:00:00.000Z",
|
||||
"total_added": "2500",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "1545.241751882377",
|
||||
"locked_amount": "1531.52981277981275",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "2500",
|
||||
@@ -568,8 +568,8 @@
|
||||
"tranche_start": "2023-02-01T00:00:00.000Z",
|
||||
"tranche_end": "2023-08-01T00:00:00.000Z",
|
||||
"total_added": "37500",
|
||||
"total_removed": "183.137181525",
|
||||
"locked_amount": "35944.80653391651375",
|
||||
"total_removed": "328.1417856",
|
||||
"locked_amount": "35737.9910988336375",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "7500",
|
||||
@@ -587,6 +587,11 @@
|
||||
"amount": "183.137181525",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tx": "0x326ded5446d14472f79d487ece43dd7db760fec5df52e310342930db38fb5de1"
|
||||
},
|
||||
{
|
||||
"amount": "145.004604075",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tx": "0x6171eb144528a90bd3a51c6aacec83d4f40d63ffee5388a1c0b8318bee460042"
|
||||
}
|
||||
],
|
||||
"users": [
|
||||
@@ -606,11 +611,17 @@
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tranche_id": 34,
|
||||
"tx": "0x326ded5446d14472f79d487ece43dd7db760fec5df52e310342930db38fb5de1"
|
||||
},
|
||||
{
|
||||
"amount": "145.004604075",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tranche_id": 34,
|
||||
"tx": "0x6171eb144528a90bd3a51c6aacec83d4f40d63ffee5388a1c0b8318bee460042"
|
||||
}
|
||||
],
|
||||
"total_tokens": "7500",
|
||||
"withdrawn_tokens": "183.137181525",
|
||||
"remaining_tokens": "7316.862818475"
|
||||
"withdrawn_tokens": "328.1417856",
|
||||
"remaining_tokens": "7171.8582144"
|
||||
},
|
||||
{
|
||||
"address": "0x0B4e6fcE839B01ef43DA6F890FAC7B1Afb004600",
|
||||
@@ -635,7 +646,7 @@
|
||||
"tranche_end": "2023-12-05T00:00:00.000Z",
|
||||
"total_added": "129999.45",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "71047.451128348659886215",
|
||||
"locked_amount": "70810.64594104826369394",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "129999.45",
|
||||
@@ -701,7 +712,7 @@
|
||||
"tranche_end": "2023-09-03T00:00:00.000Z",
|
||||
"total_added": "62600",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "35415.06666032470672",
|
||||
"locked_amount": "35243.8635210553031",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "10000",
|
||||
@@ -894,7 +905,7 @@
|
||||
"tranche_end": "2023-09-17T00:00:00.000Z",
|
||||
"total_added": "5000",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "3020.4602676306445",
|
||||
"locked_amount": "3006.7858954845255",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "5000",
|
||||
@@ -1105,7 +1116,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "97499.58",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "12913.1328103802082906612",
|
||||
"locked_amount": "12680.8489810395158446602",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "97499.58",
|
||||
@@ -1138,7 +1149,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "135173.4239508",
|
||||
"total_removed": "98230.390980249184455396",
|
||||
"locked_amount": "17650.023192413700622871272848",
|
||||
"locked_amount": "17332.53129983515100413698276",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "135173.4239508",
|
||||
@@ -1184,7 +1195,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "32499.86",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "5432.3319754511083747504",
|
||||
"locked_amount": "5334.6141797746525149112",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "32499.86",
|
||||
@@ -1217,7 +1228,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "10833.29",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "1768.171343907611431555",
|
||||
"locked_amount": "1736.3651496459689709353",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "10833.29",
|
||||
@@ -1250,7 +1261,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "22749.93",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "6609.8193974640044998578",
|
||||
"locked_amount": "6490.920739528795672116",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "6500",
|
||||
@@ -1388,8 +1399,8 @@
|
||||
"tranche_start": "2022-11-01T00:00:00.000Z",
|
||||
"tranche_end": "2023-05-01T00:00:00.000Z",
|
||||
"total_added": "22500",
|
||||
"total_removed": "3995.28612255",
|
||||
"locked_amount": "10130.41983195211725",
|
||||
"total_removed": "4140.290726625",
|
||||
"locked_amount": "10006.330570902395325",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "7500",
|
||||
@@ -1418,6 +1429,11 @@
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tx": "0x3f253311d975a353930c10981b742ac3b0df52da085d437244f077b63ec32953"
|
||||
},
|
||||
{
|
||||
"amount": "145.004604075",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tx": "0x8050aa26e1965d26aa350efbc83e48c1b95f8c0933f35dee35fbcdd43cb08dcc"
|
||||
},
|
||||
{
|
||||
"amount": "305.3119245",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
@@ -1499,6 +1515,12 @@
|
||||
"tranche_id": 33,
|
||||
"tx": "0x3f253311d975a353930c10981b742ac3b0df52da085d437244f077b63ec32953"
|
||||
},
|
||||
{
|
||||
"amount": "145.004604075",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tranche_id": 33,
|
||||
"tx": "0x8050aa26e1965d26aa350efbc83e48c1b95f8c0933f35dee35fbcdd43cb08dcc"
|
||||
},
|
||||
{
|
||||
"amount": "305.3119245",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
@@ -1561,8 +1583,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "7500",
|
||||
"withdrawn_tokens": "3995.28612255",
|
||||
"remaining_tokens": "3504.71387745"
|
||||
"withdrawn_tokens": "4140.290726625",
|
||||
"remaining_tokens": "3359.709273375"
|
||||
},
|
||||
{
|
||||
"address": "0x2539b51EbDE65a75672aBcfE9439a706a99D18D1",
|
||||
@@ -1587,7 +1609,7 @@
|
||||
"tranche_end": "2023-06-02T00:00:00.000Z",
|
||||
"total_added": "1939928.38",
|
||||
"total_removed": "928642.9598472029154",
|
||||
"locked_amount": "603203.9854527480689673466",
|
||||
"locked_amount": "597898.524931760479177335",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "1852091.69",
|
||||
@@ -1938,7 +1960,7 @@
|
||||
"tranche_start": "2022-08-01T00:00:00.000Z",
|
||||
"tranche_end": "2023-02-01T00:00:00.000Z",
|
||||
"total_added": "42500",
|
||||
"total_removed": "24434.0787288",
|
||||
"total_removed": "30000",
|
||||
"locked_amount": "0",
|
||||
"deposits": [
|
||||
{
|
||||
@@ -1953,6 +1975,11 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "5565.9212712",
|
||||
"user": "0x0B4e6fcE839B01ef43DA6F890FAC7B1Afb004600",
|
||||
"tx": "0x1e37e1c281da391a5bb1ce5ad16cdcc78dba1cb97a1e46103dc4b07725f9ab9e"
|
||||
},
|
||||
{
|
||||
"amount": "1982.0652174",
|
||||
"user": "0x0B4e6fcE839B01ef43DA6F890FAC7B1Afb004600",
|
||||
@@ -2001,6 +2028,12 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "5565.9212712",
|
||||
"user": "0x0B4e6fcE839B01ef43DA6F890FAC7B1Afb004600",
|
||||
"tranche_id": 17,
|
||||
"tx": "0x1e37e1c281da391a5bb1ce5ad16cdcc78dba1cb97a1e46103dc4b07725f9ab9e"
|
||||
},
|
||||
{
|
||||
"amount": "1982.0652174",
|
||||
"user": "0x0B4e6fcE839B01ef43DA6F890FAC7B1Afb004600",
|
||||
@@ -2027,8 +2060,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "30000",
|
||||
"withdrawn_tokens": "24434.0787288",
|
||||
"remaining_tokens": "5565.9212712"
|
||||
"withdrawn_tokens": "30000",
|
||||
"remaining_tokens": "0"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -33570,7 +33603,7 @@
|
||||
"tranche_end": "2023-06-05T00:00:00.000Z",
|
||||
"total_added": "3732368.4671",
|
||||
"total_removed": "592998.0503546212334",
|
||||
"locked_amount": "951415.83704816660962319369",
|
||||
"locked_amount": "943263.19139257341189174758",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "1998.95815",
|
||||
@@ -34895,8 +34928,8 @@
|
||||
"tranche_start": "2022-06-05T00:00:00.000Z",
|
||||
"tranche_end": "2023-12-05T00:00:00.000Z",
|
||||
"total_added": "15870102.715470999700000001",
|
||||
"total_removed": "560497.18500562348693952",
|
||||
"locked_amount": "8673347.0570783123228140520127045570383887",
|
||||
"total_removed": "561830.98711463838793952",
|
||||
"locked_amount": "8644438.2990334618538022518075508209678292",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "16249.93",
|
||||
@@ -35475,6 +35508,16 @@
|
||||
"user": "0xE6CacAE56Cca8dFdB7910b5A13578719D4E57DA0",
|
||||
"tx": "0x86280b4d0cccc9e251d0f18fce5af974d0e1fb31a1aaf219725a27efb0d607f4"
|
||||
},
|
||||
{
|
||||
"amount": "718.26845",
|
||||
"user": "0xF4c75FdbAe821C6B5DBB9f001bB23cBA58D1bA37",
|
||||
"tx": "0x71e2885c8c466c935c3fdcc7618896e149ebd155ff432f9c95b993c9f134547a"
|
||||
},
|
||||
{
|
||||
"amount": "615.533659014901",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tx": "0x61b0366935b55d5f021bbf4c0e1c7595e1a8628fe24c135e62e66d82dc9cc021"
|
||||
},
|
||||
{
|
||||
"amount": "858.360074993579125",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
@@ -37100,6 +37143,12 @@
|
||||
"tranche_id": 2,
|
||||
"tx": "0xb6a33b8b8855789fbc2d0f9545ba5c2258e52f143d90bc75bbe2411bd2f9b4a5"
|
||||
},
|
||||
{
|
||||
"amount": "615.533659014901",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tranche_id": 2,
|
||||
"tx": "0x61b0366935b55d5f021bbf4c0e1c7595e1a8628fe24c135e62e66d82dc9cc021"
|
||||
},
|
||||
{
|
||||
"amount": "858.360074993579125",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
@@ -38188,8 +38237,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "259998.8875",
|
||||
"withdrawn_tokens": "117484.092376092228875",
|
||||
"remaining_tokens": "142514.795123907771125"
|
||||
"withdrawn_tokens": "118099.626035107129875",
|
||||
"remaining_tokens": "141899.261464892870125"
|
||||
},
|
||||
{
|
||||
"address": "0x89051CAb67Bc7F8CC44F7e270c6EDaf1EC57676c",
|
||||
@@ -38849,6 +38898,12 @@
|
||||
"tranche_id": 2,
|
||||
"tx": "0x94fe358ee7c973dd1d28ca4c56250dfaccbcb718673872c8e9cf8651a22a1108"
|
||||
},
|
||||
{
|
||||
"amount": "718.26845",
|
||||
"user": "0xF4c75FdbAe821C6B5DBB9f001bB23cBA58D1bA37",
|
||||
"tranche_id": 2,
|
||||
"tx": "0x71e2885c8c466c935c3fdcc7618896e149ebd155ff432f9c95b993c9f134547a"
|
||||
},
|
||||
{
|
||||
"amount": "1099.300488",
|
||||
"user": "0xF4c75FdbAe821C6B5DBB9f001bB23cBA58D1bA37",
|
||||
@@ -39031,8 +39086,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "200000",
|
||||
"withdrawn_tokens": "90095.748006",
|
||||
"remaining_tokens": "109904.251994"
|
||||
"withdrawn_tokens": "90814.016456",
|
||||
"remaining_tokens": "109185.983544"
|
||||
},
|
||||
{
|
||||
"address": "0x1b956E6c00E238194B331eddEFF72Cb5f28A8d01",
|
||||
@@ -40384,8 +40439,8 @@
|
||||
"tranche_start": "2021-11-05T00:00:00.000Z",
|
||||
"tranche_end": "2023-05-05T00:00:00.000Z",
|
||||
"total_added": "14597706.0446472999",
|
||||
"total_removed": "3921707.576409189114087282",
|
||||
"locked_amount": "2285733.39696055204772238928937325",
|
||||
"total_removed": "3922560.622544070958832032",
|
||||
"locked_amount": "2259045.016117707539647181202605103",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "129284.449",
|
||||
@@ -40649,6 +40704,11 @@
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tx": "0x0c292f2355b5cdc3b389ed35e6e138e593b1db9d91fcd58f132835343724bf90"
|
||||
},
|
||||
{
|
||||
"amount": "853.04613488184474475",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tx": "0xe2b3e0f908fa79636a02b919ede475f86857f0588badd6c85249eb97802fc331"
|
||||
},
|
||||
{
|
||||
"amount": "8950.14985089483210984",
|
||||
"user": "0x66827bCD635f2bB1779d68c46aEB16541bCA6ba8",
|
||||
@@ -43492,6 +43552,12 @@
|
||||
"tranche_id": 3,
|
||||
"tx": "0x0c292f2355b5cdc3b389ed35e6e138e593b1db9d91fcd58f132835343724bf90"
|
||||
},
|
||||
{
|
||||
"amount": "853.04613488184474475",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tranche_id": 3,
|
||||
"tx": "0xe2b3e0f908fa79636a02b919ede475f86857f0588badd6c85249eb97802fc331"
|
||||
},
|
||||
{
|
||||
"amount": "1192.05386354121365675",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
@@ -45882,8 +45948,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "359123.469575",
|
||||
"withdrawn_tokens": "302309.38363864041348675",
|
||||
"remaining_tokens": "56814.08593635958651325"
|
||||
"withdrawn_tokens": "303162.4297735222582315",
|
||||
"remaining_tokens": "55961.0398014777417685"
|
||||
},
|
||||
{
|
||||
"address": "0xBdd412797c1B78535Afc5F71503b91fAbD0160fB",
|
||||
@@ -47221,7 +47287,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "5778205.3912159303",
|
||||
"total_removed": "2730068.739915456784546642",
|
||||
"locked_amount": "586203.563337309134341622543222115",
|
||||
"locked_amount": "575658.944918433408911164999611974",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "552496.6455",
|
||||
@@ -49204,7 +49270,7 @@
|
||||
"tranche_end": "2023-06-05T00:00:00.000Z",
|
||||
"total_added": "472355.6199999996",
|
||||
"total_removed": "32520.5457984892685",
|
||||
"locked_amount": "150757.26292676673422831001319128",
|
||||
"locked_amount": "149465.44459842708862109310096396",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "3000",
|
||||
|
||||
@@ -866,6 +866,10 @@ context(
|
||||
|
||||
cy.get(stakeTokenSubmitButton).should('contain', 'Add 1 $VEGA tokens');
|
||||
});
|
||||
|
||||
after('teardown wallet', function () {
|
||||
cy.vega_wallet_teardown();
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -10,6 +10,16 @@ const pendingStake = '[data-testid="pending-stake"]';
|
||||
const stakedByOperator = '[data-testid="staked-by-operator"]';
|
||||
const stakedByDelegates = '[data-testid="staked-by-delegates"]';
|
||||
const stakeShare = '[data-testid="stake-percentage"]';
|
||||
const stakedByOperatorToolTip = "[data-testid='staked-operator-tooltip']";
|
||||
const stakedByDelegatesToolTip = "[data-testid='staked-delegates-tooltip']";
|
||||
const totalStakedToolTip = "[data-testid='total-staked-tooltip']";
|
||||
const unnormalisedVotingPowerToolTip =
|
||||
"[data-testid='unnormalised-voting-power-tooltip']";
|
||||
const normalisedVotingPowerToolTip =
|
||||
"[data-testid='normalised-voting-power-tooltip']";
|
||||
const performancePenaltyToolTip = "[data-testid='performance-penalty-tooltip']";
|
||||
const overstakedPenaltyToolTip = "[data-testid='overstaked-penalty-tooltip']";
|
||||
const totalPenaltyToolTip = "[data-testid='total-penalty-tooltip']";
|
||||
const epochCountDown = '[data-testid="epoch-countdown"]';
|
||||
const stakeNumberRegex = /^\d*\.?\d*$/;
|
||||
|
||||
@@ -56,37 +66,70 @@ context('Staking Page - verify elements on page', function () {
|
||||
});
|
||||
|
||||
it('Should be able to see validator stake', function () {
|
||||
cy.get('[col-id="stake"] > div > span')
|
||||
cy.get('[col-id="stake"] > div > span > span')
|
||||
.should('have.length.at.least', 1)
|
||||
.each(($stake) => {
|
||||
cy.wrap($stake).should('not.be.empty');
|
||||
});
|
||||
});
|
||||
|
||||
it('Should be able to see validator stake tooltip', function () {
|
||||
cy.get('[col-id="stake"] > div > span > span').first().realHover();
|
||||
|
||||
cy.get(stakedByOperatorToolTip)
|
||||
.invoke('text')
|
||||
.should('contain', 'Staked by operator: 0.00');
|
||||
cy.get(stakedByDelegatesToolTip)
|
||||
.invoke('text')
|
||||
.should('contain', 'Staked by delegates: 0.00');
|
||||
cy.get(totalStakedToolTip)
|
||||
.invoke('text')
|
||||
.should('contain', 'Total stake: 0.00');
|
||||
});
|
||||
|
||||
it('Should be able to see validator normalised voting power', function () {
|
||||
cy.get('[col-id="normalisedVotingPower"] > div > span')
|
||||
cy.get('[col-id="normalisedVotingPower"] > div > span > span')
|
||||
.should('have.length.at.least', 1)
|
||||
.each(($vPower) => {
|
||||
cy.wrap($vPower).should('not.be.empty');
|
||||
});
|
||||
});
|
||||
|
||||
it('Should be able to see validator normalised voting power', function () {
|
||||
cy.get('[col-id="normalisedVotingPower"] > div > span')
|
||||
.should('have.length.at.least', 1)
|
||||
.each(($vPower) => {
|
||||
cy.wrap($vPower).should('not.be.empty');
|
||||
});
|
||||
it('Should be able to see validator voting power tooltip', function () {
|
||||
cy.get('[col-id="normalisedVotingPower"] > div > span > span')
|
||||
.first()
|
||||
.realHover();
|
||||
|
||||
cy.get(unnormalisedVotingPowerToolTip)
|
||||
.invoke('text')
|
||||
.should('contain', 'Unnormalised voting power: 0.00%');
|
||||
cy.get(normalisedVotingPowerToolTip)
|
||||
.invoke('text')
|
||||
.should('contain', 'Normalised voting power: 0.10%');
|
||||
});
|
||||
|
||||
it('Should be able to see validator total penalties', function () {
|
||||
cy.get('[col-id="totalPenalties"] > div > span')
|
||||
cy.get('[col-id="totalPenalties"] > div > span > span')
|
||||
.should('have.length.at.least', 1)
|
||||
.each(($penalties) => {
|
||||
cy.wrap($penalties).should('contain.text', '0%');
|
||||
});
|
||||
});
|
||||
|
||||
it('Should be able to see validator penalties tooltip', function () {
|
||||
cy.get('[col-id="totalPenalties"] > div > span > span').realHover();
|
||||
|
||||
cy.get(performancePenaltyToolTip)
|
||||
.invoke('text')
|
||||
.should('contain', 'Performance penalty: 100.00%');
|
||||
cy.get(overstakedPenaltyToolTip)
|
||||
.invoke('text')
|
||||
.should('contain', 'Overstaked penalty:'); // value not asserted due to #2886
|
||||
cy.get(totalPenaltyToolTip)
|
||||
.invoke('text')
|
||||
.should('contain', 'Total penalties: 0.00%');
|
||||
});
|
||||
|
||||
it('Should be able to see validator pending stake', function () {
|
||||
cy.get('[col-id="pendingStake"] > div > span')
|
||||
.should('have.length.at.least', 1)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import '@vegaprotocol/cypress';
|
||||
import 'cypress-real-events/support';
|
||||
|
||||
import './common.functions.js';
|
||||
import './staking.functions.js';
|
||||
|
||||
@@ -95,8 +95,15 @@ Cypress.Commands.add('faucet_asset', function (assetEthAddress) {
|
||||
});
|
||||
|
||||
Cypress.Commands.add('vega_wallet_teardown', function () {
|
||||
cy.get('[data-testid="associated-amount"]')
|
||||
.should('be.visible')
|
||||
.invoke('text')
|
||||
.as('associatedAmount');
|
||||
cy.get('body').then(($body) => {
|
||||
if ($body.find('[data-testid="eth-wallet-associated-balances"]').length) {
|
||||
if (
|
||||
$body.find('[data-testid="eth-wallet-associated-balances"]').length ||
|
||||
this.associatedAmount != '0.00'
|
||||
) {
|
||||
cy.vega_wallet_teardown_vesting(this.vestingContract);
|
||||
cy.vega_wallet_teardown_staking(this.stakingBridgeContract);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"outDir": "../../dist/out-tsc",
|
||||
"allowJs": true,
|
||||
"types": ["cypress", "node", "@cypress/grep"]
|
||||
"types": ["cypress", "node", "cypress-real-events", "@cypress/grep"]
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.js"]
|
||||
}
|
||||
|
||||
@@ -126,10 +126,10 @@ export const VotingPowerRenderer = ({ data }: VotingPowerRendererProps) => {
|
||||
<Tooltip
|
||||
description={
|
||||
<>
|
||||
<div>
|
||||
<div data-testid="unnormalised-voting-power-tooltip">
|
||||
{t('unnormalisedVotingPower')}: {data.unnormalisedVotingPower}
|
||||
</div>
|
||||
<div>
|
||||
<div data-testid="normalised-voting-power-tooltip">
|
||||
{t('normalisedVotingPower')}: {data.normalisedVotingPower}
|
||||
</div>
|
||||
</>
|
||||
@@ -155,13 +155,13 @@ export const TotalStakeRenderer = ({ data }: TotalStakeRendererProps) => {
|
||||
<Tooltip
|
||||
description={
|
||||
<>
|
||||
<div>
|
||||
<div data-testid="staked-operator-tooltip">
|
||||
{t('stakedByOperator')}: {data.stakedByOperator.toString()}
|
||||
</div>
|
||||
<div>
|
||||
<div data-testid="staked-delegates-tooltip">
|
||||
{t('stakedByDelegates')}: {data.stakedByDelegates.toString()}
|
||||
</div>
|
||||
<div>
|
||||
<div data-testid="total-staked-tooltip">
|
||||
{t('totalStake')}: <span className="font-bold">{data.stake}</span>
|
||||
</div>
|
||||
</>
|
||||
@@ -191,13 +191,13 @@ export const TotalPenaltiesRenderer = ({
|
||||
<Tooltip
|
||||
description={
|
||||
<>
|
||||
<div>
|
||||
<div data-testid="performance-penalty-tooltip">
|
||||
{t('performancePenalty')}: {data.performancePenalty}
|
||||
</div>
|
||||
<div>
|
||||
<div data-testid="overstaked-penalty-tooltip">
|
||||
{t('overstakedPenalty')}: {data.overstakingPenalty}
|
||||
</div>
|
||||
<div>
|
||||
<div data-testid="total-penalty-tooltip">
|
||||
{t('totalPenalties')}:{' '}
|
||||
<span className="font-bold">{data.totalPenalties}</span>
|
||||
</div>
|
||||
|
||||
@@ -32,11 +32,14 @@ const usdcSymbol = 'fUSDC';
|
||||
const toastContent = 'toast-content';
|
||||
const ordersTab = 'Orders';
|
||||
const depositsTab = 'Deposits';
|
||||
const collateralTab = 'Collateral';
|
||||
const toastCloseBtn = 'toast-close';
|
||||
const price = '390';
|
||||
const size = '0.0005';
|
||||
const newPrice = '200';
|
||||
const completeWithdrawalBtn = 'complete-withdrawal';
|
||||
const submitTransferBtn = '[type="submit"]';
|
||||
const transferForm = 'transfer-form';
|
||||
|
||||
// Because the tests are run on a live network to optimize time, the tests are interdependent and must be run in the given order.
|
||||
describe('capsule - without MultiSign', { tags: '@slow' }, () => {
|
||||
@@ -105,12 +108,39 @@ describe('capsule - without MultiSign', { tags: '@slow' }, () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('can key to key transfers', function () {
|
||||
cy.visit('/#/portfolio');
|
||||
cy.get('main[data-testid="/portfolio"]').should('exist');
|
||||
|
||||
cy.getByTestId(collateralTab).click();
|
||||
cy.getByTestId('open-transfer-dialog').click();
|
||||
cy.getByTestId('transfer-form').should('be.visible');
|
||||
cy.getByTestId('transfer-form').find('[name="toAddress"]').select(1);
|
||||
cy.get('select option')
|
||||
.contains('BTC')
|
||||
.invoke('index')
|
||||
.then((index) => {
|
||||
cy.get(assetSelectField).select(index, { force: true });
|
||||
});
|
||||
cy.getByTestId(transferForm)
|
||||
.find(amountField)
|
||||
.focus()
|
||||
.type('1', { delay: 100 });
|
||||
cy.getByTestId(transferForm).find(submitTransferBtn).click();
|
||||
cy.getByTestId(toastContent).should(
|
||||
'contain.text',
|
||||
'Transfer completeYour transaction has been confirmed TransferTo 7f9cf0…c255351.00 tBTC'
|
||||
);
|
||||
cy.getByTestId(toastCloseBtn).click();
|
||||
});
|
||||
|
||||
it('can not withdrawal because of no MultiSign', function () {
|
||||
// 1002-WITH-022
|
||||
// 1002-WITH-023
|
||||
|
||||
cy.getByTestId('Withdrawals').click();
|
||||
cy.getByTestId('withdraw-dialog-button').click();
|
||||
connectEthereumWallet('Unknown');
|
||||
cy.get(assetSelectField, txTimeout).select(btcName, { force: true });
|
||||
cy.get(amountField).clear().type('1');
|
||||
cy.getByTestId('submit-withdrawal').click();
|
||||
@@ -118,7 +148,7 @@ describe('capsule - without MultiSign', { tags: '@slow' }, () => {
|
||||
'contain.text',
|
||||
'Funds unlocked'
|
||||
);
|
||||
|
||||
cy.getByTestId(toastCloseBtn).click();
|
||||
cy.getByTestId('tab-withdrawals').within(() => {
|
||||
cy.get('.ag-center-cols-container')
|
||||
.children()
|
||||
@@ -135,6 +165,7 @@ describe('capsule - without MultiSign', { tags: '@slow' }, () => {
|
||||
'contain.text',
|
||||
'Error occurredprocessing response error'
|
||||
);
|
||||
cy.getByTestId(toastCloseBtn).click({ multiple: true });
|
||||
cy.getByTestId(completeWithdrawalBtn).should(
|
||||
'contain.text',
|
||||
'Complete withdrawal'
|
||||
@@ -227,8 +258,8 @@ describe('capsule', { tags: '@slow' }, () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('can edit order', function () {
|
||||
// comment because of bug #2695
|
||||
it.skip('can edit order', function () {
|
||||
cy.getByTestId(ordersTab).click();
|
||||
cy.getByTestId('edit').first().should('be.visible').click();
|
||||
cy.getByTestId('dialog-title').should('contain.text', 'Edit order');
|
||||
@@ -253,8 +284,8 @@ describe('capsule', { tags: '@slow' }, () => {
|
||||
checkIfDataAndTimeOfCreationAndUpdateIsEqual(orderUpdatedAt);
|
||||
});
|
||||
});
|
||||
|
||||
it('can cancel order', function () {
|
||||
// comment because of bug #2695
|
||||
it.skip('can cancel order', function () {
|
||||
cy.getByTestId(ordersTab).click();
|
||||
cy.getByTestId('cancel').first().click();
|
||||
cy.getByTestId(toastContent).should(
|
||||
@@ -301,7 +332,6 @@ describe('capsule', { tags: '@slow' }, () => {
|
||||
'contain.text',
|
||||
'Funds unlocked'
|
||||
);
|
||||
|
||||
cy.getByTestId('tab-withdrawals').within(() => {
|
||||
cy.get('.ag-center-cols-container')
|
||||
.children()
|
||||
@@ -318,8 +348,19 @@ describe('capsule', { tags: '@slow' }, () => {
|
||||
'contain.text',
|
||||
'Transaction confirmed'
|
||||
);
|
||||
cy.getByTestId(toastCloseBtn).click({ multiple: true });
|
||||
|
||||
cy.getByTestId(completeWithdrawalBtn).eq(0, txTimeout).should('not.exist');
|
||||
cy.wrap(null).then(() => {
|
||||
try {
|
||||
cy.getByTestId(completeWithdrawalBtn)
|
||||
.eq(0, txTimeout)
|
||||
.should('not.exist');
|
||||
} catch (error) {
|
||||
console.log(
|
||||
'Assertion failed, but we are continuing because this is our wait to complete transaction'
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
cy.get('[col-id="txHash"]', txTimeout)
|
||||
.should('have.length.above', 1)
|
||||
|
||||
@@ -59,11 +59,9 @@ describe('home', { tags: '@regression' }, () => {
|
||||
describe('default market found', () => {
|
||||
it('redirects to a default market with the landing dialog open', () => {
|
||||
cy.visit('/');
|
||||
cy.wait('@Market');
|
||||
cy.wait('@Markets');
|
||||
|
||||
cy.get('main', { timeout: 20000 }).then((el) => {
|
||||
expect(el.attr('data-testid')?.startsWith('/market')).to.equal(true);
|
||||
}); // Wait for page to be rendered to before checking url
|
||||
cy.get('main[data-testid^="/markets/"]');
|
||||
|
||||
// Overlay should be shown
|
||||
cy.getByTestId(selectMarketOverlay).should('exist');
|
||||
@@ -101,7 +99,7 @@ describe('home', { tags: '@regression' }, () => {
|
||||
// the choose market overlay is no longer showing
|
||||
cy.contains('Select a market to get started').should('not.exist');
|
||||
cy.contains('Loading...').should('not.exist');
|
||||
cy.url().should('eq', Cypress.config().baseUrl + '/#/markets/market-0');
|
||||
cy.url().should('eq', Cypress.config().baseUrl + '/#/markets/market-1');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -125,7 +123,7 @@ describe('home', { tags: '@regression' }, () => {
|
||||
aliasGQLQuery(req, 'MarketsData', data);
|
||||
});
|
||||
cy.visit('/');
|
||||
cy.wait('@Market');
|
||||
cy.wait('@Markets');
|
||||
cy.getByTestId(selectMarketOverlay)
|
||||
.get('table')
|
||||
.invoke('outerWidth')
|
||||
@@ -233,7 +231,7 @@ describe('home', { tags: '@regression' }, () => {
|
||||
cy.window().then((window) => {
|
||||
window.localStorage.setItem('marketId', 'market-1');
|
||||
cy.visit('/');
|
||||
cy.wait('@Market');
|
||||
cy.wait('@Markets');
|
||||
cy.location('hash').should('equal', '#/markets/market-1');
|
||||
cy.getByTestId('dialog-content').should('not.exist');
|
||||
});
|
||||
@@ -246,7 +244,7 @@ describe('home', { tags: '@regression' }, () => {
|
||||
aliasGQLQuery(req, 'Market', null);
|
||||
});
|
||||
cy.visit('/');
|
||||
cy.wait('@Market');
|
||||
cy.wait('@Markets');
|
||||
cy.location('hash').should('equal', '#/markets/market-not-existing');
|
||||
cy.getByTestId('dialog-content').should('not.exist');
|
||||
});
|
||||
|
||||
@@ -11,7 +11,7 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Market');
|
||||
cy.wait('@Markets');
|
||||
cy.getByTestId(marketInfoBtn).click();
|
||||
cy.wait('@MarketInfo');
|
||||
});
|
||||
|
||||
@@ -237,7 +237,6 @@ describe('market states not accepting orders', { tags: '@smoke' }, function () {
|
||||
cy.mockSubscription();
|
||||
cy.setVegaWallet();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Market');
|
||||
});
|
||||
it('must display that market is not accepting orders', function () {
|
||||
cy.getByTestId('place-order').click();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { aliasGQLQuery } from '@vegaprotocol/cypress';
|
||||
import { marketQuery } from '@vegaprotocol/mock';
|
||||
import { marketsQuery } from '@vegaprotocol/mock';
|
||||
import { getDateTimeFormat } from '@vegaprotocol/react-helpers';
|
||||
|
||||
describe('markets table', { tags: '@smoke' }, () => {
|
||||
@@ -13,7 +13,6 @@ describe('markets table', { tags: '@smoke' }, () => {
|
||||
);
|
||||
cy.mockSubscription();
|
||||
cy.visit('/');
|
||||
cy.wait('@Market');
|
||||
cy.wait('@Markets');
|
||||
cy.wait('@MarketsData');
|
||||
cy.wait('@MarketsCandles');
|
||||
@@ -123,17 +122,24 @@ describe('markets table', { tags: '@smoke' }, () => {
|
||||
);
|
||||
cy.mockGQL((req) => {
|
||||
const override = {
|
||||
market: {
|
||||
tradableInstrument: {
|
||||
instrument: {
|
||||
name: `opening auction MARKET`,
|
||||
marketsConnection: {
|
||||
edges: [
|
||||
{
|
||||
node: {
|
||||
tradableInstrument: {
|
||||
instrument: {
|
||||
name: `opening auction MARKET`,
|
||||
},
|
||||
},
|
||||
state: Schema.MarketState.STATE_ACTIVE,
|
||||
tradingMode:
|
||||
Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION,
|
||||
},
|
||||
},
|
||||
},
|
||||
state: Schema.MarketState.STATE_ACTIVE,
|
||||
tradingMode: Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION,
|
||||
],
|
||||
},
|
||||
};
|
||||
const market = marketQuery(override);
|
||||
const market = marketsQuery(override);
|
||||
aliasGQLQuery(req, 'Market', market);
|
||||
aliasGQLQuery(req, 'ProposalOfMarket', {
|
||||
proposal: { terms: { enactmentDatetime: '2023-01-31 12:00:01' } },
|
||||
|
||||
@@ -4,14 +4,15 @@ before(() => {
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.visit('/');
|
||||
cy.wait('@Market');
|
||||
cy.wait('@Markets');
|
||||
cy.wait('@MarketsData');
|
||||
cy.getByTestId('dialog-close').click();
|
||||
});
|
||||
|
||||
describe('Desktop view', { tags: '@smoke' }, () => {
|
||||
describe('Navbar', () => {
|
||||
const links = ['Markets', 'Trading', 'Portfolio'];
|
||||
const hashes = ['#/markets/all', '#/markets/market-0', '#/portfolio'];
|
||||
const hashes = ['#/markets/all', '#/markets/market-1', '#/portfolio'];
|
||||
|
||||
links.forEach((link, index) => {
|
||||
it(`${link} should be correctly rendered`, () => {
|
||||
@@ -67,7 +68,7 @@ describe('Mobile view', { tags: '@smoke' }, () => {
|
||||
cy.getByTestId('button-menu-drawer').click();
|
||||
cy.getByTestId('menu-drawer').within((el) => {
|
||||
cy.wrap(el).getByTestId('Trading').click();
|
||||
cy.location('hash').should('equal', '#/markets/market-0');
|
||||
cy.location('hash').should('equal', '#/markets/market-1');
|
||||
});
|
||||
});
|
||||
it('Portfolio should be correctly rendered', () => {
|
||||
|
||||
@@ -35,7 +35,7 @@ describe('time in force default values', () => {
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Market');
|
||||
cy.wait('@Markets');
|
||||
});
|
||||
|
||||
it('must have market order set up to IOC by default', function () {
|
||||
@@ -64,7 +64,7 @@ describe('must submit order', { tags: '@smoke' }, () => {
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Market');
|
||||
cy.wait('@Markets');
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -162,7 +162,7 @@ describe(
|
||||
);
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Market');
|
||||
cy.wait('@Markets');
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -231,7 +231,7 @@ describe(
|
||||
);
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Market');
|
||||
cy.wait('@Markets');
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -300,7 +300,7 @@ describe(
|
||||
);
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Market');
|
||||
cy.wait('@Markets');
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -360,7 +360,7 @@ describe('deal ticket validation', { tags: '@smoke' }, () => {
|
||||
beforeEach(() => {
|
||||
cy.mockTradingPage();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Market');
|
||||
cy.wait('@Markets');
|
||||
});
|
||||
|
||||
it('must not place an order if wallet is not connected', () => {
|
||||
@@ -405,7 +405,7 @@ describe('deal ticket size validation', { tags: '@smoke' }, function () {
|
||||
cy.setVegaWallet();
|
||||
cy.mockTradingPage();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Market');
|
||||
cy.wait('@Markets');
|
||||
});
|
||||
|
||||
it('must warn if order size input has too many digits after the decimal place', function () {
|
||||
@@ -440,7 +440,7 @@ describe('limit order validations', { tags: '@smoke' }, () => {
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Market');
|
||||
cy.wait('@Markets');
|
||||
cy.getByTestId(toggleLimit).click();
|
||||
});
|
||||
|
||||
@@ -452,7 +452,7 @@ describe('limit order validations', { tags: '@smoke' }, () => {
|
||||
//7002-SORD-018
|
||||
cy.getByTestId(orderPriceField)
|
||||
.siblings('label')
|
||||
.should('have.text', 'Price (BTC)');
|
||||
.should('have.text', 'Price (DAI)');
|
||||
});
|
||||
|
||||
it('must see warning when placing an order with expiry date in past', () => {
|
||||
@@ -532,7 +532,7 @@ describe('market order validations', { tags: '@smoke' }, () => {
|
||||
cy.setVegaWallet();
|
||||
cy.mockTradingPage();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Market');
|
||||
cy.wait('@Markets');
|
||||
cy.getByTestId(toggleMarket).click();
|
||||
});
|
||||
|
||||
@@ -586,7 +586,7 @@ describe('suspended market validation', { tags: '@regression' }, () => {
|
||||
);
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Market');
|
||||
cy.wait('@Markets');
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -648,7 +648,7 @@ describe('account validation', { tags: '@regression' }, () => {
|
||||
market: null,
|
||||
asset: {
|
||||
__typename: 'Asset',
|
||||
id: '5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c',
|
||||
id: 'asset-0',
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -660,7 +660,7 @@ describe('account validation', { tags: '@regression' }, () => {
|
||||
});
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Market');
|
||||
cy.wait('@Markets');
|
||||
});
|
||||
|
||||
it('should show an error if your balance is zero', () => {
|
||||
@@ -670,7 +670,7 @@ describe('account validation', { tags: '@regression' }, () => {
|
||||
//7002-SORD-003
|
||||
cy.getByTestId('dealticket-error-message-zero-balance').should(
|
||||
'have.text',
|
||||
'Insufficient balance. Deposit ' + 'tBTC'
|
||||
'Insufficient balance. Deposit ' + 'tDAI'
|
||||
);
|
||||
cy.getByTestId('deal-ticket-deposit-dialog-button').should('exist');
|
||||
});
|
||||
@@ -696,7 +696,7 @@ describe('account validation', { tags: '@regression' }, () => {
|
||||
});
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Market');
|
||||
cy.wait('@Markets');
|
||||
});
|
||||
|
||||
it('should display info and button for deposit', () => {
|
||||
@@ -708,7 +708,7 @@ describe('account validation', { tags: '@regression' }, () => {
|
||||
);
|
||||
cy.getByTestId('dealticket-warning-margin').should(
|
||||
'contain.text',
|
||||
'9,999.99 tBTC currently required, 1,000.00 tBTC available'
|
||||
'9,999.99 tDAI currently required, 1,000.00 tDAI available'
|
||||
);
|
||||
cy.getByTestId('deal-ticket-deposit-dialog-button').click();
|
||||
cy.getByTestId('dialog-content')
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import { aliasGQLQuery } from '@vegaprotocol/cypress';
|
||||
import { marketsDataQuery } from '@vegaprotocol/mock';
|
||||
|
||||
beforeEach(() => {
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
@@ -17,6 +20,47 @@ describe('positions', { tags: '@smoke' }, () => {
|
||||
validatePositionsDisplayed();
|
||||
});
|
||||
|
||||
it('renders position among some graphql errors', () => {
|
||||
const errors = [
|
||||
{
|
||||
message: 'no market data for market: market-2',
|
||||
path: ['market', 'data'],
|
||||
extensions: {
|
||||
code: 13,
|
||||
type: 'Internal',
|
||||
},
|
||||
},
|
||||
];
|
||||
const marketData = marketsDataQuery();
|
||||
const edges = marketData.marketsConnection?.edges.map((market) => {
|
||||
const replace =
|
||||
market.node.data?.market.id === 'market-2' ? null : market.node.data;
|
||||
return { ...market, node: { ...market.node, data: replace } };
|
||||
});
|
||||
const overrides = {
|
||||
...marketData,
|
||||
marketsConnection: { ...marketData.marketsConnection, edges },
|
||||
};
|
||||
cy.mockGQL((req) => {
|
||||
aliasGQLQuery(req, 'MarketsData', overrides, errors);
|
||||
});
|
||||
cy.visit('/#/markets/market-0');
|
||||
const emptyCells = [
|
||||
'notional',
|
||||
'markPrice',
|
||||
'liquidationPrice',
|
||||
'currentLeverage',
|
||||
'averageEntryPrice',
|
||||
];
|
||||
cy.getByTestId('tab-positions').within(() => {
|
||||
cy.get('[row-id="market-2"]').within(() => {
|
||||
emptyCells.forEach((cell) => {
|
||||
cy.get(`[col-id="${cell}"]`).should('contain.text', '-');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function validatePositionsDisplayed() {
|
||||
cy.getByTestId('tab-positions').should('be.visible');
|
||||
cy.getByTestId('tab-positions').within(() => {
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
import { selectAsset } from '../support/helpers';
|
||||
|
||||
const formFieldError = 'input-error-text';
|
||||
const toAddressField = '[name="toAddress"]';
|
||||
const amountField = 'input[name="amount"]';
|
||||
const submitTransferBtn = '[type="submit"]';
|
||||
const transferForm = 'transfer-form';
|
||||
const errorText = 'input-error-text';
|
||||
const openTransferDialog = 'open-transfer-dialog';
|
||||
const closeDialog = 'dialog-close';
|
||||
const dialogTransferText = 'dialog-transfer-text';
|
||||
|
||||
const ASSET_SEPOLIA_TBTC = 2;
|
||||
const ASSET_EURO = 1;
|
||||
|
||||
const toastContent = 'toast-content';
|
||||
const collateralTab = 'Collateral';
|
||||
const toastCloseBtn = 'toast-close';
|
||||
|
||||
describe(
|
||||
'transfer form validation and transfer from options',
|
||||
{ tags: '@smoke' },
|
||||
() => {
|
||||
before(() => {
|
||||
cy.mockWeb3Provider();
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.setVegaWallet();
|
||||
|
||||
cy.visit('/#/portfolio');
|
||||
cy.getByTestId(collateralTab).click();
|
||||
cy.getByTestId(openTransferDialog).click();
|
||||
|
||||
cy.wait('@Accounts');
|
||||
cy.wait('@Assets');
|
||||
});
|
||||
|
||||
it('empty fields', () => {
|
||||
cy.getByTestId(transferForm).find(submitTransferBtn).click();
|
||||
|
||||
cy.getByTestId(formFieldError).should('contain.text', 'Required');
|
||||
// only 2 despite 3 fields because the ethereum address will be auto populated
|
||||
cy.getByTestId(formFieldError).should('have.length', 3);
|
||||
});
|
||||
it('min amount', () => {
|
||||
// 1002-WITH-010
|
||||
selectAsset(ASSET_SEPOLIA_TBTC);
|
||||
cy.get(amountField).clear().type('0');
|
||||
cy.getByTestId(transferForm).find(submitTransferBtn).click();
|
||||
cy.getByTestId(errorText).should(
|
||||
'contain.text',
|
||||
'Value is below minimum'
|
||||
);
|
||||
});
|
||||
it('max amount', () => {
|
||||
selectAsset(ASSET_EURO); // Will be above maximum because the vega wallet doesn't have any collateral
|
||||
cy.get(amountField).clear().type('1001', { delay: 100 });
|
||||
cy.getByTestId(transferForm).find(submitTransferBtn).click();
|
||||
cy.getByTestId(errorText).should(
|
||||
'contain.text',
|
||||
'You cannot transfer more than your available collateral'
|
||||
);
|
||||
});
|
||||
|
||||
it('can start transfer from vega wallet', () => {
|
||||
cy.getByTestId(closeDialog).click();
|
||||
cy.getByTestId('manage-vega-wallet').click();
|
||||
cy.getByTestId('wallet-transfer').should('have.text', 'Transfer').click();
|
||||
cy.getByTestId(dialogTransferText).should(
|
||||
'contain.text',
|
||||
'Transfer funds to another Vega key from 02ecea…342f65 If you are at all unsure, stop and seek advice.'
|
||||
);
|
||||
});
|
||||
|
||||
it('can start transfer from trading collateral table', () => {
|
||||
cy.getByTestId(closeDialog).click();
|
||||
cy.getByTestId('Trading').first().click();
|
||||
cy.getByTestId(collateralTab).click();
|
||||
cy.getByTestId(openTransferDialog).click();
|
||||
cy.getByTestId(dialogTransferText).should(
|
||||
'contain.text',
|
||||
'Transfer funds to another Vega key from 02ecea…342f65 If you are at all unsure, stop and seek advice.'
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
describe('withdraw actions', { tags: '@regression' }, () => {
|
||||
beforeEach(() => {
|
||||
cy.mockWeb3Provider();
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.setVegaWallet();
|
||||
|
||||
cy.visit('/#/portfolio');
|
||||
cy.getByTestId(collateralTab).click();
|
||||
cy.getByTestId(openTransferDialog).click();
|
||||
|
||||
cy.wait('@Accounts');
|
||||
cy.wait('@Assets');
|
||||
cy.mockVegaWalletTransaction();
|
||||
});
|
||||
|
||||
it('key to key transfers by select key', function () {
|
||||
cy.getByTestId(transferForm).should('be.visible');
|
||||
cy.getByTestId(transferForm).find(toAddressField).select(1);
|
||||
selectAsset(ASSET_SEPOLIA_TBTC);
|
||||
cy.getByTestId(transferForm).find(amountField).type('1', { delay: 100 });
|
||||
cy.getByTestId(transferForm).find(submitTransferBtn).click();
|
||||
cy.getByTestId(toastContent).should(
|
||||
'contain.text',
|
||||
'Awaiting confirmation'
|
||||
);
|
||||
cy.getByTestId(toastCloseBtn).click();
|
||||
});
|
||||
|
||||
it('key to key transfers by enter manual key', function () {
|
||||
cy.getByTestId(transferForm).should('be.visible');
|
||||
cy.contains('Enter manually').click();
|
||||
cy.getByTestId(transferForm)
|
||||
.find(toAddressField)
|
||||
.type('7f9cf07d3a9905b1a61a1069f7a758855da428bc0f4a97de87f48644bfc25535');
|
||||
selectAsset(ASSET_SEPOLIA_TBTC);
|
||||
cy.getByTestId(transferForm).find(amountField).type('1', { delay: 100 });
|
||||
cy.getByTestId(transferForm).find(submitTransferBtn).click();
|
||||
cy.getByTestId(toastContent).should(
|
||||
'contain.text',
|
||||
'Awaiting confirmation'
|
||||
);
|
||||
cy.getByTestId(toastCloseBtn).click();
|
||||
});
|
||||
});
|
||||
@@ -15,7 +15,6 @@ import {
|
||||
marketDataQuery,
|
||||
marketDepthQuery,
|
||||
marketInfoQuery,
|
||||
marketQuery,
|
||||
marketsCandlesQuery,
|
||||
marketsDataQuery,
|
||||
marketsQuery,
|
||||
@@ -28,7 +27,7 @@ import {
|
||||
withdrawalsQuery,
|
||||
} from '@vegaprotocol/mock';
|
||||
import type { PartialDeep } from 'type-fest';
|
||||
import type { MarketDataQuery, MarketQuery } from '@vegaprotocol/market-list';
|
||||
import type { MarketDataQuery, MarketsQuery } from '@vegaprotocol/market-list';
|
||||
import type { MarketInfoQuery } from '@vegaprotocol/market-info';
|
||||
|
||||
type MarketPageMockData = {
|
||||
@@ -55,17 +54,18 @@ const marketDataOverride = (
|
||||
},
|
||||
});
|
||||
|
||||
const marketQueryOverride = (
|
||||
const marketsDataOverride = (
|
||||
data: MarketPageMockData
|
||||
): PartialDeep<MarketQuery> => ({
|
||||
market: {
|
||||
tradableInstrument: {
|
||||
instrument: {
|
||||
name: `${data.state?.toUpperCase()} MARKET`,
|
||||
): PartialDeep<MarketsQuery> => ({
|
||||
marketsConnection: {
|
||||
edges: [
|
||||
{
|
||||
node: {
|
||||
tradingMode: data.tradingMode,
|
||||
state: data.state,
|
||||
},
|
||||
},
|
||||
},
|
||||
state: data.state,
|
||||
tradingMode: data.tradingMode,
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
@@ -91,10 +91,9 @@ const mockTradingPage = (
|
||||
aliasGQLQuery(req, 'Statistics', statisticsQuery());
|
||||
aliasGQLQuery(
|
||||
req,
|
||||
'Market',
|
||||
marketQuery(marketQueryOverride({ state, tradingMode, trigger }))
|
||||
'Markets',
|
||||
marketsQuery(marketsDataOverride({ state, tradingMode, trigger }))
|
||||
);
|
||||
aliasGQLQuery(req, 'Markets', marketsQuery());
|
||||
aliasGQLQuery(
|
||||
req,
|
||||
'MarketData',
|
||||
|
||||
@@ -59,7 +59,7 @@ export const LiquidityContainer = ({
|
||||
marketId: string | undefined;
|
||||
}) => {
|
||||
const gridRef = useRef<AgGridReact | null>(null);
|
||||
const market = useMarket(marketId);
|
||||
const { data: market } = useMarket(marketId);
|
||||
const dataRef = useRef<LiquidityProvisionData[] | null>(null);
|
||||
|
||||
// To be removed when liquidityProvision subscriptions are working
|
||||
@@ -129,8 +129,8 @@ export const LiquidityViewContainer = ({
|
||||
}) => {
|
||||
const { pubKey } = useVegaWallet();
|
||||
const gridRef = useRef<AgGridReact | null>(null);
|
||||
const market = useMarket(marketId);
|
||||
const marketData = useStaticMarketData(marketId);
|
||||
const { data: market } = useMarket(marketId);
|
||||
const { data: marketData } = useStaticMarketData(marketId);
|
||||
|
||||
const dataRef = useRef<LiquidityProvisionData[] | null>(null);
|
||||
|
||||
|
||||
@@ -9,9 +9,7 @@ import {
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import { AsyncRenderer, ExternalLink, Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import type {
|
||||
SingleMarketFieldsFragment,
|
||||
MarketData,
|
||||
Candle,
|
||||
MarketDataUpdateFieldsFragment,
|
||||
} from '@vegaprotocol/market-list';
|
||||
|
||||
@@ -27,11 +25,6 @@ const calculatePrice = (markPrice?: string, decimalPlaces?: number) => {
|
||||
: '-';
|
||||
};
|
||||
|
||||
export interface SingleMarketData extends SingleMarketFieldsFragment {
|
||||
candles: Candle[];
|
||||
data: MarketData;
|
||||
}
|
||||
|
||||
const TitleUpdater = ({
|
||||
marketId,
|
||||
marketName,
|
||||
@@ -89,12 +82,9 @@ export const MarketPage = () => {
|
||||
[marketId, navigate]
|
||||
);
|
||||
|
||||
const { data, error, loading } = useDataProvider<
|
||||
SingleMarketFieldsFragment,
|
||||
never
|
||||
>({
|
||||
const { data, error, loading } = useDataProvider({
|
||||
dataProvider: marketProvider,
|
||||
variables: useMemo(() => ({ marketId: marketId || '' }), [marketId]),
|
||||
variables: { marketId: marketId || '' },
|
||||
skip: !marketId,
|
||||
});
|
||||
|
||||
@@ -115,7 +105,7 @@ export const MarketPage = () => {
|
||||
<Splash>
|
||||
<span className="flex flex-col items-center gap-2">
|
||||
<p className="text-sm justify-center">
|
||||
{t('This market URL is not available anymore.')}
|
||||
{t('This market URL is not available any more.')}
|
||||
</p>
|
||||
<p className="text-sm justify-center">
|
||||
{t(`Please choose another market from the`)}{' '}
|
||||
@@ -129,7 +119,7 @@ export const MarketPage = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<AsyncRenderer<SingleMarketFieldsFragment>
|
||||
<AsyncRenderer
|
||||
loading={loading}
|
||||
error={error}
|
||||
data={data || undefined}
|
||||
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import { AccountsContainer } from '../../components/accounts-container';
|
||||
import type { SingleMarketFieldsFragment } from '@vegaprotocol/market-list';
|
||||
import type { Market } from '@vegaprotocol/market-list';
|
||||
import { VegaWalletContainer } from '../../components/vega-wallet-container';
|
||||
import { TradeMarketHeader } from './trade-market-header';
|
||||
import { NO_MARKET } from './constants';
|
||||
@@ -63,7 +63,7 @@ const TradingViews = {
|
||||
type TradingView = keyof typeof TradingViews;
|
||||
|
||||
interface TradeGridProps {
|
||||
market: SingleMarketFieldsFragment | null;
|
||||
market: Market | null;
|
||||
onSelect: (marketId: string) => void;
|
||||
}
|
||||
|
||||
@@ -207,7 +207,7 @@ const TradeGridChild = ({ children }: TradeGridChildProps) => {
|
||||
};
|
||||
|
||||
interface TradePanelsProps {
|
||||
market: SingleMarketFieldsFragment | null;
|
||||
market: Market | null;
|
||||
onSelect: (marketId: string) => void;
|
||||
onMarketClick?: (marketId: string) => void;
|
||||
}
|
||||
|
||||
@@ -2,12 +2,12 @@ import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
||||
import { useEnvironment } from '@vegaprotocol/environment';
|
||||
import { ButtonLink, Link } from '@vegaprotocol/ui-toolkit';
|
||||
import { MarketProposalNotification } from '@vegaprotocol/governance';
|
||||
import type { Market } from '@vegaprotocol/market-list';
|
||||
import {
|
||||
getExpiryDate,
|
||||
getMarketExpiryDate,
|
||||
t,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import type { SingleMarketFieldsFragment } from '@vegaprotocol/market-list';
|
||||
import {
|
||||
ColumnKind,
|
||||
SelectMarketPopover,
|
||||
@@ -24,7 +24,7 @@ import { MarketLiquiditySupplied } from '../../components/liquidity-supplied';
|
||||
import { MarketState as State } from '@vegaprotocol/types';
|
||||
|
||||
interface TradeMarketHeaderProps {
|
||||
market: SingleMarketFieldsFragment | null;
|
||||
market: Market | null;
|
||||
onSelect: (marketId: string) => void;
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ export const TradeMarketHeader = ({
|
||||
};
|
||||
|
||||
type ExpiryLabelProps = {
|
||||
market: SingleMarketFieldsFragment | null;
|
||||
market: Market | null;
|
||||
};
|
||||
|
||||
const ExpiryLabel = ({ market }: ExpiryLabelProps) => {
|
||||
@@ -140,7 +140,7 @@ const ExpiryLabel = ({ market }: ExpiryLabelProps) => {
|
||||
};
|
||||
|
||||
type ExpiryTooltipContentProps = {
|
||||
market: SingleMarketFieldsFragment;
|
||||
market: Market;
|
||||
explorerUrl?: string;
|
||||
};
|
||||
|
||||
|
||||
@@ -43,7 +43,11 @@ export const AccountsContainer = () => {
|
||||
</div>
|
||||
{!isReadOnly && (
|
||||
<div className="flex gap-2 justify-end p-2 px-[11px]">
|
||||
<Button size="sm" onClick={() => openTransferDialog()}>
|
||||
<Button
|
||||
size="sm"
|
||||
data-testid="open-transfer-dialog"
|
||||
onClick={() => openTransferDialog()}
|
||||
>
|
||||
{t('Transfer')}
|
||||
</Button>
|
||||
<Button size="sm" onClick={() => openDepositDialog()}>
|
||||
|
||||
@@ -10,7 +10,6 @@ import {
|
||||
import type {
|
||||
MarketData,
|
||||
MarketDataUpdateFieldsFragment,
|
||||
SingleMarketFieldsFragment,
|
||||
} from '@vegaprotocol/market-list';
|
||||
import { marketDataProvider, marketProvider } from '@vegaprotocol/market-list';
|
||||
import { HeaderStat } from '../header';
|
||||
@@ -44,12 +43,12 @@ export const MarketLiquiditySupplied = ({
|
||||
|
||||
const variables = useMemo(
|
||||
() => ({
|
||||
marketId: marketId,
|
||||
marketId: marketId || '',
|
||||
}),
|
||||
[marketId]
|
||||
);
|
||||
|
||||
const { data } = useDataProvider<SingleMarketFieldsFragment, never>({
|
||||
const { data } = useDataProvider({
|
||||
dataProvider: marketProvider,
|
||||
variables,
|
||||
skip: !marketId,
|
||||
|
||||
@@ -2,7 +2,7 @@ import throttle from 'lodash/throttle';
|
||||
import type {
|
||||
MarketData,
|
||||
MarketDataUpdateFieldsFragment,
|
||||
SingleMarketFieldsFragment,
|
||||
Market,
|
||||
} from '@vegaprotocol/market-list';
|
||||
import { marketDataProvider } from '@vegaprotocol/market-list';
|
||||
import { t, useDataProvider } from '@vegaprotocol/react-helpers';
|
||||
@@ -11,11 +11,7 @@ import { HeaderStat } from '../header';
|
||||
import { useCallback, useMemo, useRef, useState } from 'react';
|
||||
import * as constants from '../constants';
|
||||
|
||||
export const MarketState = ({
|
||||
market,
|
||||
}: {
|
||||
market: SingleMarketFieldsFragment | null;
|
||||
}) => {
|
||||
export const MarketState = ({ market }: { market: Market | null }) => {
|
||||
const [marketState, setMarketState] = useState<Schema.MarketState | null>(
|
||||
null
|
||||
);
|
||||
|
||||
@@ -1,37 +1,24 @@
|
||||
import type { RefObject } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import { t, useDataProvider } from '@vegaprotocol/react-helpers';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import { TradingModeTooltip } from '@vegaprotocol/deal-ticket';
|
||||
import { useInView } from 'react-intersection-observer';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { HeaderStat } from '../header';
|
||||
import { Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||
import { marketDataProvider } from '@vegaprotocol/market-list';
|
||||
|
||||
// This will cause often re-rendering
|
||||
// Here it may not be a problem because the component is not very complex
|
||||
// In general, we should avoid using this marketData hook without any throttling
|
||||
const useMarketData = (marketId?: string, skip?: boolean) => {
|
||||
const variables = useMemo(() => ({ marketId }), [marketId]);
|
||||
const { data } = useDataProvider({
|
||||
dataProvider: marketDataProvider,
|
||||
variables,
|
||||
skip: skip || !marketId,
|
||||
});
|
||||
return data;
|
||||
};
|
||||
import { useStaticMarketData } from '@vegaprotocol/market-list';
|
||||
|
||||
const getTradingModeLabel = (
|
||||
tradingMode?: Schema.MarketTradingMode,
|
||||
marketTradingMode?: Schema.MarketTradingMode,
|
||||
trigger?: Schema.AuctionTrigger
|
||||
) => {
|
||||
return (
|
||||
(tradingMode === Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION &&
|
||||
(marketTradingMode ===
|
||||
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION &&
|
||||
trigger &&
|
||||
trigger !== Schema.AuctionTrigger.AUCTION_TRIGGER_UNSPECIFIED
|
||||
? `${Schema.MarketTradingModeMapping[tradingMode]} - ${Schema.AuctionTriggerMapping[trigger]}`
|
||||
? `${Schema.MarketTradingModeMapping[marketTradingMode]} - ${Schema.AuctionTriggerMapping[trigger]}`
|
||||
: Schema.MarketTradingModeMapping[
|
||||
tradingMode as Schema.MarketTradingMode
|
||||
marketTradingMode as Schema.MarketTradingMode
|
||||
]) || '-'
|
||||
);
|
||||
};
|
||||
@@ -49,8 +36,8 @@ export const HeaderStatMarketTradingMode = ({
|
||||
initialTradingMode,
|
||||
initialTrigger,
|
||||
}: HeaderStatMarketTradingModeProps) => {
|
||||
const data = useMarketData(marketId);
|
||||
const tradingMode = data?.marketTradingMode ?? initialTradingMode;
|
||||
const { data } = useStaticMarketData(marketId);
|
||||
const marketTradingMode = data?.marketTradingMode ?? initialTradingMode;
|
||||
const trigger = data?.trigger ?? initialTrigger;
|
||||
|
||||
return (
|
||||
@@ -61,7 +48,7 @@ export const HeaderStatMarketTradingMode = ({
|
||||
}
|
||||
testId="market-trading-mode"
|
||||
>
|
||||
<div>{getTradingModeLabel(tradingMode, trigger)}</div>
|
||||
<div>{getTradingModeLabel(marketTradingMode, trigger)}</div>
|
||||
</HeaderStat>
|
||||
);
|
||||
};
|
||||
@@ -75,7 +62,7 @@ export const MarketTradingMode = ({
|
||||
inViewRoot?: RefObject<Element>;
|
||||
}) => {
|
||||
const [ref, inView] = useInView({ root: inViewRoot?.current });
|
||||
const data = useMarketData(marketId, !inView);
|
||||
const { data } = useStaticMarketData(marketId, !inView);
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
import type {
|
||||
MarketData,
|
||||
MarketDataUpdateFieldsFragment,
|
||||
SingleMarketFieldsFragment,
|
||||
} from '@vegaprotocol/market-list';
|
||||
import { marketDataProvider, marketProvider } from '@vegaprotocol/market-list';
|
||||
import { HeaderStat } from '../header';
|
||||
@@ -22,7 +21,7 @@ export const MarketVolume = ({ marketId }: { marketId: string }) => {
|
||||
}),
|
||||
[marketId]
|
||||
);
|
||||
const { data } = useDataProvider<SingleMarketFieldsFragment, never>({
|
||||
const { data } = useDataProvider({
|
||||
dataProvider: marketProvider,
|
||||
variables,
|
||||
skip: !marketId,
|
||||
|
||||
@@ -14,10 +14,7 @@ import {
|
||||
import { Link as UILink, Sparkline, Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||
import isNil from 'lodash/isNil';
|
||||
import type { CandleClose } from '@vegaprotocol/types';
|
||||
import type {
|
||||
MarketWithData,
|
||||
MarketWithCandles,
|
||||
} from '@vegaprotocol/market-list';
|
||||
import type { MarketMaybeWithDataAndCandles } from '@vegaprotocol/market-list';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { MarketMarkPrice } from '../market-mark-price';
|
||||
import { Last24hPriceChange } from '../last-24h-price-change';
|
||||
@@ -25,8 +22,6 @@ import { MarketTradingMode } from '../market-trading-mode';
|
||||
import { Last24hVolume } from '../last-24h-volume';
|
||||
import { Links, Routes } from '../../pages/client-router';
|
||||
|
||||
type Market = MarketWithData & MarketWithCandles;
|
||||
|
||||
const ellipsisClasses = 'whitespace-nowrap overflow-hidden text-ellipsis';
|
||||
export const cellClassNames = `py-1 first:text-left text-right ${ellipsisClasses}`;
|
||||
|
||||
@@ -171,7 +166,7 @@ export type OnCellClickHandler = (
|
||||
) => void;
|
||||
|
||||
export const columns = (
|
||||
market: Market,
|
||||
market: MarketMaybeWithDataAndCandles,
|
||||
onSelect: (id: string) => void,
|
||||
onCellClick: OnCellClickHandler,
|
||||
inViewRoot?: RefObject<HTMLElement>
|
||||
@@ -359,7 +354,7 @@ export const columns = (
|
||||
};
|
||||
|
||||
export const columnsPositionMarkets = (
|
||||
market: Market,
|
||||
market: MarketMaybeWithDataAndCandles,
|
||||
onSelect: (id: string) => void,
|
||||
inViewRoot?: RefObject<HTMLElement>,
|
||||
openVolume?: string,
|
||||
|
||||
@@ -4,13 +4,13 @@ import * as Schema from '@vegaprotocol/types';
|
||||
import { SelectAllMarketsTableBody } from './select-market';
|
||||
|
||||
import type {
|
||||
MarketWithCandles,
|
||||
MarketWithData,
|
||||
MarketMaybeWithCandles,
|
||||
MarketMaybeWithData,
|
||||
MarketData,
|
||||
} from '@vegaprotocol/market-list';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
type Market = MarketWithCandles & MarketWithData;
|
||||
type Market = MarketMaybeWithCandles & MarketMaybeWithData;
|
||||
|
||||
type PartialMarket = Partial<
|
||||
Omit<Market, 'data'> & { data: Partial<MarketData> }
|
||||
@@ -34,9 +34,13 @@ const MARKET_A: PartialMarket = {
|
||||
settlementAsset: {
|
||||
__typename: 'Asset',
|
||||
id: 'asset-ABC',
|
||||
name: '',
|
||||
decimals: 2,
|
||||
symbol: 'ABC',
|
||||
},
|
||||
dataSourceSpecForTradingTermination: {
|
||||
id: '',
|
||||
},
|
||||
},
|
||||
metadata: {
|
||||
__typename: 'InstrumentMetadata',
|
||||
@@ -106,9 +110,13 @@ const MARKET_B: PartialMarket = {
|
||||
settlementAsset: {
|
||||
__typename: 'Asset',
|
||||
id: 'asset-XYZ',
|
||||
name: 'asset-XYZ',
|
||||
decimals: 2,
|
||||
symbol: 'XYZ',
|
||||
},
|
||||
dataSourceSpecForTradingTermination: {
|
||||
id: '',
|
||||
},
|
||||
},
|
||||
metadata: {
|
||||
__typename: 'InstrumentMetadata',
|
||||
|
||||
@@ -17,10 +17,7 @@ import {
|
||||
SelectMarketTableRowSplash,
|
||||
} from './select-market-table';
|
||||
import type { ReactNode } from 'react';
|
||||
import type {
|
||||
MarketWithCandles,
|
||||
MarketWithData,
|
||||
} from '@vegaprotocol/market-list';
|
||||
import type { MarketMaybeWithDataAndCandles } from '@vegaprotocol/market-list';
|
||||
import type { PositionFieldsFragment } from '@vegaprotocol/positions';
|
||||
import type { Column, OnCellClickHandler } from './select-market-columns';
|
||||
import {
|
||||
@@ -30,8 +27,6 @@ import {
|
||||
} from '@vegaprotocol/environment';
|
||||
import { HeaderTitle } from '../header';
|
||||
|
||||
export type Market = MarketWithCandles & MarketWithData;
|
||||
|
||||
export const SelectAllMarketsTableBody = ({
|
||||
markets,
|
||||
positions,
|
||||
@@ -41,14 +36,14 @@ export const SelectAllMarketsTableBody = ({
|
||||
headers = columnHeaders,
|
||||
tableColumns = (market) => columns(market, onSelect, onCellClick, inViewRoot),
|
||||
}: {
|
||||
markets?: Market[] | null;
|
||||
markets?: MarketMaybeWithDataAndCandles[] | null;
|
||||
positions?: PositionFieldsFragment[];
|
||||
title?: string;
|
||||
onSelect: (id: string) => void;
|
||||
onCellClick: OnCellClickHandler;
|
||||
headers?: Column[];
|
||||
tableColumns?: (
|
||||
market: Market,
|
||||
market: MarketMaybeWithDataAndCandles,
|
||||
inViewRoot?: RefObject<HTMLDivElement>,
|
||||
openVolume?: string
|
||||
) => Column[];
|
||||
|
||||
@@ -185,7 +185,10 @@ export const VegaWalletConnectButton = () => {
|
||||
))}
|
||||
</DropdownMenuRadioGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem onClick={() => openTransferDialog(true)}>
|
||||
<DropdownMenuItem
|
||||
data-testid="wallet-transfer"
|
||||
onClick={() => openTransferDialog(true)}
|
||||
>
|
||||
{t('Transfer')}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem data-testid="disconnect" onClick={disconnect}>
|
||||
|
||||
@@ -3,13 +3,13 @@ import { MemoryRouter } from 'react-router-dom';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import type {
|
||||
MarketWithCandles,
|
||||
MarketWithData,
|
||||
MarketMaybeWithCandles,
|
||||
MarketMaybeWithData,
|
||||
MarketData,
|
||||
} from '@vegaprotocol/market-list';
|
||||
import { SelectMarketLandingTable } from './welcome-landing-dialog';
|
||||
|
||||
type Market = MarketWithCandles & MarketWithData;
|
||||
type Market = MarketMaybeWithCandles & MarketMaybeWithData;
|
||||
type PartialMarket = Partial<
|
||||
Omit<Market, 'data'> & { data: Partial<MarketData> }
|
||||
>;
|
||||
@@ -32,9 +32,13 @@ const MARKET_A: PartialMarket = {
|
||||
settlementAsset: {
|
||||
__typename: 'Asset',
|
||||
id: 'asset-ABC',
|
||||
name: 'asset-ABC',
|
||||
decimals: 2,
|
||||
symbol: 'ABC',
|
||||
},
|
||||
dataSourceSpecForTradingTermination: {
|
||||
id: '',
|
||||
},
|
||||
},
|
||||
metadata: {
|
||||
__typename: 'InstrumentMetadata',
|
||||
@@ -104,9 +108,13 @@ const MARKET_B: PartialMarket = {
|
||||
settlementAsset: {
|
||||
__typename: 'Asset',
|
||||
id: 'asset-XYZ',
|
||||
name: 'asset-XYZ',
|
||||
decimals: 2,
|
||||
symbol: 'XYZ',
|
||||
},
|
||||
dataSourceSpecForTradingTermination: {
|
||||
id: '',
|
||||
},
|
||||
},
|
||||
metadata: {
|
||||
__typename: 'InstrumentMetadata',
|
||||
|
||||
@@ -3,7 +3,8 @@ import { useMarketList } from '@vegaprotocol/market-list';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
||||
import { Link as UILink } from '@vegaprotocol/ui-toolkit';
|
||||
import type { Market, OnCellClickHandler } from '../select-market';
|
||||
import type { OnCellClickHandler } from '../select-market';
|
||||
import type { MarketMaybeWithDataAndCandles } from '@vegaprotocol/market-list';
|
||||
import {
|
||||
ColumnKind,
|
||||
columns,
|
||||
@@ -19,7 +20,7 @@ export const SelectMarketLandingTable = ({
|
||||
markets,
|
||||
onClose,
|
||||
}: {
|
||||
markets: Market[] | null;
|
||||
markets: MarketMaybeWithDataAndCandles[] | null;
|
||||
onClose: () => void;
|
||||
}) => {
|
||||
const params = useParams();
|
||||
|
||||
@@ -51,7 +51,7 @@ export const TransferContainer = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<p className="text-sm mb-4">
|
||||
<p className="text-sm mb-4" data-testid="dialog-transfer-text">
|
||||
{t('Transfer funds to another Vega key from')}{' '}
|
||||
<Lozenge className="font-mono">{truncateByChars(pubKey || '')}</Lozenge>{' '}
|
||||
{t('If you are at all unsure, stop and seek advice.')}
|
||||
|
||||
@@ -14,7 +14,6 @@ export * from '../market-depth/src/lib/market-depth.mock';
|
||||
export * from '../market-info/src/components/market-info/market-info.mock';
|
||||
export * from '../market-list/src/lib/market-candles.mock';
|
||||
export * from '../market-list/src/lib/market-data.mock';
|
||||
export * from '../market-list/src/lib/market.mock';
|
||||
export * from '../market-list/src/lib/markets-candles.mock';
|
||||
export * from '../market-list/src/lib/markets-data.mock';
|
||||
export * from '../market-list/src/lib/markets.mock';
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { GraphQLError } from 'graphql';
|
||||
import type { RouteHandler } from 'cypress/types/net-stubbing';
|
||||
import type { CyHttpMessages } from 'cypress/types/net-stubbing';
|
||||
|
||||
@@ -30,14 +31,15 @@ export const aliasGQLQuery = (
|
||||
req: CyHttpMessages.IncomingHttpRequest,
|
||||
operationName: string,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
data?: any
|
||||
data?: any,
|
||||
errors?: Partial<GraphQLError>[]
|
||||
) => {
|
||||
if (hasOperationName(req, operationName)) {
|
||||
req.alias = operationName;
|
||||
if (data !== undefined) {
|
||||
if (data !== undefined || errors !== undefined) {
|
||||
req.reply({
|
||||
statusCode: 200,
|
||||
body: { data },
|
||||
body: { ...(data && { data }), ...(errors && { errors }) },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { UseFormRegister } from 'react-hook-form';
|
||||
import type { MarketDealTicket } from '@vegaprotocol/market-list';
|
||||
import type { Market, MarketData } from '@vegaprotocol/market-list';
|
||||
import { DealTicketMarketAmount } from './deal-ticket-market-amount';
|
||||
import { DealTicketLimitAmount } from './deal-ticket-limit-amount';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
@@ -7,7 +7,8 @@ import type { DealTicketFormFields } from './deal-ticket';
|
||||
|
||||
export interface DealTicketAmountProps {
|
||||
orderType: Schema.OrderType;
|
||||
market: MarketDealTicket;
|
||||
marketData: MarketData;
|
||||
market: Market;
|
||||
register: UseFormRegister<DealTicketFormFields>;
|
||||
sizeError?: string;
|
||||
priceError?: string;
|
||||
@@ -15,11 +16,12 @@ export interface DealTicketAmountProps {
|
||||
|
||||
export const DealTicketAmount = ({
|
||||
orderType,
|
||||
marketData,
|
||||
...props
|
||||
}: DealTicketAmountProps) => {
|
||||
switch (orderType) {
|
||||
case Schema.OrderType.TYPE_MARKET:
|
||||
return <DealTicketMarketAmount {...props} />;
|
||||
return <DealTicketMarketAmount {...props} marketData={marketData} />;
|
||||
case Schema.OrderType.TYPE_LIMIT:
|
||||
return <DealTicketLimitAmount {...props} />;
|
||||
default: {
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
import { useMemo } from 'react';
|
||||
import { AsyncRenderer, Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import { t, useDataProvider } from '@vegaprotocol/react-helpers';
|
||||
import type {
|
||||
MarketDataUpdateFieldsFragment,
|
||||
MarketDealTicket,
|
||||
} from '@vegaprotocol/market-list';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import { useThrottledDataProvider } from '@vegaprotocol/react-helpers';
|
||||
import { useVegaTransactionStore } from '@vegaprotocol/wallet';
|
||||
import { marketDealTicketProvider } from '@vegaprotocol/market-list';
|
||||
import { useMarket, marketDataProvider } from '@vegaprotocol/market-list';
|
||||
import { DealTicket } from './deal-ticket';
|
||||
|
||||
export interface DealTicketContainerProps {
|
||||
@@ -14,31 +11,35 @@ export interface DealTicketContainerProps {
|
||||
}
|
||||
|
||||
export const DealTicketContainer = ({ marketId }: DealTicketContainerProps) => {
|
||||
const variables = useMemo(
|
||||
() => ({
|
||||
marketId: marketId || '',
|
||||
}),
|
||||
[marketId]
|
||||
const {
|
||||
data: market,
|
||||
error: marketError,
|
||||
loading: marketLoading,
|
||||
} = useMarket(marketId);
|
||||
|
||||
const {
|
||||
data: marketData,
|
||||
error: marketDataError,
|
||||
loading: marketDataLoading,
|
||||
} = useThrottledDataProvider(
|
||||
{
|
||||
dataProvider: marketDataProvider,
|
||||
variables: useMemo(() => ({ marketId }), [marketId]),
|
||||
},
|
||||
1000
|
||||
);
|
||||
const { data, error, loading } = useDataProvider<
|
||||
MarketDealTicket,
|
||||
MarketDataUpdateFieldsFragment
|
||||
>({
|
||||
dataProvider: marketDealTicketProvider,
|
||||
variables,
|
||||
skip: !marketId,
|
||||
});
|
||||
const create = useVegaTransactionStore((state) => state.create);
|
||||
|
||||
return (
|
||||
<AsyncRenderer<MarketDealTicket>
|
||||
data={data || undefined}
|
||||
loading={loading}
|
||||
error={error}
|
||||
<AsyncRenderer
|
||||
data={market && marketData}
|
||||
loading={marketLoading || marketDataLoading}
|
||||
error={marketError || marketDataError}
|
||||
>
|
||||
{data ? (
|
||||
{market && marketData ? (
|
||||
<DealTicket
|
||||
market={data}
|
||||
market={market}
|
||||
marketData={marketData}
|
||||
submit={(orderSubmission) => create({ orderSubmission })}
|
||||
/>
|
||||
) : (
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||
import type { ReactNode } from 'react';
|
||||
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
|
||||
import type { MarketDealTicket } from '@vegaprotocol/market-list';
|
||||
import type { Market, MarketData } from '@vegaprotocol/market-list';
|
||||
import {
|
||||
getFeeDetailsValues,
|
||||
useFeeDealTicketDetails,
|
||||
@@ -9,7 +9,8 @@ import {
|
||||
|
||||
interface DealTicketFeeDetailsProps {
|
||||
order: OrderSubmissionBody['orderSubmission'];
|
||||
market: MarketDealTicket;
|
||||
market: Market;
|
||||
marketData: MarketData;
|
||||
}
|
||||
|
||||
export interface DealTicketFeeDetails {
|
||||
@@ -22,8 +23,9 @@ export interface DealTicketFeeDetails {
|
||||
export const DealTicketFeeDetails = ({
|
||||
order,
|
||||
market,
|
||||
marketData,
|
||||
}: DealTicketFeeDetailsProps) => {
|
||||
const feeDetails = useFeeDealTicketDetails(order, market);
|
||||
const feeDetails = useFeeDealTicketDetails(order, market, marketData);
|
||||
const details = getFeeDetailsValues(feeDetails);
|
||||
return (
|
||||
<div>
|
||||
|
||||
@@ -3,7 +3,7 @@ import { t, toDecimal, validateAmount } from '@vegaprotocol/react-helpers';
|
||||
import type { DealTicketAmountProps } from './deal-ticket-amount';
|
||||
|
||||
export type DealTicketLimitAmountProps = Omit<
|
||||
DealTicketAmountProps,
|
||||
Omit<DealTicketAmountProps, 'marketData'>,
|
||||
'orderType'
|
||||
>;
|
||||
|
||||
|
||||
@@ -17,11 +17,12 @@ export type DealTicketMarketAmountProps = Omit<
|
||||
export const DealTicketMarketAmount = ({
|
||||
register,
|
||||
market,
|
||||
marketData,
|
||||
sizeError,
|
||||
}: DealTicketMarketAmountProps) => {
|
||||
const quoteName = market.tradableInstrument.instrument.product.quoteName;
|
||||
const sizeStep = toDecimal(market?.positionDecimalPlaces);
|
||||
const price = getMarketPrice(market);
|
||||
const price = getMarketPrice(marketData);
|
||||
|
||||
const priceFormatted = price
|
||||
? addDecimalsFormatNumber(price, market.decimalPlaces)
|
||||
@@ -33,7 +34,7 @@ export const DealTicketMarketAmount = ({
|
||||
<div className="flex-1 text-sm">Size</div>
|
||||
<div />
|
||||
<div className="flex-2 text-sm text-right">
|
||||
{isMarketInAuction(market) && (
|
||||
{isMarketInAuction(marketData.marketTradingMode) && (
|
||||
<Tooltip
|
||||
description={t(
|
||||
'This market is in auction. The uncrossing price is an indication of what the price is expected to be when the auction ends.'
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
act,
|
||||
waitFor,
|
||||
} from '@testing-library/react';
|
||||
import { generateMarket } from '../../test-helpers';
|
||||
import { generateMarket, generateMarketData } from '../../test-helpers';
|
||||
import { DealTicket } from './deal-ticket';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
|
||||
@@ -25,6 +25,7 @@ jest.mock('../../hooks/use-has-no-balance', () => {
|
||||
});
|
||||
|
||||
const market = generateMarket();
|
||||
const marketData = generateMarketData();
|
||||
const submit = jest.fn();
|
||||
|
||||
const mockChainId = 'chain-id';
|
||||
@@ -45,7 +46,7 @@ function generateJsx(order?: OrderSubmissionBody['orderSubmission']) {
|
||||
return (
|
||||
<MockedProvider mocks={[chainIdMock]}>
|
||||
<VegaWalletContext.Provider value={{ pubKey: mockChainId } as any}>
|
||||
<DealTicket market={market} submit={submit} />
|
||||
<DealTicket market={market} marketData={marketData} submit={submit} />
|
||||
</VegaWalletContext.Provider>
|
||||
</MockedProvider>
|
||||
);
|
||||
@@ -79,11 +80,10 @@ describe('DealTicket', () => {
|
||||
expect(screen.getByTestId('order-tif')).toHaveValue(
|
||||
Schema.OrderTimeInForce.TIME_IN_FORCE_IOC
|
||||
);
|
||||
|
||||
// Assert last price is shown
|
||||
expect(screen.getByTestId('last-price')).toHaveTextContent(
|
||||
// eslint-disable-next-line
|
||||
`~${addDecimal(market!.data.markPrice, market.decimalPlaces)} ${
|
||||
`~${addDecimal(marketData.markPrice, market.decimalPlaces)} ${
|
||||
market.tradableInstrument.instrument.product.quoteName
|
||||
}`
|
||||
);
|
||||
|
||||
@@ -25,14 +25,17 @@ import {
|
||||
import { ZeroBalanceError } from '../deal-ticket-validation/zero-balance-error';
|
||||
import { SummaryValidationType } from '../../constants';
|
||||
import { useHasNoBalance } from '../../hooks/use-has-no-balance';
|
||||
import type { MarketDealTicket } from '@vegaprotocol/market-list';
|
||||
import type { Market, MarketData } from '@vegaprotocol/market-list';
|
||||
import {
|
||||
usePersistedOrderStore,
|
||||
usePersistedOrderStoreSubscription,
|
||||
} from '@vegaprotocol/orders';
|
||||
|
||||
export type TransactionStatus = 'default' | 'pending';
|
||||
|
||||
export interface DealTicketProps {
|
||||
market: MarketDealTicket;
|
||||
market: Market;
|
||||
marketData: MarketData;
|
||||
submit: (order: OrderSubmissionBody['orderSubmission']) => void;
|
||||
}
|
||||
|
||||
@@ -42,7 +45,7 @@ export type DealTicketFormFields = OrderSubmissionBody['orderSubmission'] & {
|
||||
summary: string;
|
||||
};
|
||||
|
||||
export const DealTicket = ({ market, submit }: DealTicketProps) => {
|
||||
export const DealTicket = ({ market, marketData, submit }: DealTicketProps) => {
|
||||
const { pubKey, isReadOnly } = useVegaWallet();
|
||||
const { getPersistedOrder, setPersistedOrder } = usePersistedOrderStore(
|
||||
(store) => ({
|
||||
@@ -77,12 +80,12 @@ export const DealTicket = ({ market, submit }: DealTicketProps) => {
|
||||
}
|
||||
});
|
||||
|
||||
const marketStateError = validateMarketState(market.data.marketState);
|
||||
const marketStateError = validateMarketState(marketData.marketState);
|
||||
const hasNoBalance = useHasNoBalance(
|
||||
market.tradableInstrument.instrument.product.settlementAsset.id
|
||||
);
|
||||
const marketTradingModeError = validateMarketTradingMode(
|
||||
market.data.marketTradingMode
|
||||
marketData.marketTradingMode
|
||||
);
|
||||
useEffect(() => {
|
||||
if (
|
||||
@@ -165,13 +168,17 @@ export const DealTicket = ({ market, submit }: DealTicketProps) => {
|
||||
name="type"
|
||||
control={control}
|
||||
rules={{
|
||||
validate: validateType(market),
|
||||
validate: validateType(
|
||||
marketData.marketTradingMode,
|
||||
marketData.trigger
|
||||
),
|
||||
}}
|
||||
render={({ field }) => (
|
||||
<TypeSelector
|
||||
value={field.value}
|
||||
onSelect={field.onChange}
|
||||
market={market}
|
||||
marketData={marketData}
|
||||
errorMessage={errors.type?.message}
|
||||
/>
|
||||
)}
|
||||
@@ -186,6 +193,7 @@ export const DealTicket = ({ market, submit }: DealTicketProps) => {
|
||||
<DealTicketAmount
|
||||
orderType={order.type}
|
||||
market={market}
|
||||
marketData={marketData}
|
||||
register={register}
|
||||
sizeError={errors.size?.message}
|
||||
priceError={errors.price?.message}
|
||||
@@ -194,7 +202,10 @@ export const DealTicket = ({ market, submit }: DealTicketProps) => {
|
||||
name="timeInForce"
|
||||
control={control}
|
||||
rules={{
|
||||
validate: validateTimeInForce(market),
|
||||
validate: validateTimeInForce(
|
||||
marketData.marketTradingMode,
|
||||
marketData.trigger
|
||||
),
|
||||
}}
|
||||
render={({ field }) => (
|
||||
<TimeInForceSelector
|
||||
@@ -202,6 +213,7 @@ export const DealTicket = ({ market, submit }: DealTicketProps) => {
|
||||
orderType={order.type}
|
||||
onSelect={field.onChange}
|
||||
market={market}
|
||||
marketData={marketData}
|
||||
errorMessage={errors.timeInForce?.message}
|
||||
/>
|
||||
)}
|
||||
@@ -228,10 +240,15 @@ export const DealTicket = ({ market, submit }: DealTicketProps) => {
|
||||
<SummaryMessage
|
||||
errorMessage={errors.summary?.message}
|
||||
market={market}
|
||||
marketData={marketData}
|
||||
order={order}
|
||||
isReadOnly={isReadOnly}
|
||||
/>
|
||||
<DealTicketFeeDetails order={order} market={market} />
|
||||
<DealTicketFeeDetails
|
||||
order={order}
|
||||
market={market}
|
||||
marketData={marketData}
|
||||
/>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
@@ -242,17 +259,25 @@ export const DealTicket = ({ market, submit }: DealTicketProps) => {
|
||||
*/
|
||||
interface SummaryMessageProps {
|
||||
errorMessage?: string;
|
||||
market: MarketDealTicket;
|
||||
market: Market;
|
||||
marketData: MarketData;
|
||||
order: OrderSubmissionBody['orderSubmission'];
|
||||
isReadOnly: boolean;
|
||||
}
|
||||
const SummaryMessage = memo(
|
||||
({ errorMessage, market, order, isReadOnly }: SummaryMessageProps) => {
|
||||
({
|
||||
errorMessage,
|
||||
market,
|
||||
marketData,
|
||||
order,
|
||||
isReadOnly,
|
||||
}: SummaryMessageProps) => {
|
||||
// Specific error UI for if balance is so we can
|
||||
// render a deposit dialog
|
||||
const asset = market.tradableInstrument.instrument.product.settlementAsset;
|
||||
const { balanceError, balance, margin } = useOrderMarginValidation({
|
||||
market,
|
||||
marketData,
|
||||
order,
|
||||
});
|
||||
if (isReadOnly) {
|
||||
@@ -298,7 +323,7 @@ const SummaryMessage = memo(
|
||||
Schema.MarketTradingMode.TRADING_MODE_BATCH_AUCTION,
|
||||
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
|
||||
Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION,
|
||||
].includes(market.data.marketTradingMode)
|
||||
].includes(marketData.marketTradingMode)
|
||||
) {
|
||||
return (
|
||||
<div
|
||||
|
||||
@@ -24,11 +24,10 @@ import {
|
||||
import { IconNames } from '@blueprintjs/icons';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import type { Market } from '@vegaprotocol/market-list';
|
||||
import type { MarketDealTicket } from '@vegaprotocol/market-list';
|
||||
import { marketsProvider } from '@vegaprotocol/market-list';
|
||||
|
||||
interface Props {
|
||||
market: MarketDealTicket;
|
||||
market: Market;
|
||||
setMarket: (marketId: string) => void;
|
||||
ItemRenderer?: React.FC<{
|
||||
market: Market;
|
||||
|
||||
@@ -8,15 +8,16 @@ import {
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { DataGrid, t } from '@vegaprotocol/react-helpers';
|
||||
import { timeInForceLabel } from '@vegaprotocol/orders';
|
||||
import type { MarketDealTicket } from '@vegaprotocol/market-list';
|
||||
import { compileGridData } from '../trading-mode-tooltip';
|
||||
import { MarketModeValidationType } from '../../constants';
|
||||
import type { Market, StaticMarketData } from '@vegaprotocol/market-list';
|
||||
|
||||
interface TimeInForceSelectorProps {
|
||||
value: Schema.OrderTimeInForce;
|
||||
orderType: Schema.OrderType;
|
||||
onSelect: (tif: Schema.OrderTimeInForce) => void;
|
||||
market: MarketDealTicket;
|
||||
market: Market;
|
||||
marketData: StaticMarketData;
|
||||
errorMessage?: string;
|
||||
}
|
||||
|
||||
@@ -34,6 +35,7 @@ export const TimeInForceSelector = ({
|
||||
orderType,
|
||||
onSelect,
|
||||
market,
|
||||
marketData,
|
||||
errorMessage,
|
||||
}: TimeInForceSelectorProps) => {
|
||||
const options =
|
||||
@@ -80,7 +82,7 @@ export const TimeInForceSelector = ({
|
||||
{t('This market is in auction until it reaches')}{' '}
|
||||
<Tooltip
|
||||
description={
|
||||
<DataGrid grid={compileGridData(market, market.data)} />
|
||||
<DataGrid grid={compileGridData(market, marketData)} />
|
||||
}
|
||||
>
|
||||
<span>{t('sufficient liquidity')}</span>
|
||||
@@ -99,7 +101,7 @@ export const TimeInForceSelector = ({
|
||||
{t('This market is in auction due to')}{' '}
|
||||
<Tooltip
|
||||
description={
|
||||
<DataGrid grid={compileGridData(market, market.data)} />
|
||||
<DataGrid grid={compileGridData(market, marketData)} />
|
||||
}
|
||||
>
|
||||
<span>{t('high price volatility')}</span>
|
||||
|
||||
@@ -2,14 +2,15 @@ import { FormGroup, InputError, Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||
import { DataGrid, t } from '@vegaprotocol/react-helpers';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { Toggle } from '@vegaprotocol/ui-toolkit';
|
||||
import type { MarketDealTicket } from '@vegaprotocol/market-list';
|
||||
import type { Market, MarketData } from '@vegaprotocol/market-list';
|
||||
import { compileGridData } from '../trading-mode-tooltip';
|
||||
import { MarketModeValidationType } from '../../constants';
|
||||
|
||||
interface TypeSelectorProps {
|
||||
value: Schema.OrderType;
|
||||
onSelect: (type: Schema.OrderType) => void;
|
||||
market: MarketDealTicket;
|
||||
market: Market;
|
||||
marketData: MarketData;
|
||||
errorMessage?: string;
|
||||
}
|
||||
|
||||
@@ -22,6 +23,7 @@ export const TypeSelector = ({
|
||||
value,
|
||||
onSelect,
|
||||
market,
|
||||
marketData,
|
||||
errorMessage,
|
||||
}: TypeSelectorProps) => {
|
||||
const renderError = (errorType: MarketModeValidationType) => {
|
||||
@@ -35,7 +37,7 @@ export const TypeSelector = ({
|
||||
{t('This market is in auction until it reaches')}{' '}
|
||||
<Tooltip
|
||||
description={
|
||||
<DataGrid grid={compileGridData(market, market.data)} />
|
||||
<DataGrid grid={compileGridData(market, marketData)} />
|
||||
}
|
||||
>
|
||||
<span>{t('sufficient liquidity')}</span>
|
||||
@@ -52,7 +54,7 @@ export const TypeSelector = ({
|
||||
{t('This market is in auction due to')}{' '}
|
||||
<Tooltip
|
||||
description={
|
||||
<DataGrid grid={compileGridData(market, market.data)} />
|
||||
<DataGrid grid={compileGridData(market, marketData)} />
|
||||
}
|
||||
>
|
||||
<span>{t('high price volatility')}</span>
|
||||
|
||||
@@ -13,9 +13,9 @@ import type { Market, MarketData } from '@vegaprotocol/market-list';
|
||||
export const compileGridData = (
|
||||
market: Pick<
|
||||
Market,
|
||||
'tradableInstrument' | 'id' | 'decimalPlaces' | 'positionDecimalPlaces'
|
||||
'id' | 'tradableInstrument' | 'decimalPlaces' | 'positionDecimalPlaces'
|
||||
>,
|
||||
marketData: Pick<
|
||||
marketData?: Pick<
|
||||
MarketData,
|
||||
| 'marketTradingMode'
|
||||
| 'auctionStart'
|
||||
@@ -25,14 +25,14 @@ export const compileGridData = (
|
||||
| 'suppliedStake'
|
||||
| 'targetStake'
|
||||
| 'trigger'
|
||||
>,
|
||||
> | null,
|
||||
onSelect?: (id: string) => void
|
||||
): { label: ReactNode; value?: ReactNode }[] => {
|
||||
const grid: DataGridProps['grid'] = [];
|
||||
const isLiquidityMonitoringAuction =
|
||||
marketData.marketTradingMode ===
|
||||
marketData?.marketTradingMode ===
|
||||
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION &&
|
||||
marketData.trigger === Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY;
|
||||
marketData?.trigger === Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY;
|
||||
|
||||
const formatStake = (value: string) => {
|
||||
const formattedValue = addDecimalsFormatNumber(
|
||||
|
||||
@@ -22,15 +22,16 @@ export const TradingModeTooltip = ({
|
||||
skip,
|
||||
}: TradingModeTooltipProps) => {
|
||||
const { VEGA_DOCS_URL } = useEnvironment();
|
||||
const market = useMarket(marketId);
|
||||
const marketData = useStaticMarketData(marketId, skip);
|
||||
const { marketTradingMode: tradingMode, trigger } = marketData || {};
|
||||
const { data: market } = useMarket(marketId);
|
||||
const { data: marketData } = useStaticMarketData(marketId, skip);
|
||||
const { marketTradingMode, trigger } = marketData || {};
|
||||
const variables = useMemo(() => ({ marketId: marketId || '' }), [marketId]);
|
||||
const { data: proposalData } = useProposalOfMarketQuery({
|
||||
variables,
|
||||
skip:
|
||||
!tradingMode ||
|
||||
Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION !== tradingMode,
|
||||
!marketTradingMode ||
|
||||
Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION !==
|
||||
marketTradingMode,
|
||||
});
|
||||
|
||||
if (!market || !marketData) {
|
||||
@@ -43,7 +44,7 @@ export const TradingModeTooltip = ({
|
||||
const compiledGrid =
|
||||
onSelect && compileGridData(market, marketData, onSelect);
|
||||
|
||||
switch (tradingMode) {
|
||||
switch (marketTradingMode) {
|
||||
case Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS: {
|
||||
return (
|
||||
<section data-testid="trading-mode-tooltip">
|
||||
@@ -67,7 +68,7 @@ export const TradingModeTooltip = ({
|
||||
className="justify-center font-bold my-2"
|
||||
data-testid="opening-auction-sub-status"
|
||||
>
|
||||
{`${Schema.MarketTradingModeMapping[tradingMode]}: ${t(
|
||||
{`${Schema.MarketTradingModeMapping[marketTradingMode]}: ${t(
|
||||
'Not enough liquidity to open'
|
||||
)}`}
|
||||
</span>
|
||||
@@ -84,7 +85,9 @@ export const TradingModeTooltip = ({
|
||||
className="justify-center font-bold my-2"
|
||||
data-testid="opening-auction-sub-status"
|
||||
>
|
||||
{`${Schema.MarketTradingModeMapping[tradingMode]}: ${t(
|
||||
{`${
|
||||
Schema.MarketTradingModeMapping[marketTradingMode]
|
||||
}: ${t(
|
||||
'Closing on %s',
|
||||
getDateTimeFormat().format(enactmentDate)
|
||||
)}`}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import type { Market } from '@vegaprotocol/market-list';
|
||||
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
|
||||
import { useCalculateSlippage } from './use-calculate-slippage';
|
||||
|
||||
@@ -74,12 +75,17 @@ describe('useCalculateSlippage Hook', () => {
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
const market = {
|
||||
id: 'marketId',
|
||||
decimalPlaces: 0,
|
||||
positionDecimalPlaces: 0,
|
||||
} as Market;
|
||||
|
||||
it('long order', () => {
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useCalculateSlippage({
|
||||
marketId: 'marketId',
|
||||
market,
|
||||
order: {
|
||||
size: '10',
|
||||
side: Schema.Side.SIDE_BUY,
|
||||
@@ -96,7 +102,7 @@ describe('useCalculateSlippage Hook', () => {
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useCalculateSlippage({
|
||||
marketId: 'marketId',
|
||||
market,
|
||||
order: {
|
||||
size: '10',
|
||||
side: Schema.Side.SIDE_SELL,
|
||||
@@ -122,7 +128,7 @@ describe('useCalculateSlippage Hook', () => {
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useCalculateSlippage({
|
||||
marketId: 'marketId',
|
||||
market,
|
||||
order: {
|
||||
size: '10',
|
||||
side: Schema.Side.SIDE_SELL,
|
||||
|
||||
@@ -1,36 +1,29 @@
|
||||
import { useMemo } from 'react';
|
||||
import { marketDepthProvider } from '@vegaprotocol/market-depth';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { marketProvider } from '@vegaprotocol/market-list';
|
||||
import type { SingleMarketFieldsFragment } from '@vegaprotocol/market-list';
|
||||
import type { Market } from '@vegaprotocol/market-list';
|
||||
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
|
||||
import { BigNumber } from 'bignumber.js';
|
||||
import {
|
||||
formatNumber,
|
||||
toBigNum,
|
||||
useDataProvider,
|
||||
useThrottledDataProvider,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
|
||||
interface Props {
|
||||
marketId: string;
|
||||
market: Market;
|
||||
order: OrderSubmissionBody['orderSubmission'];
|
||||
}
|
||||
|
||||
export const useCalculateSlippage = ({ marketId, order }: Props) => {
|
||||
const variables = useMemo(() => ({ marketId }), [marketId]);
|
||||
export const useCalculateSlippage = ({ market, order }: Props) => {
|
||||
const variables = useMemo(() => ({ marketId: market.id }), [market.id]);
|
||||
const { data } = useThrottledDataProvider(
|
||||
{
|
||||
dataProvider: marketDepthProvider,
|
||||
variables,
|
||||
},
|
||||
5000
|
||||
1000
|
||||
);
|
||||
const { data: market } = useDataProvider<SingleMarketFieldsFragment, never>({
|
||||
dataProvider: marketProvider,
|
||||
skipUpdates: true,
|
||||
variables,
|
||||
});
|
||||
const volPriceArr =
|
||||
data?.depth[order.side === Schema.Side.SIDE_BUY ? 'sell' : 'buy'] || [];
|
||||
if (volPriceArr.length && market) {
|
||||
|
||||
@@ -9,7 +9,7 @@ import * as Schema from '@vegaprotocol/types';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { useMemo } from 'react';
|
||||
import type { MarketDealTicket } from '@vegaprotocol/market-list';
|
||||
import type { Market, MarketData } from '@vegaprotocol/market-list';
|
||||
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
|
||||
import {
|
||||
EST_CLOSEOUT_TOOLTIP_TEXT,
|
||||
@@ -24,14 +24,15 @@ import { getDerivedPrice } from '../utils/get-price';
|
||||
|
||||
export const useFeeDealTicketDetails = (
|
||||
order: OrderSubmissionBody['orderSubmission'],
|
||||
market: MarketDealTicket
|
||||
market: Market,
|
||||
marketData: MarketData
|
||||
) => {
|
||||
const { pubKey } = useVegaWallet();
|
||||
const slippage = useCalculateSlippage({ marketId: market.id, order });
|
||||
const slippage = useCalculateSlippage({ market, order });
|
||||
|
||||
const derivedPrice = useMemo(() => {
|
||||
return getDerivedPrice(order, market);
|
||||
}, [order, market]);
|
||||
return getDerivedPrice(order, market, marketData);
|
||||
}, [order, market, marketData]);
|
||||
|
||||
// Note this isn't currently used anywhere
|
||||
const slippageAdjustedPrice = useMemo(() => {
|
||||
@@ -51,6 +52,7 @@ export const useFeeDealTicketDetails = (
|
||||
const estMargin = useOrderMargin({
|
||||
order,
|
||||
market,
|
||||
marketData,
|
||||
partyId: pubKey || '',
|
||||
derivedPrice,
|
||||
});
|
||||
@@ -58,6 +60,7 @@ export const useFeeDealTicketDetails = (
|
||||
const estCloseOut = useOrderCloseOut({
|
||||
order,
|
||||
market,
|
||||
marketData,
|
||||
});
|
||||
|
||||
const notionalSize = useMemo(() => {
|
||||
@@ -94,7 +97,7 @@ export const useFeeDealTicketDetails = (
|
||||
};
|
||||
|
||||
export interface FeeDetails {
|
||||
market: MarketDealTicket;
|
||||
market: Market;
|
||||
symbol: string;
|
||||
notionalSize: string | null;
|
||||
estMargin: OrderMargin | null;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
|
||||
import type { MarketDealTicket } from '@vegaprotocol/market-list';
|
||||
import type { Market, MarketData } from '@vegaprotocol/market-list';
|
||||
import { useOrderCloseOut } from './use-order-closeout';
|
||||
|
||||
jest.mock('@vegaprotocol/wallet', () => ({
|
||||
@@ -18,11 +18,6 @@ describe('useOrderCloseOut', () => {
|
||||
const order = { size: '2', side: 'SIDE_BUY' };
|
||||
const market = {
|
||||
decimalPlaces: 5,
|
||||
depth: {
|
||||
lastTrade: {
|
||||
price: '1000000',
|
||||
},
|
||||
},
|
||||
tradableInstrument: {
|
||||
instrument: {
|
||||
product: {
|
||||
@@ -32,10 +27,11 @@ describe('useOrderCloseOut', () => {
|
||||
},
|
||||
},
|
||||
},
|
||||
data: {
|
||||
markPrice: 100000,
|
||||
},
|
||||
} as unknown as MarketDealTicket;
|
||||
} as unknown as Market;
|
||||
|
||||
const marketData = {
|
||||
markPrice: 100000,
|
||||
} as unknown as MarketData;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
@@ -47,7 +43,10 @@ describe('useOrderCloseOut', () => {
|
||||
() =>
|
||||
useOrderCloseOut({
|
||||
order: order as OrderSubmissionBody['orderSubmission'],
|
||||
market: { ...market, data: { ...market.data, markPrice: '0' } },
|
||||
market,
|
||||
marketData: {
|
||||
markPrice: '0',
|
||||
} as MarketData,
|
||||
}),
|
||||
{
|
||||
wrapper: MockedProvider,
|
||||
@@ -65,7 +64,8 @@ describe('useOrderCloseOut', () => {
|
||||
...order,
|
||||
side: 'SIDE_SELL',
|
||||
} as OrderSubmissionBody['orderSubmission'],
|
||||
market: market,
|
||||
market,
|
||||
marketData,
|
||||
}),
|
||||
{
|
||||
wrapper: MockedProvider,
|
||||
@@ -85,7 +85,8 @@ describe('useOrderCloseOut', () => {
|
||||
type: 'TYPE_LIMIT',
|
||||
side: 'SIDE_SELL',
|
||||
} as OrderSubmissionBody['orderSubmission'],
|
||||
market: market,
|
||||
market,
|
||||
marketData,
|
||||
}),
|
||||
{
|
||||
wrapper: MockedProvider,
|
||||
@@ -102,7 +103,10 @@ describe('useOrderCloseOut', () => {
|
||||
...order,
|
||||
side: 'SIDE_SELL',
|
||||
} as OrderSubmissionBody['orderSubmission'],
|
||||
market: { ...market, data: { ...market.data, markPrice: '0' } },
|
||||
market,
|
||||
marketData: {
|
||||
markPrice: '0',
|
||||
} as MarketData,
|
||||
}),
|
||||
{
|
||||
wrapper: MockedProvider,
|
||||
|
||||
@@ -2,7 +2,7 @@ import { BigNumber } from 'bignumber.js';
|
||||
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
|
||||
import { addDecimal } from '@vegaprotocol/react-helpers';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import type { MarketDealTicket } from '@vegaprotocol/market-list';
|
||||
import type { Market, MarketData } from '@vegaprotocol/market-list';
|
||||
import {
|
||||
useAccountBalance,
|
||||
useMarketAccountBalance,
|
||||
@@ -12,10 +12,15 @@ import { useMarketPositions } from './use-market-positions';
|
||||
|
||||
interface Props {
|
||||
order: OrderSubmissionBody['orderSubmission'];
|
||||
market: MarketDealTicket;
|
||||
market: Market;
|
||||
marketData: MarketData;
|
||||
}
|
||||
|
||||
export const useOrderCloseOut = ({ order, market }: Props): string | null => {
|
||||
export const useOrderCloseOut = ({
|
||||
order,
|
||||
market,
|
||||
marketData,
|
||||
}: Props): string | null => {
|
||||
const { accountBalance, accountDecimals } = useAccountBalance(
|
||||
market.tradableInstrument.instrument.product.settlementAsset.id
|
||||
);
|
||||
@@ -43,9 +48,7 @@ export const useOrderCloseOut = ({ order, market }: Props): string | null => {
|
||||
const price =
|
||||
order.type === Schema.OrderType.TYPE_LIMIT && order.price
|
||||
? new BigNumber(order.price)
|
||||
: new BigNumber(
|
||||
addDecimal(market.data.markPrice || 0, market.decimalPlaces || 0)
|
||||
);
|
||||
: new BigNumber(addDecimal(marketData.markPrice, market.decimalPlaces));
|
||||
// regarding formula (marginMaintenanceLevel - positionAccountBalance - generalAccountBalance) / volume + markPrice
|
||||
const marginDifference = marginMaintenanceLevel
|
||||
.minus(positionAccountBalance)
|
||||
|
||||
@@ -4,18 +4,24 @@ import { toBigNum } from '@vegaprotocol/react-helpers';
|
||||
import { useAccountBalance } from '@vegaprotocol/accounts';
|
||||
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
|
||||
import { useOrderMargin } from './use-order-margin';
|
||||
import type { MarketDealTicket } from '@vegaprotocol/market-list';
|
||||
import type { Market, MarketData } from '@vegaprotocol/market-list';
|
||||
|
||||
interface Props {
|
||||
market: MarketDealTicket;
|
||||
market: Market;
|
||||
marketData: MarketData;
|
||||
order: OrderSubmissionBody['orderSubmission'];
|
||||
}
|
||||
|
||||
export const useOrderMarginValidation = ({ market, order }: Props) => {
|
||||
export const useOrderMarginValidation = ({
|
||||
market,
|
||||
marketData,
|
||||
order,
|
||||
}: Props) => {
|
||||
const { pubKey } = useVegaWallet();
|
||||
const estMargin = useOrderMargin({
|
||||
order,
|
||||
market,
|
||||
marketData,
|
||||
partyId: pubKey || '',
|
||||
});
|
||||
const { id: assetId, decimals: assetDecimals } =
|
||||
|
||||
@@ -5,7 +5,7 @@ import type { PositionMargin } from './use-market-positions';
|
||||
import type { Props } from './use-order-margin';
|
||||
import { useOrderMargin } from './use-order-margin';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import type { MarketDealTicket } from '@vegaprotocol/market-list';
|
||||
import type { Market, MarketData } from '@vegaprotocol/market-list';
|
||||
|
||||
let mockEstimateData = {
|
||||
estimateOrder: {
|
||||
@@ -55,11 +55,11 @@ describe('useOrderMargin', () => {
|
||||
decimalPlaces: 2,
|
||||
positionDecimalPlaces: 0,
|
||||
tradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
|
||||
data: {
|
||||
indicativePrice: '100',
|
||||
markPrice: '200',
|
||||
},
|
||||
} as MarketDealTicket,
|
||||
} as unknown as Market,
|
||||
marketData: {
|
||||
indicativePrice: '100',
|
||||
markPrice: '200',
|
||||
} as unknown as MarketData,
|
||||
partyId: 'partyId',
|
||||
};
|
||||
|
||||
|
||||
@@ -4,12 +4,13 @@ import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
|
||||
import { removeDecimal } from '@vegaprotocol/react-helpers';
|
||||
import { useMarketPositions } from './use-market-positions';
|
||||
import { useEstimateOrderQuery } from './__generated__/EstimateOrder';
|
||||
import type { MarketDealTicket } from '@vegaprotocol/market-list';
|
||||
import type { Market, MarketData } from '@vegaprotocol/market-list';
|
||||
import { getDerivedPrice } from '../utils/get-price';
|
||||
|
||||
export interface Props {
|
||||
order: OrderSubmissionBody['orderSubmission'];
|
||||
market: MarketDealTicket;
|
||||
market: Market;
|
||||
marketData: MarketData;
|
||||
partyId: string;
|
||||
derivedPrice?: string;
|
||||
}
|
||||
@@ -27,11 +28,13 @@ export interface OrderMargin {
|
||||
export const useOrderMargin = ({
|
||||
order,
|
||||
market,
|
||||
marketData,
|
||||
partyId,
|
||||
derivedPrice,
|
||||
}: Props): OrderMargin | null => {
|
||||
const { balance } = useMarketPositions({ marketId: market.id }) || {};
|
||||
const priceForEstimate = derivedPrice || getDerivedPrice(order, market);
|
||||
const priceForEstimate =
|
||||
derivedPrice || getDerivedPrice(order, market, marketData);
|
||||
|
||||
const { data } = useEstimateOrderQuery({
|
||||
variables: {
|
||||
|
||||
@@ -1,68 +1,49 @@
|
||||
import type { MarketDealTicket } from '@vegaprotocol/market-list';
|
||||
import type { Market, MarketData } from '@vegaprotocol/market-list';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import merge from 'lodash/merge';
|
||||
import type { PartialDeep } from 'type-fest';
|
||||
|
||||
export function generateMarket(
|
||||
override?: PartialDeep<MarketDealTicket>
|
||||
): MarketDealTicket {
|
||||
const defaultMarket: MarketDealTicket = {
|
||||
export function generateMarket(override?: PartialDeep<Market>): Market {
|
||||
const defaultMarket: Market = {
|
||||
__typename: 'Market',
|
||||
id: 'market-id',
|
||||
decimalPlaces: 2,
|
||||
positionDecimalPlaces: 1,
|
||||
tradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
|
||||
state: Schema.MarketState.STATE_ACTIVE,
|
||||
marketTimestamps: {
|
||||
__typename: 'MarketTimestamps',
|
||||
close: '',
|
||||
open: '',
|
||||
},
|
||||
tradableInstrument: {
|
||||
__typename: 'TradableInstrument',
|
||||
instrument: {
|
||||
__typename: 'Instrument',
|
||||
id: '1',
|
||||
name: 'Instrument name',
|
||||
code: 'instrument-code',
|
||||
id: '',
|
||||
code: 'BTCUSD.MF21',
|
||||
name: 'ACTIVE MARKET',
|
||||
metadata: {
|
||||
__typename: 'InstrumentMetadata',
|
||||
tags: [],
|
||||
},
|
||||
product: {
|
||||
__typename: 'Future',
|
||||
quoteName: 'quote-name',
|
||||
dataSourceSpecForTradingTermination: {
|
||||
id: 'data-source-for-trading-termination-id',
|
||||
},
|
||||
settlementAsset: {
|
||||
id: 'asset-0',
|
||||
symbol: 'tDAI',
|
||||
name: 'tDAI',
|
||||
decimals: 5,
|
||||
__typename: 'Asset',
|
||||
id: 'asset-id',
|
||||
name: 'asset-name',
|
||||
symbol: 'asset-symbol',
|
||||
decimals: 2,
|
||||
},
|
||||
dataSourceSpecForTradingTermination: {
|
||||
id: '',
|
||||
},
|
||||
quoteName: 'BTC',
|
||||
__typename: 'Future',
|
||||
},
|
||||
__typename: 'Instrument',
|
||||
},
|
||||
},
|
||||
data: {
|
||||
__typename: 'MarketData',
|
||||
market: {
|
||||
__typename: 'Market',
|
||||
id: 'market-id',
|
||||
},
|
||||
bestBidPrice: '100',
|
||||
bestOfferPrice: '100',
|
||||
markPrice: '200',
|
||||
trigger: Schema.AuctionTrigger.AUCTION_TRIGGER_BATCH,
|
||||
staticMidPrice: '100',
|
||||
marketTradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
|
||||
marketState: Schema.MarketState.STATE_ACTIVE,
|
||||
indicativePrice: '100',
|
||||
indicativeVolume: '10',
|
||||
bestStaticBidPrice: '100',
|
||||
bestStaticOfferPrice: '100',
|
||||
},
|
||||
marketTimestamps: {
|
||||
__typename: 'MarketTimestamps',
|
||||
open: null,
|
||||
close: null,
|
||||
},
|
||||
|
||||
fees: {
|
||||
factors: {
|
||||
makerFee: '0.001',
|
||||
@@ -70,14 +51,34 @@ export function generateMarket(
|
||||
liquidityFee: '0.003',
|
||||
},
|
||||
},
|
||||
depth: {
|
||||
__typename: 'MarketDepth',
|
||||
lastTrade: {
|
||||
__typename: 'Trade',
|
||||
price: '100',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return merge(defaultMarket, override);
|
||||
}
|
||||
|
||||
export function generateMarketData(
|
||||
override?: PartialDeep<MarketData>
|
||||
): MarketData {
|
||||
const defaultMarketData: MarketData = {
|
||||
__typename: 'MarketData',
|
||||
market: {
|
||||
id: 'market-id',
|
||||
__typename: 'Market',
|
||||
},
|
||||
auctionStart: '2022-06-21T17:18:43.484055236Z',
|
||||
auctionEnd: '2022-06-21T17:18:43.484055236Z',
|
||||
targetStake: '1000000',
|
||||
suppliedStake: '1000',
|
||||
marketTradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
|
||||
marketState: Schema.MarketState.STATE_ACTIVE,
|
||||
staticMidPrice: '0',
|
||||
indicativePrice: '100',
|
||||
bestStaticBidPrice: '0',
|
||||
bestStaticOfferPrice: '0',
|
||||
indicativeVolume: '10',
|
||||
bestBidPrice: '0',
|
||||
bestOfferPrice: '0',
|
||||
markPrice: '200',
|
||||
trigger: Schema.AuctionTrigger.AUCTION_TRIGGER_BATCH,
|
||||
};
|
||||
return merge(defaultMarketData, override);
|
||||
}
|
||||
|
||||
@@ -1,24 +1,25 @@
|
||||
import type { MarketDealTicket } from '@vegaprotocol/market-list';
|
||||
import { removeDecimal } from '@vegaprotocol/react-helpers';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { isMarketInAuction } from './is-market-in-auction';
|
||||
import type { MarketData, Market } from '@vegaprotocol/market-list';
|
||||
|
||||
/**
|
||||
* Get the market price based on market mode (auction or not auction)
|
||||
*/
|
||||
export const getMarketPrice = (market: MarketDealTicket) => {
|
||||
if (isMarketInAuction(market)) {
|
||||
export const getMarketPrice = (marketData: MarketData) => {
|
||||
const { marketTradingMode, indicativePrice, markPrice } = marketData;
|
||||
if (isMarketInAuction(marketTradingMode)) {
|
||||
// 0 can never be a valid uncrossing price
|
||||
// as it would require there being orders on the book at that price.
|
||||
if (
|
||||
market.data.indicativePrice &&
|
||||
market.data.indicativePrice !== '0' &&
|
||||
BigInt(market.data.indicativePrice) !== BigInt(0)
|
||||
indicativePrice &&
|
||||
indicativePrice !== '0' &&
|
||||
BigInt(indicativePrice) !== BigInt(0)
|
||||
) {
|
||||
return market.data.indicativePrice;
|
||||
return indicativePrice;
|
||||
}
|
||||
} else {
|
||||
return market.data.markPrice;
|
||||
return markPrice;
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
@@ -33,7 +34,8 @@ export const getDerivedPrice = (
|
||||
type: Schema.OrderType;
|
||||
price?: string | undefined;
|
||||
},
|
||||
market: MarketDealTicket
|
||||
market: Market,
|
||||
marketData: MarketData
|
||||
) => {
|
||||
// If order type is market we should use either the mark price
|
||||
// or the uncrossing price. If order type is limit use the price
|
||||
@@ -44,7 +46,7 @@ export const getDerivedPrice = (
|
||||
if (order.type === Schema.OrderType.TYPE_LIMIT && order.price) {
|
||||
price = removeDecimal(order.price, market.decimalPlaces);
|
||||
} else {
|
||||
price = getMarketPrice(market);
|
||||
price = getMarketPrice(marketData);
|
||||
}
|
||||
|
||||
return price === '0' ? undefined : price;
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
|
||||
export const isMarketInAuction = (market: {
|
||||
data: {
|
||||
marketTradingMode: Schema.MarketTradingMode;
|
||||
};
|
||||
}) => {
|
||||
export const isMarketInAuction = (
|
||||
marketTradingMode: Schema.MarketTradingMode
|
||||
) => {
|
||||
return [
|
||||
Schema.MarketTradingMode.TRADING_MODE_BATCH_AUCTION,
|
||||
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
|
||||
Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION,
|
||||
].includes(market.data.marketTradingMode);
|
||||
].includes(marketTradingMode);
|
||||
};
|
||||
|
||||
@@ -2,9 +2,9 @@ import { t } from '@vegaprotocol/react-helpers';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
|
||||
export const validateMarketTradingMode = (
|
||||
tradingMode: Schema.MarketTradingMode
|
||||
marketTradingMode: Schema.MarketTradingMode
|
||||
) => {
|
||||
if (tradingMode === Schema.MarketTradingMode.TRADING_MODE_NO_TRADING) {
|
||||
if (marketTradingMode === Schema.MarketTradingMode.TRADING_MODE_NO_TRADING) {
|
||||
return t('Trading terminated');
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { MarketModeValidationType } from '../constants';
|
||||
import { isMarketInAuction } from './is-market-in-auction';
|
||||
import type { MarketDealTicket } from '@vegaprotocol/market-list';
|
||||
|
||||
export const validateTimeInForce = (market: MarketDealTicket) => {
|
||||
export const validateTimeInForce = (
|
||||
marketTradingMode: Schema.MarketTradingMode,
|
||||
trigger: Schema.AuctionTrigger
|
||||
) => {
|
||||
return (value: Schema.OrderTimeInForce) => {
|
||||
const isMonitoringAuction =
|
||||
market.data.marketTradingMode ===
|
||||
marketTradingMode ===
|
||||
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION;
|
||||
const isPriceTrigger =
|
||||
market.data.trigger === Schema.AuctionTrigger.AUCTION_TRIGGER_PRICE;
|
||||
trigger === Schema.AuctionTrigger.AUCTION_TRIGGER_PRICE;
|
||||
const isLiquidityTrigger =
|
||||
market.data.trigger === Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY;
|
||||
trigger === Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY;
|
||||
|
||||
if (isMarketInAuction(market)) {
|
||||
if (isMarketInAuction(marketTradingMode)) {
|
||||
if (
|
||||
[
|
||||
Schema.OrderTimeInForce.TIME_IN_FORCE_FOK,
|
||||
|
||||
@@ -1,18 +1,23 @@
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { MarketModeValidationType } from '../constants';
|
||||
import { isMarketInAuction } from './is-market-in-auction';
|
||||
import type { MarketDealTicket } from '@vegaprotocol/market-list';
|
||||
|
||||
export const validateType = (market: MarketDealTicket) => {
|
||||
export const validateType = (
|
||||
marketTradingMode: Schema.MarketTradingMode,
|
||||
trigger: Schema.AuctionTrigger
|
||||
) => {
|
||||
return (value: Schema.OrderType) => {
|
||||
if (isMarketInAuction(market) && value === Schema.OrderType.TYPE_MARKET) {
|
||||
if (
|
||||
isMarketInAuction(marketTradingMode) &&
|
||||
value === Schema.OrderType.TYPE_MARKET
|
||||
) {
|
||||
const isMonitoringAuction =
|
||||
market.data.marketTradingMode ===
|
||||
marketTradingMode ===
|
||||
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION;
|
||||
const isPriceTrigger =
|
||||
market.data.trigger === Schema.AuctionTrigger.AUCTION_TRIGGER_PRICE;
|
||||
trigger === Schema.AuctionTrigger.AUCTION_TRIGGER_PRICE;
|
||||
const isLiquidityTrigger =
|
||||
market.data.trigger === Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY;
|
||||
trigger === Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY;
|
||||
|
||||
if (isMonitoringAuction && isPriceTrigger) {
|
||||
return MarketModeValidationType.PriceMonitoringAuction;
|
||||
|
||||
@@ -72,10 +72,14 @@ export const generateFill = (override?: PartialDeep<Trade>) => {
|
||||
settlementAsset: {
|
||||
__typename: 'Asset',
|
||||
id: 'assset-id',
|
||||
name: 'assset-id',
|
||||
symbol: 'SYM',
|
||||
decimals: 18,
|
||||
},
|
||||
quoteName: '',
|
||||
dataSourceSpecForTradingTermination: {
|
||||
id: '',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -9,8 +9,7 @@ import {
|
||||
|
||||
import type {
|
||||
MarketCandles,
|
||||
MarketWithCandles,
|
||||
MarketWithData,
|
||||
MarketMaybeWithDataAndCandles,
|
||||
} from '@vegaprotocol/market-list';
|
||||
|
||||
import {
|
||||
@@ -37,21 +36,20 @@ export interface FeeLevels {
|
||||
fee: string;
|
||||
}
|
||||
|
||||
export type Market = MarketWithData &
|
||||
MarketWithCandles & {
|
||||
feeLevels: FeeLevels[];
|
||||
target: string;
|
||||
dayVolume: string;
|
||||
liquidityCommitted: number;
|
||||
volumeChange: string;
|
||||
tradableInstrument?: {
|
||||
instrument?: {
|
||||
metadata?: {
|
||||
tags?: string[] | null;
|
||||
};
|
||||
export type Market = MarketMaybeWithDataAndCandles & {
|
||||
feeLevels: FeeLevels[];
|
||||
target: string;
|
||||
dayVolume: string;
|
||||
liquidityCommitted: number;
|
||||
volumeChange: string;
|
||||
tradableInstrument?: {
|
||||
instrument?: {
|
||||
metadata?: {
|
||||
tags?: string[] | null;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
export interface Markets {
|
||||
markets: Market[];
|
||||
@@ -68,7 +66,7 @@ const getData = (
|
||||
};
|
||||
|
||||
export const addData = (
|
||||
markets: (MarketWithData & MarketWithCandles)[],
|
||||
markets: MarketMaybeWithDataAndCandles[],
|
||||
marketsCandles24hAgo: MarketCandles[],
|
||||
marketsLiquidity: LiquidityProvisionMarket[]
|
||||
) => {
|
||||
@@ -104,7 +102,7 @@ export const liquidityMarketsProvider = makeDataProvider<
|
||||
getData,
|
||||
});
|
||||
|
||||
const liquidityProvisionProvider = makeDerivedDataProvider<Markets, never>(
|
||||
const liquidityProvisionProvider = makeDerivedDataProvider<Market[], never>(
|
||||
[
|
||||
marketListProvider,
|
||||
(callback, client, variables) =>
|
||||
@@ -115,12 +113,11 @@ const liquidityProvisionProvider = makeDerivedDataProvider<Markets, never>(
|
||||
liquidityMarketsProvider,
|
||||
],
|
||||
(parts) => {
|
||||
const data = addData(
|
||||
parts[0] as (MarketWithData & MarketWithCandles)[],
|
||||
return addData(
|
||||
parts[0] as MarketMaybeWithDataAndCandles[],
|
||||
parts[1] as MarketCandles[],
|
||||
parts[2] as LiquidityProvisionMarket[]
|
||||
);
|
||||
return { markets: data };
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
-98
@@ -1,98 +0,0 @@
|
||||
import * as Types from '@vegaprotocol/types';
|
||||
|
||||
import { gql } from '@apollo/client';
|
||||
import * as Apollo from '@apollo/client';
|
||||
const defaultOptions = {} as const;
|
||||
export type SingleMarketFieldsFragment = { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradingMode: Types.MarketTradingMode, fees: { __typename?: 'Fees', factors: { __typename?: 'FeeFactors', makerFee: string, infrastructureFee: string, liquidityFee: string } }, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', id: string, name: string, code: string, metadata: { __typename?: 'InstrumentMetadata', tags?: Array<string> | null }, product: { __typename?: 'Future', quoteName: string, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string }, settlementAsset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number } } } }, marketTimestamps: { __typename?: 'MarketTimestamps', open: any, close: any }, depth: { __typename?: 'MarketDepth', lastTrade?: { __typename?: 'Trade', price: string } | null } };
|
||||
|
||||
export type MarketQueryVariables = Types.Exact<{
|
||||
marketId: Types.Scalars['ID'];
|
||||
}>;
|
||||
|
||||
|
||||
export type MarketQuery = { __typename?: 'Query', market?: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradingMode: Types.MarketTradingMode, fees: { __typename?: 'Fees', factors: { __typename?: 'FeeFactors', makerFee: string, infrastructureFee: string, liquidityFee: string } }, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', id: string, name: string, code: string, metadata: { __typename?: 'InstrumentMetadata', tags?: Array<string> | null }, product: { __typename?: 'Future', quoteName: string, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string }, settlementAsset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number } } } }, marketTimestamps: { __typename?: 'MarketTimestamps', open: any, close: any }, depth: { __typename?: 'MarketDepth', lastTrade?: { __typename?: 'Trade', price: string } | null } } | null };
|
||||
|
||||
export const SingleMarketFieldsFragmentDoc = gql`
|
||||
fragment SingleMarketFields on Market {
|
||||
id
|
||||
decimalPlaces
|
||||
positionDecimalPlaces
|
||||
state
|
||||
tradingMode
|
||||
fees {
|
||||
factors {
|
||||
makerFee
|
||||
infrastructureFee
|
||||
liquidityFee
|
||||
}
|
||||
}
|
||||
tradableInstrument {
|
||||
instrument {
|
||||
id
|
||||
name
|
||||
code
|
||||
metadata {
|
||||
tags
|
||||
}
|
||||
product {
|
||||
... on Future {
|
||||
dataSourceSpecForTradingTermination {
|
||||
id
|
||||
}
|
||||
settlementAsset {
|
||||
id
|
||||
symbol
|
||||
name
|
||||
decimals
|
||||
}
|
||||
quoteName
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
marketTimestamps {
|
||||
open
|
||||
close
|
||||
}
|
||||
depth {
|
||||
lastTrade {
|
||||
price
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
export const MarketDocument = gql`
|
||||
query Market($marketId: ID!) {
|
||||
market(id: $marketId) {
|
||||
...SingleMarketFields
|
||||
}
|
||||
}
|
||||
${SingleMarketFieldsFragmentDoc}`;
|
||||
|
||||
/**
|
||||
* __useMarketQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useMarketQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useMarketQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||
* you can use to render your UI.
|
||||
*
|
||||
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||
*
|
||||
* @example
|
||||
* const { data, loading, error } = useMarketQuery({
|
||||
* variables: {
|
||||
* marketId: // value for 'marketId'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useMarketQuery(baseOptions: Apollo.QueryHookOptions<MarketQuery, MarketQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useQuery<MarketQuery, MarketQueryVariables>(MarketDocument, options);
|
||||
}
|
||||
export function useMarketLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<MarketQuery, MarketQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useLazyQuery<MarketQuery, MarketQueryVariables>(MarketDocument, options);
|
||||
}
|
||||
export type MarketQueryHookResult = ReturnType<typeof useMarketQuery>;
|
||||
export type MarketLazyQueryHookResult = ReturnType<typeof useMarketLazyQuery>;
|
||||
export type MarketQueryResult = Apollo.QueryResult<MarketQuery, MarketQueryVariables>;
|
||||
+6
-2
@@ -3,12 +3,12 @@ import * as Types from '@vegaprotocol/types';
|
||||
import { gql } from '@apollo/client';
|
||||
import * as Apollo from '@apollo/client';
|
||||
const defaultOptions = {} as const;
|
||||
export type MarketFieldsFragment = { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradingMode: Types.MarketTradingMode, fees: { __typename?: 'Fees', factors: { __typename?: 'FeeFactors', makerFee: string, infrastructureFee: string, liquidityFee: string } }, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', id: string, name: string, code: string, metadata: { __typename?: 'InstrumentMetadata', tags?: Array<string> | null }, product: { __typename?: 'Future', quoteName: string, settlementAsset: { __typename?: 'Asset', id: string, symbol: string, decimals: number } } } }, marketTimestamps: { __typename?: 'MarketTimestamps', open: any, close: any } };
|
||||
export type MarketFieldsFragment = { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradingMode: Types.MarketTradingMode, fees: { __typename?: 'Fees', factors: { __typename?: 'FeeFactors', makerFee: string, infrastructureFee: string, liquidityFee: string } }, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', id: string, name: string, code: string, metadata: { __typename?: 'InstrumentMetadata', tags?: Array<string> | null }, product: { __typename?: 'Future', quoteName: string, settlementAsset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string } } } }, marketTimestamps: { __typename?: 'MarketTimestamps', open: any, close: any } };
|
||||
|
||||
export type MarketsQueryVariables = Types.Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type MarketsQuery = { __typename?: 'Query', marketsConnection?: { __typename?: 'MarketConnection', edges: Array<{ __typename?: 'MarketEdge', node: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradingMode: Types.MarketTradingMode, fees: { __typename?: 'Fees', factors: { __typename?: 'FeeFactors', makerFee: string, infrastructureFee: string, liquidityFee: string } }, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', id: string, name: string, code: string, metadata: { __typename?: 'InstrumentMetadata', tags?: Array<string> | null }, product: { __typename?: 'Future', quoteName: string, settlementAsset: { __typename?: 'Asset', id: string, symbol: string, decimals: number } } } }, marketTimestamps: { __typename?: 'MarketTimestamps', open: any, close: any } } }> } | null };
|
||||
export type MarketsQuery = { __typename?: 'Query', marketsConnection?: { __typename?: 'MarketConnection', edges: Array<{ __typename?: 'MarketEdge', node: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradingMode: Types.MarketTradingMode, fees: { __typename?: 'Fees', factors: { __typename?: 'FeeFactors', makerFee: string, infrastructureFee: string, liquidityFee: string } }, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', id: string, name: string, code: string, metadata: { __typename?: 'InstrumentMetadata', tags?: Array<string> | null }, product: { __typename?: 'Future', quoteName: string, settlementAsset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string } } } }, marketTimestamps: { __typename?: 'MarketTimestamps', open: any, close: any } } }> } | null };
|
||||
|
||||
export const MarketFieldsFragmentDoc = gql`
|
||||
fragment MarketFields on Market {
|
||||
@@ -37,9 +37,13 @@ export const MarketFieldsFragmentDoc = gql`
|
||||
settlementAsset {
|
||||
id
|
||||
symbol
|
||||
name
|
||||
decimals
|
||||
}
|
||||
quoteName
|
||||
dataSourceSpecForTradingTermination {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ import { AgGridDynamic as AgGrid, ButtonLink } from '@vegaprotocol/ui-toolkit';
|
||||
import { AgGridColumn } from 'ag-grid-react';
|
||||
import type { AgGridReact } from 'ag-grid-react';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import type { MarketFieldsFragment, MarketWithData } from '../../';
|
||||
import type { MarketMaybeWithData, MarketFieldsFragment } from '../../';
|
||||
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
||||
|
||||
const { MarketTradingMode, AuctionTrigger } = Schema;
|
||||
@@ -24,7 +24,7 @@ export const getRowId = ({ data }: { data: { id: string } }) => data.id;
|
||||
|
||||
export const MarketListTable = forwardRef<
|
||||
AgGridReact,
|
||||
TypedDataAgGrid<MarketWithData>
|
||||
TypedDataAgGrid<MarketMaybeWithData>
|
||||
>((props, ref) => {
|
||||
const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore();
|
||||
return (
|
||||
@@ -51,7 +51,7 @@ export const MarketListTable = forwardRef<
|
||||
value,
|
||||
data,
|
||||
}: VegaICellRendererParams<
|
||||
MarketWithData,
|
||||
MarketMaybeWithData,
|
||||
'tradableInstrument.instrument.code'
|
||||
>) => {
|
||||
if (!data) return null;
|
||||
@@ -68,7 +68,7 @@ export const MarketListTable = forwardRef<
|
||||
minWidth={170}
|
||||
valueGetter={({
|
||||
data,
|
||||
}: VegaValueGetterParams<MarketWithData, 'data'>) => {
|
||||
}: VegaValueGetterParams<MarketMaybeWithData, 'data'>) => {
|
||||
if (!data?.data) return undefined;
|
||||
const { trigger } = data.data;
|
||||
const { tradingMode } = data;
|
||||
@@ -98,14 +98,17 @@ export const MarketListTable = forwardRef<
|
||||
filter="agNumberColumnFilter"
|
||||
valueGetter={({
|
||||
data,
|
||||
}: VegaValueGetterParams<MarketWithData, 'data.bestBidPrice'>) => {
|
||||
}: VegaValueGetterParams<MarketMaybeWithData, 'data.bestBidPrice'>) => {
|
||||
return data?.data?.bestBidPrice === undefined
|
||||
? undefined
|
||||
: toBigNum(data?.data?.bestBidPrice, data.decimalPlaces).toNumber();
|
||||
}}
|
||||
valueFormatter={({
|
||||
data,
|
||||
}: VegaValueFormatterParams<MarketWithData, 'data.bestBidPrice'>) =>
|
||||
}: VegaValueFormatterParams<
|
||||
MarketMaybeWithData,
|
||||
'data.bestBidPrice'
|
||||
>) =>
|
||||
data?.data?.bestBidPrice === undefined
|
||||
? undefined
|
||||
: addDecimalsFormatNumber(
|
||||
@@ -122,7 +125,10 @@ export const MarketListTable = forwardRef<
|
||||
filter="agNumberColumnFilter"
|
||||
valueGetter={({
|
||||
data,
|
||||
}: VegaValueGetterParams<MarketWithData, 'data.bestOfferPrice'>) => {
|
||||
}: VegaValueGetterParams<
|
||||
MarketMaybeWithData,
|
||||
'data.bestOfferPrice'
|
||||
>) => {
|
||||
return data?.data?.bestOfferPrice === undefined
|
||||
? undefined
|
||||
: toBigNum(
|
||||
@@ -132,7 +138,10 @@ export const MarketListTable = forwardRef<
|
||||
}}
|
||||
valueFormatter={({
|
||||
data,
|
||||
}: VegaValueFormatterParams<MarketWithData, 'data.bestOfferPrice'>) =>
|
||||
}: VegaValueFormatterParams<
|
||||
MarketMaybeWithData,
|
||||
'data.bestOfferPrice'
|
||||
>) =>
|
||||
data?.data?.bestOfferPrice === undefined
|
||||
? undefined
|
||||
: addDecimalsFormatNumber(
|
||||
@@ -149,14 +158,14 @@ export const MarketListTable = forwardRef<
|
||||
filter="agNumberColumnFilter"
|
||||
valueGetter={({
|
||||
data,
|
||||
}: VegaValueGetterParams<MarketWithData, 'data.markPrice'>) => {
|
||||
}: VegaValueGetterParams<MarketMaybeWithData, 'data.markPrice'>) => {
|
||||
return data?.data?.markPrice === undefined
|
||||
? undefined
|
||||
: toBigNum(data?.data?.markPrice, data.decimalPlaces).toNumber();
|
||||
}}
|
||||
valueFormatter={({
|
||||
data,
|
||||
}: VegaValueFormatterParams<MarketWithData, 'data.markPrice'>) =>
|
||||
}: VegaValueFormatterParams<MarketMaybeWithData, 'data.markPrice'>) =>
|
||||
data?.data?.bestOfferPrice === undefined
|
||||
? undefined
|
||||
: addDecimalsFormatNumber(data.data.markPrice, data.decimalPlaces)
|
||||
@@ -168,7 +177,7 @@ export const MarketListTable = forwardRef<
|
||||
cellRenderer={({
|
||||
value,
|
||||
}: VegaICellRendererParams<
|
||||
MarketWithData,
|
||||
MarketMaybeWithData,
|
||||
'tradableInstrument.instrument.product.settlementAsset'
|
||||
>) =>
|
||||
value ? (
|
||||
|
||||
@@ -4,13 +4,13 @@ import { MarketListTable } from './market-list-table';
|
||||
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||
import type { RowClickedEvent } from 'ag-grid-community';
|
||||
import { marketsWithDataProvider as dataProvider } from '../../markets-provider';
|
||||
import type { MarketWithData } from '../../markets-provider';
|
||||
import type { MarketMaybeWithData } from '../../markets-provider';
|
||||
interface MarketsContainerProps {
|
||||
onSelect: (marketId: string) => void;
|
||||
}
|
||||
|
||||
export const MarketsContainer = ({ onSelect }: MarketsContainerProps) => {
|
||||
const { data, error, loading } = useDataProvider<MarketWithData[], never>({
|
||||
const { data, error, loading } = useDataProvider({
|
||||
dataProvider,
|
||||
skipUpdates: true,
|
||||
});
|
||||
@@ -27,7 +27,7 @@ export const MarketsContainer = ({ onSelect }: MarketsContainerProps) => {
|
||||
) {
|
||||
return;
|
||||
}
|
||||
onSelect((data as MarketWithData).id);
|
||||
onSelect((data as MarketMaybeWithData).id);
|
||||
}}
|
||||
/>
|
||||
<div className="pointer-events-none absolute inset-0">
|
||||
|
||||
@@ -3,13 +3,11 @@ export * from './utils';
|
||||
export { marketCandlesProvider } from './market-candles-provider';
|
||||
export type { Candle } from './market-candles-provider';
|
||||
export * from './market-data-provider';
|
||||
export * from './market-provider';
|
||||
export * from './markets-candles-provider';
|
||||
export * from './markets-data-provider';
|
||||
export * from './markets-provider';
|
||||
export * from './__generated__/market-candles';
|
||||
export * from './__generated__/market-data';
|
||||
export * from './__generated__/market';
|
||||
export * from './__generated__/markets';
|
||||
export * from './__generated__/markets-candles';
|
||||
export * from './__generated__/markets-data';
|
||||
|
||||
@@ -54,6 +54,7 @@ export const marketDataProvider = makeDataProvider<
|
||||
export type StaticMarketData = Pick<
|
||||
MarketData,
|
||||
| 'marketTradingMode'
|
||||
| 'marketState'
|
||||
| 'auctionStart'
|
||||
| 'auctionEnd'
|
||||
| 'indicativePrice'
|
||||
@@ -73,6 +74,7 @@ export const staticMarketDataProvider = makeDerivedDataProvider<
|
||||
}
|
||||
const data: StaticMarketData = {
|
||||
marketTradingMode: marketData.marketTradingMode,
|
||||
marketState: marketData.marketState,
|
||||
auctionStart: marketData.auctionStart,
|
||||
auctionEnd: marketData.auctionEnd,
|
||||
indicativePrice: marketData.indicativePrice,
|
||||
@@ -91,10 +93,9 @@ export const staticMarketDataProvider = makeDerivedDataProvider<
|
||||
|
||||
export const useStaticMarketData = (marketId?: string, skip?: boolean) => {
|
||||
const variables = useMemo(() => ({ marketId }), [marketId]);
|
||||
const { data } = useDataProvider({
|
||||
return useDataProvider({
|
||||
dataProvider: staticMarketDataProvider,
|
||||
variables,
|
||||
skip: skip || !marketId,
|
||||
});
|
||||
return data;
|
||||
};
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
import {
|
||||
makeDataProvider,
|
||||
makeDerivedDataProvider,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import { MarketDocument } from './__generated__/market';
|
||||
import type {
|
||||
MarketQuery,
|
||||
SingleMarketFieldsFragment,
|
||||
} from './__generated__/market';
|
||||
import type { MarketData } from './market-data-provider';
|
||||
import { marketDataProvider } from './market-data-provider';
|
||||
|
||||
const getData = (
|
||||
responseData: MarketQuery | null
|
||||
): SingleMarketFieldsFragment | null => responseData?.market || null;
|
||||
|
||||
export const marketProvider = makeDataProvider<
|
||||
MarketQuery,
|
||||
SingleMarketFieldsFragment,
|
||||
never,
|
||||
never
|
||||
>({
|
||||
query: MarketDocument,
|
||||
getData,
|
||||
});
|
||||
|
||||
export type MarketDealTicket = SingleMarketFieldsFragment & {
|
||||
data: MarketData;
|
||||
};
|
||||
export type MarketDealTicketAsset =
|
||||
MarketDealTicket['tradableInstrument']['instrument']['product']['settlementAsset'];
|
||||
|
||||
export const marketDealTicketProvider = makeDerivedDataProvider<
|
||||
MarketDealTicket,
|
||||
never
|
||||
>([marketProvider, marketDataProvider], ([market, marketData]) => {
|
||||
return {
|
||||
...market,
|
||||
data: marketData,
|
||||
};
|
||||
});
|
||||
@@ -1,53 +0,0 @@
|
||||
fragment SingleMarketFields on Market {
|
||||
id
|
||||
decimalPlaces
|
||||
positionDecimalPlaces
|
||||
state
|
||||
tradingMode
|
||||
fees {
|
||||
factors {
|
||||
makerFee
|
||||
infrastructureFee
|
||||
liquidityFee
|
||||
}
|
||||
}
|
||||
tradableInstrument {
|
||||
instrument {
|
||||
id
|
||||
name
|
||||
code
|
||||
metadata {
|
||||
tags
|
||||
}
|
||||
product {
|
||||
... on Future {
|
||||
dataSourceSpecForTradingTermination {
|
||||
id
|
||||
}
|
||||
settlementAsset {
|
||||
id
|
||||
symbol
|
||||
name
|
||||
decimals
|
||||
}
|
||||
quoteName
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
marketTimestamps {
|
||||
open
|
||||
close
|
||||
}
|
||||
depth {
|
||||
lastTrade {
|
||||
price
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
query Market($marketId: ID!) {
|
||||
market(id: $marketId) {
|
||||
...SingleMarketFields
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
import merge from 'lodash/merge';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import type { PartialDeep } from 'type-fest';
|
||||
import type {
|
||||
MarketQuery,
|
||||
SingleMarketFieldsFragment,
|
||||
} from './__generated__/market';
|
||||
|
||||
export const marketQuery = (
|
||||
override?: PartialDeep<MarketQuery>
|
||||
): MarketQuery => {
|
||||
const defaultResult: MarketQuery = {
|
||||
__typename: 'Query',
|
||||
market: Object.assign({}, singleMarketFieldsFragment),
|
||||
};
|
||||
return merge(Object.assign({}, defaultResult), override);
|
||||
};
|
||||
|
||||
const singleMarketFieldsFragment: SingleMarketFieldsFragment = {
|
||||
__typename: 'Market',
|
||||
id: 'market-0',
|
||||
tradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
|
||||
state: Schema.MarketState.STATE_ACTIVE,
|
||||
decimalPlaces: 5,
|
||||
positionDecimalPlaces: 0,
|
||||
tradableInstrument: {
|
||||
instrument: {
|
||||
id: 'BTCUSD.MF21',
|
||||
name: 'ACTIVE MARKET',
|
||||
code: 'BTCUSD.MF21',
|
||||
metadata: {
|
||||
tags: [
|
||||
'formerly:076BB86A5AA41E3E',
|
||||
'base:BTC',
|
||||
'quote:USD',
|
||||
'class:fx/crypto',
|
||||
'monthly',
|
||||
'sector:crypto',
|
||||
],
|
||||
__typename: 'InstrumentMetadata',
|
||||
},
|
||||
product: {
|
||||
dataSourceSpecForTradingTermination: {
|
||||
id: 'd253c16c6a17ab88e098479635c611ab503582a1079752d1a49ac15f656f7e7b',
|
||||
__typename: 'DataSourceSpec',
|
||||
},
|
||||
quoteName: 'BTC',
|
||||
settlementAsset: {
|
||||
decimals: 5,
|
||||
id: '5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c',
|
||||
symbol: 'tBTC',
|
||||
name: 'tBTC TEST',
|
||||
__typename: 'Asset',
|
||||
},
|
||||
__typename: 'Future',
|
||||
},
|
||||
__typename: 'Instrument',
|
||||
},
|
||||
__typename: 'TradableInstrument',
|
||||
},
|
||||
marketTimestamps: {
|
||||
open: '2022-06-21T17:18:43.484055236Z',
|
||||
close: null,
|
||||
__typename: 'MarketTimestamps',
|
||||
},
|
||||
fees: {
|
||||
__typename: 'Fees',
|
||||
factors: {
|
||||
__typename: 'FeeFactors',
|
||||
makerFee: '0.0002',
|
||||
infrastructureFee: '0.0005',
|
||||
liquidityFee: '0.0005',
|
||||
},
|
||||
},
|
||||
depth: {
|
||||
__typename: 'MarketDepth',
|
||||
lastTrade: { price: '100', __typename: 'Trade' },
|
||||
},
|
||||
};
|
||||
@@ -1,4 +1,7 @@
|
||||
import { makeDataProvider } from '@vegaprotocol/react-helpers';
|
||||
import {
|
||||
makeDataProvider,
|
||||
marketDataErrorPolicyGuard,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import type { MarketsDataQuery } from './__generated__/markets-data';
|
||||
import { MarketsDataDocument } from './__generated__/markets-data';
|
||||
import type { MarketData } from './market-data-provider';
|
||||
@@ -16,4 +19,5 @@ export const marketsDataProvider = makeDataProvider<
|
||||
>({
|
||||
query: MarketsDataDocument,
|
||||
getData,
|
||||
errorPolicyGuard: marketDataErrorPolicyGuard,
|
||||
});
|
||||
|
||||
@@ -9,6 +9,7 @@ import type {
|
||||
MarketFieldsFragment,
|
||||
} from './__generated__/markets';
|
||||
import { marketsDataProvider } from './markets-data-provider';
|
||||
import { marketDataProvider } from './market-data-provider';
|
||||
import { marketsCandlesProvider } from './markets-candles-provider';
|
||||
import type { MarketData } from './market-data-provider';
|
||||
import type { MarketCandles } from './markets-candles-provider';
|
||||
@@ -35,7 +36,7 @@ export const marketsProvider = makeDataProvider<
|
||||
fetchPolicy: 'cache-first',
|
||||
});
|
||||
|
||||
const marketProvider = makeDerivedDataProvider<
|
||||
export const marketProvider = makeDerivedDataProvider<
|
||||
Market,
|
||||
never,
|
||||
{ marketId: string }
|
||||
@@ -49,20 +50,31 @@ const marketProvider = makeDerivedDataProvider<
|
||||
|
||||
export const useMarket = (marketId?: string) => {
|
||||
const variables = useMemo(() => ({ marketId: marketId || '' }), [marketId]);
|
||||
const { data } = useDataProvider({
|
||||
return useDataProvider({
|
||||
dataProvider: marketProvider,
|
||||
variables,
|
||||
skip: !marketId,
|
||||
});
|
||||
return data;
|
||||
};
|
||||
export type MarketWithData = Market & { data: MarketData };
|
||||
|
||||
export const marketWithDataProvider = makeDerivedDataProvider<
|
||||
MarketWithData,
|
||||
never,
|
||||
{ marketId: string }
|
||||
>([marketProvider, marketDataProvider], ([market, marketData]) => {
|
||||
return {
|
||||
...market,
|
||||
data: marketData,
|
||||
};
|
||||
});
|
||||
|
||||
export const activeMarketsProvider = makeDerivedDataProvider<Market[], never>(
|
||||
[marketsProvider],
|
||||
([markets]) => filterAndSortMarkets(markets)
|
||||
);
|
||||
|
||||
export type MarketWithCandles = Market & { candles?: Candle[] };
|
||||
export type MarketMaybeWithCandles = Market & { candles?: Candle[] };
|
||||
|
||||
const addCandles = <T extends Market>(
|
||||
markets: T[],
|
||||
@@ -75,7 +87,7 @@ const addCandles = <T extends Market>(
|
||||
}));
|
||||
|
||||
export const marketsWithCandlesProvider = makeDerivedDataProvider<
|
||||
MarketWithCandles[],
|
||||
MarketMaybeWithCandles[],
|
||||
never
|
||||
>(
|
||||
[
|
||||
@@ -85,7 +97,7 @@ export const marketsWithCandlesProvider = makeDerivedDataProvider<
|
||||
(parts) => addCandles(parts[0] as Market[], parts[1] as MarketCandles[])
|
||||
);
|
||||
|
||||
export type MarketWithData = Market & { data?: MarketData };
|
||||
export type MarketMaybeWithData = Market & { data?: MarketData };
|
||||
|
||||
const addData = <T extends Market>(markets: T[], marketsData: MarketData[]) =>
|
||||
markets.map((market) => ({
|
||||
@@ -94,14 +106,17 @@ const addData = <T extends Market>(markets: T[], marketsData: MarketData[]) =>
|
||||
}));
|
||||
|
||||
export const marketsWithDataProvider = makeDerivedDataProvider<
|
||||
MarketWithData[],
|
||||
MarketMaybeWithData[],
|
||||
never
|
||||
>([activeMarketsProvider, marketsDataProvider], (parts) =>
|
||||
addData(parts[0] as Market[], parts[1] as MarketData[])
|
||||
);
|
||||
|
||||
export type MarketMaybeWithDataAndCandles = MarketMaybeWithData &
|
||||
MarketMaybeWithCandles;
|
||||
|
||||
export const marketListProvider = makeDerivedDataProvider<
|
||||
(MarketWithData & MarketWithCandles)[],
|
||||
MarketMaybeWithDataAndCandles[],
|
||||
never
|
||||
>(
|
||||
[
|
||||
@@ -109,7 +124,7 @@ export const marketListProvider = makeDerivedDataProvider<
|
||||
marketsCandlesProvider,
|
||||
],
|
||||
(parts) =>
|
||||
addCandles(parts[0] as MarketWithCandles[], parts[1] as MarketCandles[])
|
||||
addCandles(parts[0] as MarketMaybeWithData[], parts[1] as MarketCandles[])
|
||||
);
|
||||
|
||||
export const useMarketList = () => {
|
||||
|
||||
@@ -24,9 +24,13 @@ fragment MarketFields on Market {
|
||||
settlementAsset {
|
||||
id
|
||||
symbol
|
||||
name
|
||||
decimals
|
||||
}
|
||||
quoteName
|
||||
dataSourceSpecForTradingTermination {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,8 +31,8 @@ const marketFieldsFragments: MarketFieldsFragment[] = [
|
||||
state: Schema.MarketState.STATE_ACTIVE,
|
||||
marketTimestamps: {
|
||||
__typename: 'MarketTimestamps',
|
||||
close: '',
|
||||
open: '',
|
||||
close: null,
|
||||
open: null,
|
||||
},
|
||||
fees: {
|
||||
__typename: 'Fees',
|
||||
@@ -56,9 +56,13 @@ const marketFieldsFragments: MarketFieldsFragment[] = [
|
||||
settlementAsset: {
|
||||
id: 'asset-0',
|
||||
symbol: 'tDAI',
|
||||
name: 'tDAI',
|
||||
decimals: 5,
|
||||
__typename: 'Asset',
|
||||
},
|
||||
dataSourceSpecForTradingTermination: {
|
||||
id: 'oracleId',
|
||||
},
|
||||
quoteName: 'DAI',
|
||||
__typename: 'Future',
|
||||
},
|
||||
@@ -101,9 +105,13 @@ const marketFieldsFragments: MarketFieldsFragment[] = [
|
||||
settlementAsset: {
|
||||
id: 'asset-1',
|
||||
symbol: 'XYZalpha',
|
||||
name: 'XYZalpha',
|
||||
decimals: 5,
|
||||
__typename: 'Asset',
|
||||
},
|
||||
dataSourceSpecForTradingTermination: {
|
||||
id: 'oracleId',
|
||||
},
|
||||
quoteName: 'USD',
|
||||
__typename: 'Future',
|
||||
},
|
||||
@@ -145,10 +153,14 @@ const marketFieldsFragments: MarketFieldsFragment[] = [
|
||||
product: {
|
||||
settlementAsset: {
|
||||
id: 'asset-2',
|
||||
name: '',
|
||||
symbol: 'tUSDC',
|
||||
decimals: 5,
|
||||
__typename: 'Asset',
|
||||
},
|
||||
dataSourceSpecForTradingTermination: {
|
||||
id: 'oracleId',
|
||||
},
|
||||
quoteName: 'USDC',
|
||||
__typename: 'Future',
|
||||
},
|
||||
@@ -191,9 +203,13 @@ const marketFieldsFragments: MarketFieldsFragment[] = [
|
||||
settlementAsset: {
|
||||
id: 'asset-3',
|
||||
symbol: 'tBTC',
|
||||
name: '',
|
||||
decimals: 5,
|
||||
__typename: 'Asset',
|
||||
},
|
||||
dataSourceSpecForTradingTermination: {
|
||||
id: 'oracleId',
|
||||
},
|
||||
quoteName: 'BTC',
|
||||
__typename: 'Future',
|
||||
},
|
||||
|
||||
@@ -46,6 +46,10 @@ export const generateOrder = (partialOrder?: PartialDeep<Order>) => {
|
||||
id: 'asset-id',
|
||||
decimals: 1,
|
||||
symbol: 'XYZ',
|
||||
name: 'XYZ',
|
||||
},
|
||||
dataSourceSpecForTradingTermination: {
|
||||
id: '',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -10,31 +10,7 @@ import { OrderSubDocument } from './';
|
||||
import type { MockedResponse } from '@apollo/client/testing';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
|
||||
const defaultMarket = {
|
||||
__typename: 'Market',
|
||||
id: 'market-id',
|
||||
decimalPlaces: 2,
|
||||
positionDecimalPlaces: 1,
|
||||
tradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
|
||||
state: Schema.MarketState.STATE_ACTIVE,
|
||||
tradableInstrument: {
|
||||
__typename: 'TradableInstrument',
|
||||
instrument: {
|
||||
__typename: 'Instrument',
|
||||
product: {
|
||||
__typename: 'Future',
|
||||
quoteName: 'quote-name',
|
||||
},
|
||||
},
|
||||
},
|
||||
depth: {
|
||||
__typename: 'MarketDepth',
|
||||
lastTrade: {
|
||||
__typename: 'Trade',
|
||||
price: '100',
|
||||
},
|
||||
},
|
||||
};
|
||||
const marketId = 'market-id';
|
||||
|
||||
const defaultWalletContext = {
|
||||
pubKey: null,
|
||||
@@ -135,13 +111,13 @@ describe('useOrderSubmit', () => {
|
||||
expiresAt: new Date('2022-01-01').toISOString(),
|
||||
};
|
||||
await act(async () => {
|
||||
result.current.submit({ ...order, marketId: defaultMarket.id });
|
||||
result.current.submit({ ...order, marketId });
|
||||
});
|
||||
|
||||
expect(mockSendTx).toHaveBeenCalledWith(pubKey, {
|
||||
orderSubmission: {
|
||||
type: Schema.OrderType.TYPE_LIMIT,
|
||||
marketId: defaultMarket.id,
|
||||
marketId,
|
||||
size: '10',
|
||||
side: Schema.Side.SIDE_BUY,
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTT,
|
||||
@@ -172,13 +148,13 @@ describe('useOrderSubmit', () => {
|
||||
expiresAt: new Date('2022-01-01').toISOString(),
|
||||
};
|
||||
await act(async () => {
|
||||
result.current.submit({ ...order, marketId: defaultMarket.id });
|
||||
result.current.submit({ ...order, marketId });
|
||||
});
|
||||
|
||||
expect(mockSendTx).toHaveBeenCalledWith(publicKeyObj.publicKey, {
|
||||
orderSubmission: {
|
||||
type: Schema.OrderType.TYPE_LIMIT,
|
||||
marketId: defaultMarket.id,
|
||||
marketId,
|
||||
size: '10',
|
||||
side: Schema.Side.SIDE_BUY,
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
import type {
|
||||
MarketDataFieldsFragment,
|
||||
SingleMarketFieldsFragment,
|
||||
} from '@vegaprotocol/market-list';
|
||||
import type { MarketData, Market } from '@vegaprotocol/market-list';
|
||||
import type { Order } from '@vegaprotocol/orders';
|
||||
import { timeInForceLabel } from '@vegaprotocol/orders';
|
||||
import { addDecimalsFormatNumber, Size, t } from '@vegaprotocol/react-helpers';
|
||||
@@ -14,8 +11,8 @@ export const ClosingOrder = ({
|
||||
marketData,
|
||||
}: {
|
||||
order: IClosingOrder;
|
||||
market: SingleMarketFieldsFragment;
|
||||
marketData: MarketDataFieldsFragment;
|
||||
market: Market;
|
||||
marketData: MarketData;
|
||||
}) => {
|
||||
const asset = market.tradableInstrument.instrument.product.settlementAsset;
|
||||
const estimatedPrice =
|
||||
@@ -50,7 +47,7 @@ export const ActiveOrders = ({
|
||||
market,
|
||||
orders,
|
||||
}: {
|
||||
market: SingleMarketFieldsFragment;
|
||||
market: Market;
|
||||
orders: Order[];
|
||||
}) => {
|
||||
const asset = market.tradableInstrument.instrument.product.settlementAsset;
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
removePaginationWrapper,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import type { MarketWithData } from '@vegaprotocol/market-list';
|
||||
import type { MarketMaybeWithData } from '@vegaprotocol/market-list';
|
||||
import { marketsWithDataProvider } from '@vegaprotocol/market-list';
|
||||
import type {
|
||||
PositionsQuery,
|
||||
@@ -36,7 +36,7 @@ interface PositionRejoined {
|
||||
unrealisedPNL: string;
|
||||
averageEntryPrice: string;
|
||||
updatedAt?: string | null;
|
||||
market: MarketWithData | null;
|
||||
market: MarketMaybeWithData | null;
|
||||
margins: PositionMarginLevel | null;
|
||||
}
|
||||
|
||||
@@ -45,22 +45,22 @@ export interface Position {
|
||||
averageEntryPrice: string;
|
||||
marginAccountBalance: string;
|
||||
capitalUtilisation: number;
|
||||
currentLeverage: number;
|
||||
currentLeverage: number | undefined;
|
||||
decimals: number;
|
||||
marketDecimalPlaces: number;
|
||||
positionDecimalPlaces: number;
|
||||
totalBalance: string;
|
||||
assetSymbol: string;
|
||||
liquidationPrice: string;
|
||||
liquidationPrice: string | undefined;
|
||||
lowMarginLevel: boolean;
|
||||
marketId: string;
|
||||
marketTradingMode: Schema.MarketTradingMode;
|
||||
markPrice: string;
|
||||
notional: string;
|
||||
markPrice: string | undefined;
|
||||
notional: string | undefined;
|
||||
openVolume: string;
|
||||
realisedPNL: string;
|
||||
unrealisedPNL: string;
|
||||
searchPrice: string;
|
||||
searchPrice: string | undefined;
|
||||
updatedAt: string | null;
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ export const getMetrics = (
|
||||
const marginAccount = accounts?.find((account) => {
|
||||
return account.market?.id === market?.id;
|
||||
});
|
||||
if (!marginAccount || !marginLevel || !market || !marketData) {
|
||||
if (!marginAccount || !marginLevel || !market) {
|
||||
return;
|
||||
}
|
||||
const generalAccount = accounts?.find(
|
||||
@@ -102,15 +102,22 @@ export const getMetrics = (
|
||||
generalAccount?.balance ?? 0,
|
||||
decimals
|
||||
);
|
||||
const markPrice = toBigNum(marketData.markPrice, marketDecimalPlaces);
|
||||
|
||||
const notional = (
|
||||
openVolume.isGreaterThan(0) ? openVolume : openVolume.multipliedBy(-1)
|
||||
).multipliedBy(markPrice);
|
||||
const markPrice = marketData
|
||||
? toBigNum(marketData.markPrice, marketDecimalPlaces)
|
||||
: undefined;
|
||||
const notional = markPrice
|
||||
? (openVolume.isGreaterThan(0)
|
||||
? openVolume
|
||||
: openVolume.multipliedBy(-1)
|
||||
).multipliedBy(markPrice)
|
||||
: undefined;
|
||||
const totalBalance = marginAccountBalance.plus(generalAccountBalance);
|
||||
const currentLeverage = totalBalance.isEqualTo(0)
|
||||
? new BigNumber(0)
|
||||
: notional.dividedBy(totalBalance);
|
||||
const currentLeverage = notional
|
||||
? totalBalance.isEqualTo(0)
|
||||
? new BigNumber(0)
|
||||
: notional.dividedBy(totalBalance)
|
||||
: undefined;
|
||||
const capitalUtilisation = totalBalance.isEqualTo(0)
|
||||
? new BigNumber(0)
|
||||
: marginAccountBalance.dividedBy(totalBalance).multipliedBy(100);
|
||||
@@ -119,19 +126,23 @@ export const getMetrics = (
|
||||
const marginSearch = toBigNum(marginLevel.searchLevel, decimals);
|
||||
const marginInitial = toBigNum(marginLevel.initialLevel, decimals);
|
||||
|
||||
const searchPrice = marginSearch
|
||||
.minus(marginAccountBalance)
|
||||
.dividedBy(openVolume)
|
||||
.plus(markPrice);
|
||||
const searchPrice = markPrice
|
||||
? marginSearch
|
||||
.minus(marginAccountBalance)
|
||||
.dividedBy(openVolume)
|
||||
.plus(markPrice)
|
||||
: undefined;
|
||||
|
||||
const liquidationPrice = BigNumber.maximum(
|
||||
0,
|
||||
marginMaintenance
|
||||
.minus(marginAccountBalance)
|
||||
.minus(generalAccountBalance)
|
||||
.dividedBy(openVolume)
|
||||
.plus(markPrice)
|
||||
);
|
||||
const liquidationPrice = markPrice
|
||||
? BigNumber.maximum(
|
||||
0,
|
||||
marginMaintenance
|
||||
.minus(marginAccountBalance)
|
||||
.minus(generalAccountBalance)
|
||||
.dividedBy(openVolume)
|
||||
.plus(markPrice)
|
||||
)
|
||||
: undefined;
|
||||
|
||||
const lowMarginLevel =
|
||||
marginAccountBalance.isLessThan(
|
||||
@@ -143,7 +154,7 @@ export const getMetrics = (
|
||||
averageEntryPrice: position.averageEntryPrice,
|
||||
marginAccountBalance: marginAccount.balance,
|
||||
capitalUtilisation: Math.round(capitalUtilisation.toNumber()),
|
||||
currentLeverage: currentLeverage.toNumber(),
|
||||
currentLeverage: currentLeverage ? currentLeverage.toNumber() : undefined,
|
||||
marketDecimalPlaces,
|
||||
positionDecimalPlaces,
|
||||
decimals,
|
||||
@@ -152,18 +163,20 @@ export const getMetrics = (
|
||||
totalBalance: totalBalance.multipliedBy(10 ** decimals).toFixed(),
|
||||
lowMarginLevel,
|
||||
liquidationPrice: liquidationPrice
|
||||
.multipliedBy(10 ** marketDecimalPlaces)
|
||||
.toFixed(0),
|
||||
? liquidationPrice.multipliedBy(10 ** marketDecimalPlaces).toFixed(0)
|
||||
: undefined,
|
||||
marketId: market.id,
|
||||
marketTradingMode: market.tradingMode,
|
||||
markPrice: marketData.markPrice,
|
||||
notional: notional.multipliedBy(10 ** marketDecimalPlaces).toFixed(0),
|
||||
markPrice: marketData ? marketData.markPrice : undefined,
|
||||
notional: notional
|
||||
? notional.multipliedBy(10 ** marketDecimalPlaces).toFixed(0)
|
||||
: undefined,
|
||||
openVolume: position.openVolume,
|
||||
realisedPNL: position.realisedPNL,
|
||||
unrealisedPNL: position.unrealisedPNL,
|
||||
searchPrice: searchPrice
|
||||
.multipliedBy(10 ** marketDecimalPlaces)
|
||||
.toFixed(0),
|
||||
? searchPrice.multipliedBy(10 ** marketDecimalPlaces).toFixed(0)
|
||||
: undefined,
|
||||
updatedAt: position.updatedAt || null,
|
||||
});
|
||||
});
|
||||
@@ -240,7 +253,7 @@ const upgradeMarginsConnection = (
|
||||
|
||||
export const rejoinPositionData = (
|
||||
positions: PositionFieldsFragment[] | null,
|
||||
marketsData: MarketWithData[] | null,
|
||||
marketsData: MarketMaybeWithData[] | null,
|
||||
margins: MarginFieldsFragment[] | null
|
||||
): PositionRejoined[] | null => {
|
||||
if (positions && marketsData && margins) {
|
||||
|
||||
@@ -49,7 +49,7 @@ export const AmountCell = ({ valueFormatted }: AmountCellProps) => {
|
||||
}
|
||||
const { openVolume, positionDecimalPlaces, marketDecimalPlaces, notional } =
|
||||
valueFormatted;
|
||||
return valueFormatted ? (
|
||||
return valueFormatted && notional ? (
|
||||
<div className="leading-tight font-mono">
|
||||
<div
|
||||
className={classNames('text-right', signedNumberCssClass(openVolume))}
|
||||
@@ -115,15 +115,15 @@ export const PositionsTable = forwardRef<AgGridReact, Props>(
|
||||
valueGetter={({
|
||||
data,
|
||||
}: VegaValueGetterParams<Position, 'notional'>) => {
|
||||
return data?.notional === undefined
|
||||
return !data?.notional
|
||||
? undefined
|
||||
: toBigNum(data?.notional, data.marketDecimalPlaces).toNumber();
|
||||
: toBigNum(data.notional, data.marketDecimalPlaces).toNumber();
|
||||
}}
|
||||
valueFormatter={({
|
||||
data,
|
||||
}: VegaValueFormatterParams<Position, 'notional'>) => {
|
||||
return !data
|
||||
? undefined
|
||||
return !data || !data.notional
|
||||
? '-'
|
||||
: addDecimalsFormatNumber(
|
||||
data.notional,
|
||||
data.marketDecimalPlaces
|
||||
@@ -173,6 +173,7 @@ export const PositionsTable = forwardRef<AgGridReact, Props>(
|
||||
data,
|
||||
}: VegaValueGetterParams<Position, 'markPrice'>) => {
|
||||
return !data ||
|
||||
!data.markPrice ||
|
||||
data.marketTradingMode ===
|
||||
Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION
|
||||
? undefined
|
||||
@@ -180,14 +181,14 @@ export const PositionsTable = forwardRef<AgGridReact, Props>(
|
||||
}}
|
||||
valueFormatter={({
|
||||
data,
|
||||
node,
|
||||
}: VegaValueFormatterParams<Position, 'markPrice'>) => {
|
||||
if (!data) {
|
||||
return undefined;
|
||||
}
|
||||
if (
|
||||
!data.markPrice ||
|
||||
data.marketTradingMode ===
|
||||
Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION
|
||||
Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION
|
||||
) {
|
||||
return '-';
|
||||
}
|
||||
@@ -220,7 +221,6 @@ export const PositionsTable = forwardRef<AgGridReact, Props>(
|
||||
}}
|
||||
valueFormatter={({
|
||||
data,
|
||||
node,
|
||||
}: VegaValueFormatterParams<Position, 'averageEntryPrice'>):
|
||||
| string
|
||||
| undefined => {
|
||||
@@ -258,7 +258,7 @@ export const PositionsTable = forwardRef<AgGridReact, Props>(
|
||||
}: VegaValueFormatterParams<Position, 'liquidationPrice'>):
|
||||
| string
|
||||
| undefined => {
|
||||
if (!data) {
|
||||
if (!data || data?.liquidationPrice === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
return addDecimalsFormatNumber(
|
||||
|
||||
@@ -8,7 +8,10 @@ export const useRequestClosePositionData = (
|
||||
marketId?: string,
|
||||
partyId?: string
|
||||
) => {
|
||||
const marketVariables = useMemo(() => ({ marketId }), [marketId]);
|
||||
const marketVariables = useMemo(
|
||||
() => ({ marketId: marketId || '' }),
|
||||
[marketId]
|
||||
);
|
||||
const orderVariables = useMemo<OrdersQueryVariables>(
|
||||
() => ({ partyId: partyId || '' }),
|
||||
[partyId]
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { ApolloError } from '@apollo/client';
|
||||
import type { GraphQLErrors } from '@apollo/client/errors';
|
||||
|
||||
const NOT_FOUND = 'NotFound';
|
||||
const INTERNAL = 'Internal';
|
||||
|
||||
const isApolloGraphQLError = (
|
||||
error: ApolloError | Error | undefined
|
||||
@@ -9,21 +10,31 @@ const isApolloGraphQLError = (
|
||||
return !!error && !!(error as ApolloError).graphQLErrors;
|
||||
};
|
||||
|
||||
const hasNotFoundGraphQLErrors = (errors: GraphQLErrors, path?: string) => {
|
||||
const hasNotFoundGraphQLErrors = (errors: GraphQLErrors, path?: string[]) => {
|
||||
return errors.some(
|
||||
(e) =>
|
||||
e.extensions &&
|
||||
e.extensions['type'] === NOT_FOUND &&
|
||||
(!path || e.path?.[0] === path)
|
||||
(!path || path.every((item, i) => item === e?.path?.[i]))
|
||||
);
|
||||
};
|
||||
|
||||
export const isNotFoundGraphQLError = (
|
||||
error: Error | ApolloError | undefined,
|
||||
path?: string
|
||||
path?: string[]
|
||||
) => {
|
||||
return (
|
||||
isApolloGraphQLError(error) &&
|
||||
hasNotFoundGraphQLErrors(error.graphQLErrors, path)
|
||||
);
|
||||
};
|
||||
|
||||
export const marketDataErrorPolicyGuard = (errors: GraphQLErrors) => {
|
||||
const path = ['market', 'data'];
|
||||
return errors.every(
|
||||
(e) =>
|
||||
e.extensions &&
|
||||
e.extensions['type'] === INTERNAL &&
|
||||
(!path || path.every((item, i) => item === e?.path?.[i]))
|
||||
);
|
||||
};
|
||||
|
||||
@@ -20,7 +20,11 @@ import type {
|
||||
ApolloQueryResult,
|
||||
QueryOptions,
|
||||
} from '@apollo/client';
|
||||
import { ApolloError } from '@apollo/client';
|
||||
import type { GraphQLErrors } from '@apollo/client/errors';
|
||||
import { GraphQLError } from 'graphql';
|
||||
import type { Subscription, Observable } from 'zen-observable-ts';
|
||||
import { waitFor } from '@testing-library/react';
|
||||
|
||||
type Item = {
|
||||
cursor: string;
|
||||
@@ -58,12 +62,16 @@ const query: Query<QueryData> = {
|
||||
};
|
||||
const subscriptionQuery: Query<SubscriptionData> = query;
|
||||
|
||||
const getData = jest.fn((r: QueryData | null) => r?.data || null);
|
||||
|
||||
const getDelta = jest.fn((r: SubscriptionData) => r.data);
|
||||
|
||||
const subscribe = makeDataProvider<QueryData, Data, SubscriptionData, Delta>({
|
||||
query,
|
||||
subscriptionQuery,
|
||||
update,
|
||||
getData: (r) => r?.data || null,
|
||||
getDelta: (r) => r.data,
|
||||
getData,
|
||||
getDelta,
|
||||
});
|
||||
|
||||
const combineData = jest.fn<
|
||||
@@ -91,8 +99,8 @@ const paginatedSubscribe = makeDataProvider<
|
||||
query,
|
||||
subscriptionQuery,
|
||||
update,
|
||||
getData: (r) => r?.data || null,
|
||||
getDelta: (r) => r.data,
|
||||
getData,
|
||||
getDelta,
|
||||
pagination: {
|
||||
first,
|
||||
append: defaultAppend,
|
||||
@@ -101,6 +109,23 @@ const paginatedSubscribe = makeDataProvider<
|
||||
},
|
||||
});
|
||||
|
||||
const mockErrorPolicyGuard: (errors: GraphQLErrors) => boolean = jest
|
||||
.fn()
|
||||
.mockImplementation(() => true);
|
||||
const errorGuardedSubscribe = makeDataProvider<
|
||||
QueryData,
|
||||
Data,
|
||||
SubscriptionData,
|
||||
Delta
|
||||
>({
|
||||
query,
|
||||
subscriptionQuery,
|
||||
update,
|
||||
getData,
|
||||
getDelta,
|
||||
errorPolicyGuard: mockErrorPolicyGuard,
|
||||
});
|
||||
|
||||
const derivedSubscribe = makeDerivedDataProvider(
|
||||
[paginatedSubscribe, subscribe],
|
||||
combineData,
|
||||
@@ -186,9 +211,20 @@ const clearPendingQueries = () => {
|
||||
};
|
||||
|
||||
describe('data provider', () => {
|
||||
beforeEach(() => {
|
||||
clearPendingQueries();
|
||||
callback.mockClear();
|
||||
getData.mockClear();
|
||||
clientQuery.mockClear();
|
||||
clientSubscribeUnsubscribe.mockClear();
|
||||
clientSubscribeSubscribe.mockClear();
|
||||
});
|
||||
it('memoize instance and unsubscribe if no subscribers', () => {
|
||||
const subscription1 = subscribe(jest.fn(), client);
|
||||
const subscription2 = subscribe(jest.fn(), client);
|
||||
const variables = { var: 'val' };
|
||||
const subscription1 = subscribe(jest.fn(), client, variables);
|
||||
const subscription2 = subscribe(jest.fn(), client, { ...variables });
|
||||
// const subscription1 = subscribe(jest.fn(), client);
|
||||
// const subscription2 = subscribe(jest.fn(), client);
|
||||
expect(clientSubscribeSubscribe.mock.calls.length).toEqual(1);
|
||||
subscription1.unsubscribe();
|
||||
expect(clientSubscribeUnsubscribe.mock.calls.length).toEqual(0);
|
||||
@@ -197,7 +233,6 @@ describe('data provider', () => {
|
||||
});
|
||||
|
||||
it('calls callback before and after initial fetch', async () => {
|
||||
callback.mockClear();
|
||||
const data: Item[] = [];
|
||||
const subscription = subscribe(callback, client);
|
||||
expect(callback.mock.calls.length).toBe(1);
|
||||
@@ -210,6 +245,49 @@ describe('data provider', () => {
|
||||
subscription.unsubscribe();
|
||||
});
|
||||
|
||||
it('calls callback on error', async () => {
|
||||
const subscription = subscribe(callback, client);
|
||||
expect(callback.mock.calls.length).toBe(1);
|
||||
expect(callback.mock.calls[0][0].data).toBe(null);
|
||||
expect(callback.mock.calls[0][0].loading).toBe(true);
|
||||
const error = new Error('Rejected by unit test');
|
||||
await rejectQuery(error);
|
||||
expect(getData).not.toBeCalled();
|
||||
expect(callback.mock.calls.length).toBe(2);
|
||||
expect(callback.mock.calls[1][0].error).toEqual(error);
|
||||
expect(callback.mock.calls[1][0].loading).toBe(false);
|
||||
subscription.unsubscribe();
|
||||
});
|
||||
|
||||
it('calls successful callback on NotFound error on party path', async () => {
|
||||
const subscription = subscribe(callback, client);
|
||||
expect(callback.mock.calls.length).toBe(1);
|
||||
expect(callback.mock.calls[0][0].data).toBe(null);
|
||||
expect(callback.mock.calls[0][0].loading).toBe(true);
|
||||
const error = new Error() as ApolloError;
|
||||
const graphQLError = new GraphQLError(
|
||||
'',
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
['party'],
|
||||
undefined,
|
||||
{
|
||||
type: 'NotFound',
|
||||
}
|
||||
);
|
||||
error.graphQLErrors = [graphQLError];
|
||||
const data: Data = [];
|
||||
getData.mockReturnValueOnce(data);
|
||||
await rejectQuery(error);
|
||||
expect(getData).toHaveBeenCalledWith(null, undefined);
|
||||
expect(callback.mock.calls.length).toBe(2);
|
||||
expect(callback.mock.calls[1][0].data).toEqual(data);
|
||||
expect(callback.mock.calls[1][0].error).toEqual(undefined);
|
||||
expect(callback.mock.calls[1][0].loading).toBe(false);
|
||||
subscription.unsubscribe();
|
||||
});
|
||||
|
||||
it('calls update and callback on each update', async () => {
|
||||
const data: Item[] = [];
|
||||
const subscription = subscribe(callback, client);
|
||||
@@ -228,8 +306,7 @@ describe('data provider', () => {
|
||||
subscription.unsubscribe();
|
||||
});
|
||||
|
||||
it("don't calls callback on update if data doesn't", async () => {
|
||||
callback.mockClear();
|
||||
it("don't calls callback on update if data doesn't change", async () => {
|
||||
const data: Item[] = [];
|
||||
const subscription = subscribe(callback, client);
|
||||
await resolveQuery({ data });
|
||||
@@ -247,10 +324,6 @@ describe('data provider', () => {
|
||||
});
|
||||
|
||||
it('refetch data on reload', async () => {
|
||||
clearPendingQueries();
|
||||
clientQuery.mockClear();
|
||||
clientSubscribeUnsubscribe.mockClear();
|
||||
clientSubscribeSubscribe.mockClear();
|
||||
const data: Item[] = [];
|
||||
const subscription = subscribe(callback, client);
|
||||
await resolveQuery({ data });
|
||||
@@ -263,9 +336,6 @@ describe('data provider', () => {
|
||||
});
|
||||
|
||||
it('refetch data and restart subscription on reload with force', async () => {
|
||||
clientQuery.mockClear();
|
||||
clientSubscribeUnsubscribe.mockClear();
|
||||
clientSubscribeSubscribe.mockClear();
|
||||
const data: Item[] = [];
|
||||
const subscription = subscribe(callback, client);
|
||||
await resolveQuery({ data });
|
||||
@@ -278,7 +348,6 @@ describe('data provider', () => {
|
||||
});
|
||||
|
||||
it('calls callback on flush', async () => {
|
||||
callback.mockClear();
|
||||
const data: Item[] = [];
|
||||
const subscription = subscribe(callback, client);
|
||||
await resolveQuery({ data });
|
||||
@@ -289,8 +358,6 @@ describe('data provider', () => {
|
||||
});
|
||||
|
||||
it('fills data with nulls if pagination is enabled', async () => {
|
||||
callback.mockClear();
|
||||
clearPendingQueries();
|
||||
const totalCount = 1000;
|
||||
const data: Item[] = new Array(first).fill(null).map((v, i) => ({
|
||||
cursor: i.toString(),
|
||||
@@ -311,7 +378,6 @@ describe('data provider', () => {
|
||||
});
|
||||
|
||||
it('loads requested data blocks and inserts data with total count', async () => {
|
||||
callback.mockClear();
|
||||
const totalCount = 1000;
|
||||
const subscription = paginatedSubscribe(callback, client);
|
||||
await resolveQuery({
|
||||
@@ -436,7 +502,6 @@ describe('data provider', () => {
|
||||
});
|
||||
|
||||
it('loads requested data blocks and inserts data without totalCount', async () => {
|
||||
callback.mockClear();
|
||||
const totalCount = undefined;
|
||||
const subscription = paginatedSubscribe(callback, client);
|
||||
await resolveQuery({
|
||||
@@ -490,6 +555,34 @@ describe('data provider', () => {
|
||||
expect(lastCallbackArgs[0].totalCount).toBe(100);
|
||||
subscription.unsubscribe();
|
||||
});
|
||||
|
||||
it('errorPolicyGuard should work properly', async () => {
|
||||
const subscription = errorGuardedSubscribe(callback, client);
|
||||
const graphQLError = new GraphQLError(
|
||||
'',
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
['market', 'data'],
|
||||
undefined,
|
||||
{
|
||||
type: 'Internal',
|
||||
}
|
||||
);
|
||||
const graphQLErrors = [graphQLError];
|
||||
const error = new ApolloError({ graphQLErrors });
|
||||
|
||||
await rejectQuery(error);
|
||||
const data = generateData(0, 5);
|
||||
await resolveQuery({
|
||||
data,
|
||||
});
|
||||
expect(mockErrorPolicyGuard).toHaveBeenNthCalledWith(1, graphQLErrors);
|
||||
await waitFor(() =>
|
||||
expect(getData).toHaveBeenCalledWith({ data }, undefined)
|
||||
);
|
||||
subscription.unsubscribe();
|
||||
});
|
||||
});
|
||||
|
||||
describe('derived data provider', () => {
|
||||
|
||||
@@ -5,7 +5,10 @@ import type {
|
||||
OperationVariables,
|
||||
TypedDocumentNode,
|
||||
FetchResult,
|
||||
ErrorPolicy,
|
||||
ApolloQueryResult,
|
||||
} from '@apollo/client';
|
||||
import type { GraphQLErrors } from '@apollo/client/errors';
|
||||
import type { Subscription } from 'zen-observable-ts';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import { isNotFoundGraphQLError } from './apollo-client';
|
||||
@@ -178,6 +181,7 @@ interface DataProviderParams<
|
||||
fetchPolicy?: FetchPolicy;
|
||||
resetDelay?: number;
|
||||
additionalContext?: Record<string, unknown>;
|
||||
errorPolicyGuard?: (graphqlErrors: GraphQLErrors) => boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -186,6 +190,9 @@ interface DataProviderParams<
|
||||
* @param getData transforms received query data to format that will be stored in data provider
|
||||
* @param getDelta transforms delta data to format that will be stored in data provider
|
||||
* @param fetchPolicy
|
||||
* @param resetDelay
|
||||
* @param additionalContext add property to the context of the query, ie. 'isEnlargedTimeout'
|
||||
* @param errorPolicyGuard indicate which gql errors can be tolerate
|
||||
* @returns subscribe function
|
||||
*/
|
||||
function makeDataProviderInternal<
|
||||
@@ -204,6 +211,7 @@ function makeDataProviderInternal<
|
||||
fetchPolicy,
|
||||
resetDelay,
|
||||
additionalContext,
|
||||
errorPolicyGuard,
|
||||
}: DataProviderParams<
|
||||
QueryData,
|
||||
Data,
|
||||
@@ -248,6 +256,30 @@ function makeDataProviderInternal<
|
||||
callbacks.forEach((callback) => notify(callback, updateData));
|
||||
};
|
||||
|
||||
const call = (
|
||||
pagination?: Pagination,
|
||||
policy?: ErrorPolicy
|
||||
): Promise<ApolloQueryResult<QueryData>> =>
|
||||
client
|
||||
.query<QueryData>({
|
||||
query,
|
||||
variables: { ...variables, ...(pagination && { pagination }) },
|
||||
fetchPolicy: fetchPolicy || 'no-cache',
|
||||
context: additionalContext,
|
||||
errorPolicy: policy || 'none',
|
||||
})
|
||||
.catch((err) => {
|
||||
if (
|
||||
err.graphQLErrors &&
|
||||
errorPolicyGuard &&
|
||||
errorPolicyGuard(err.graphQLErrors)
|
||||
) {
|
||||
return call(pagination, 'ignore');
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
|
||||
const load = async (start?: number, end?: number) => {
|
||||
if (!pagination) {
|
||||
return Promise.reject();
|
||||
@@ -276,15 +308,9 @@ function makeDataProviderInternal<
|
||||
} else if (!pageInfo?.hasNextPage) {
|
||||
return null;
|
||||
}
|
||||
const res = await client.query<QueryData>({
|
||||
query,
|
||||
variables: {
|
||||
...variables,
|
||||
pagination: paginationVariables,
|
||||
},
|
||||
fetchPolicy: fetchPolicy || 'no-cache',
|
||||
context: additionalContext,
|
||||
});
|
||||
|
||||
const res = await call(paginationVariables);
|
||||
|
||||
const insertionData = getData(res.data, variables);
|
||||
const insertionPageInfo = pagination.getPageInfo(res.data);
|
||||
({ data, totalCount } = pagination.append(
|
||||
@@ -313,15 +339,11 @@ function makeDataProviderInternal<
|
||||
if (!client) {
|
||||
return;
|
||||
}
|
||||
const paginationVariables = pagination
|
||||
? { first: pagination.first }
|
||||
: undefined;
|
||||
try {
|
||||
const res = await client.query<QueryData>({
|
||||
query,
|
||||
variables: pagination
|
||||
? { ...variables, pagination: { first: pagination.first } }
|
||||
: variables,
|
||||
fetchPolicy: fetchPolicy || 'no-cache',
|
||||
context: additionalContext,
|
||||
});
|
||||
const res = await call(paginationVariables);
|
||||
data = getData(res.data, variables);
|
||||
if (data && pagination) {
|
||||
if (!(data instanceof Array)) {
|
||||
@@ -355,7 +377,7 @@ function makeDataProviderInternal<
|
||||
}
|
||||
loaded = true;
|
||||
} catch (e) {
|
||||
if (isNotFoundGraphQLError(e as Error, 'party')) {
|
||||
if (isNotFoundGraphQLError(e as Error, ['party'])) {
|
||||
data = getData(null, variables);
|
||||
loaded = true;
|
||||
return;
|
||||
@@ -407,6 +429,15 @@ function makeDataProviderInternal<
|
||||
}
|
||||
};
|
||||
|
||||
const onError = (e: Error) => {
|
||||
error = e;
|
||||
if (subscription) {
|
||||
subscription.unsubscribe();
|
||||
subscription = undefined;
|
||||
}
|
||||
notifyAll();
|
||||
};
|
||||
|
||||
const initialize = async () => {
|
||||
if (subscription) {
|
||||
if (resetTimer) {
|
||||
@@ -427,14 +458,7 @@ function makeDataProviderInternal<
|
||||
variables,
|
||||
fetchPolicy,
|
||||
})
|
||||
.subscribe(onNext, (e) => {
|
||||
error = e as Error;
|
||||
if (subscription) {
|
||||
subscription.unsubscribe();
|
||||
subscription = undefined;
|
||||
}
|
||||
notifyAll();
|
||||
});
|
||||
.subscribe(onNext, onError);
|
||||
}
|
||||
await initialFetch();
|
||||
};
|
||||
@@ -493,7 +517,7 @@ const memoize = <
|
||||
Delta,
|
||||
Variables extends OperationVariables = OperationVariables
|
||||
>(
|
||||
fn: (variables?: Variables) => Subscribe<Data, Delta, Variables>
|
||||
fn: () => Subscribe<Data, Delta, Variables>
|
||||
) => {
|
||||
const cache: {
|
||||
subscribe: Subscribe<Data, Delta, Variables>;
|
||||
@@ -504,7 +528,7 @@ const memoize = <
|
||||
if (cached) {
|
||||
return cached.subscribe;
|
||||
}
|
||||
const subscribe = fn(variables);
|
||||
const subscribe = fn();
|
||||
cache.push({ subscribe, variables });
|
||||
return subscribe;
|
||||
};
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { t } from './i18n';
|
||||
import { getDateTimeFormat } from './format';
|
||||
import { isValid, parseISO } from 'date-fns';
|
||||
|
||||
import { MarketState } from '@vegaprotocol/types';
|
||||
|
||||
export const getMarketExpiryDate = (
|
||||
|
||||
@@ -123,14 +123,15 @@ mockUseGetWithdrawThreshold.mockReturnValue(() =>
|
||||
|
||||
let dateNowSpy: jest.SpyInstance<number, []>;
|
||||
|
||||
const erc20WithdrawalApproval = {
|
||||
assetSource: 'asset-source',
|
||||
amount: '100',
|
||||
nonce: '1',
|
||||
creation: '1',
|
||||
signatures: 'signatures',
|
||||
targetAddress: 'target-address',
|
||||
};
|
||||
const erc20WithdrawalApproval: WithdrawalApprovalQuery['erc20WithdrawalApproval'] =
|
||||
{
|
||||
assetSource: 'asset-source',
|
||||
amount: '100',
|
||||
nonce: '1',
|
||||
creation: '1',
|
||||
signatures: 'signatures',
|
||||
targetAddress: 'target-address',
|
||||
};
|
||||
|
||||
const mockedNetworkParams: MockedResponse<NetworkParamsQuery> = {
|
||||
request: {
|
||||
|
||||
@@ -143,9 +143,13 @@ describe('WithdrawFormContainer', () => {
|
||||
settlementAsset: {
|
||||
__typename: 'Asset',
|
||||
id: 'asset-id',
|
||||
name: 'asset-id',
|
||||
symbol: 'tUSDC',
|
||||
decimals: 5,
|
||||
},
|
||||
dataSourceSpecForTradingTermination: {
|
||||
id: '',
|
||||
},
|
||||
quoteName: 'USD',
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user