diff --git a/apps/console-lite/src/app/components/deal-ticket/use-order-validation.tsx b/apps/console-lite/src/app/components/deal-ticket/use-order-validation.tsx
index 3aba60ae6..b657ff34e 100644
--- a/apps/console-lite/src/app/components/deal-ticket/use-order-validation.tsx
+++ b/apps/console-lite/src/app/components/deal-ticket/use-order-validation.tsx
@@ -1,13 +1,12 @@
import type { ReactNode } from 'react';
import type { FieldErrors } from 'react-hook-form';
import { useMemo } from 'react';
-import { t, toDecimal } from '@vegaprotocol/react-helpers';
+import { DataGrid, t, toDecimal } from '@vegaprotocol/react-helpers';
import { useVegaWallet } from '@vegaprotocol/wallet';
import * as Schema from '@vegaprotocol/types';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import { Tooltip } from '@vegaprotocol/ui-toolkit';
import {
- MarketDataGrid,
compileGridData,
MarginWarning,
isMarketInAuction,
@@ -216,9 +215,7 @@ export const useOrderValidation = ({
{t('This market is in auction until it reaches')}{' '}
- }
+ description={}
>
{t('sufficient liquidity')}
@@ -240,9 +237,7 @@ export const useOrderValidation = ({
{t('This market is in auction due to')}{' '}
- }
+ description={}
>
{t('high price volatility')}
@@ -281,9 +276,7 @@ export const useOrderValidation = ({
{t('This market is in auction until it reaches')}{' '}
- }
+ description={}
>
{t('sufficient liquidity')}
@@ -307,9 +300,7 @@ export const useOrderValidation = ({
{t('This market is in auction due to')}{' '}
- }
+ description={}
>
{t('high price volatility')}
diff --git a/apps/trading/client-pages/market/trade-market-header.tsx b/apps/trading/client-pages/market/trade-market-header.tsx
index c6c25d49e..11117dd88 100644
--- a/apps/trading/client-pages/market/trade-market-header.tsx
+++ b/apps/trading/client-pages/market/trade-market-header.tsx
@@ -17,6 +17,7 @@ import { Last24hPriceChange } from '../../components/last-24h-price-change';
import { Last24hVolume } from '../../components/last-24h-volume';
import { MarketState } from '../../components/market-state';
import { MarketTradingMode } from '../../components/market-trading-mode';
+import { MarketLiquiditySupplied } from '../../components/liquidity-supplied';
interface TradeMarketHeaderProps {
market: SingleMarketFieldsFragment | null;
@@ -96,6 +97,10 @@ export const TradeMarketHeader = ({
) : null}
+
);
};
diff --git a/apps/trading/components/liquidity-supplied/index.ts b/apps/trading/components/liquidity-supplied/index.ts
new file mode 100644
index 000000000..db2d8192d
--- /dev/null
+++ b/apps/trading/components/liquidity-supplied/index.ts
@@ -0,0 +1 @@
+export * from './liquidity-supplied';
diff --git a/apps/trading/components/liquidity-supplied/liquidity-supplied.tsx b/apps/trading/components/liquidity-supplied/liquidity-supplied.tsx
new file mode 100644
index 000000000..e5e6a3815
--- /dev/null
+++ b/apps/trading/components/liquidity-supplied/liquidity-supplied.tsx
@@ -0,0 +1,130 @@
+import { useCallback, useMemo, useState } from 'react';
+import {
+ addDecimalsFormatNumber,
+ formatNumberPercentage,
+ NetworkParams,
+ t,
+ useDataProvider,
+ useNetworkParams,
+} from '@vegaprotocol/react-helpers';
+import type {
+ MarketData,
+ MarketDataUpdateFieldsFragment,
+ SingleMarketFieldsFragment,
+} from '@vegaprotocol/market-list';
+import { marketDataProvider, marketProvider } from '@vegaprotocol/market-list';
+import { HeaderStat } from '../header';
+import { Link } from '@vegaprotocol/ui-toolkit';
+import BigNumber from 'bignumber.js';
+import { useCheckLiquidityStatus } from '@vegaprotocol/liquidity';
+import { DataGrid } from '@vegaprotocol/react-helpers';
+
+interface Props {
+ marketId?: string;
+ noUpdate?: boolean;
+ assetDecimals: number;
+}
+
+export const MarketLiquiditySupplied = ({
+ marketId,
+ assetDecimals,
+ noUpdate = false,
+}: Props) => {
+ const [market, setMarket] = useState();
+ const { params } = useNetworkParams([
+ NetworkParams.market_liquidity_stakeToCcySiskas,
+ NetworkParams.market_liquidity_targetstake_triggering_ratio,
+ ]);
+
+ const stakeToCcyVolume = Number(params.market_liquidity_stakeToCcySiskas);
+ const triggeringRatio = Number(
+ params.market_liquidity_targetstake_triggering_ratio
+ );
+
+ const variables = useMemo(
+ () => ({
+ marketId: marketId,
+ }),
+ [marketId]
+ );
+
+ const { data } = useDataProvider({
+ dataProvider: marketProvider,
+ variables,
+ skip: !marketId,
+ });
+
+ const update = useCallback(
+ ({ data: marketData }: { data: MarketData | null }) => {
+ if (!noUpdate && marketData) {
+ setMarket(marketData);
+ }
+ return true;
+ },
+ [noUpdate]
+ );
+
+ useDataProvider({
+ dataProvider: marketDataProvider,
+ update,
+ variables,
+ skip: noUpdate || !marketId || !data,
+ });
+
+ const supplied = market?.suppliedStake
+ ? addDecimalsFormatNumber(
+ new BigNumber(market?.suppliedStake)
+ .multipliedBy(stakeToCcyVolume || 1)
+ .toString(),
+ assetDecimals
+ )
+ : '-';
+
+ const { percentage } = useCheckLiquidityStatus({
+ suppliedStake: market?.suppliedStake || 0,
+ targetStake: market?.targetStake || 0,
+ triggeringRatio,
+ });
+
+ const compiledGrid = [
+ {
+ label: t('Supplied stake'),
+ value: market?.suppliedStake
+ ? addDecimalsFormatNumber(
+ new BigNumber(market?.suppliedStake).toString(),
+ assetDecimals
+ )
+ : '-',
+ },
+ {
+ label: t('Target stake'),
+ value: market?.targetStake
+ ? addDecimalsFormatNumber(
+ new BigNumber(market?.targetStake).toString(),
+ assetDecimals
+ )
+ : '-',
+ },
+ ];
+
+ const description = (
+
+ {compiledGrid && }
+
+
+ {t('View liquidity provision table')}
+
+
+ );
+
+ return (
+
+ {/* */}
+ {supplied} ({formatNumberPercentage(percentage, 2)})
+
+ );
+};
diff --git a/libs/deal-ticket/src/components/deal-ticket/time-in-force-selector.tsx b/libs/deal-ticket/src/components/deal-ticket/time-in-force-selector.tsx
index dd3c660ee..f56fac56e 100644
--- a/libs/deal-ticket/src/components/deal-ticket/time-in-force-selector.tsx
+++ b/libs/deal-ticket/src/components/deal-ticket/time-in-force-selector.tsx
@@ -6,10 +6,10 @@ import {
Tooltip,
} from '@vegaprotocol/ui-toolkit';
import * as Schema from '@vegaprotocol/types';
-import { t } from '@vegaprotocol/react-helpers';
+import { DataGrid, t } from '@vegaprotocol/react-helpers';
import { timeInForceLabel } from '@vegaprotocol/orders';
import type { MarketDealTicket } from '@vegaprotocol/market-list';
-import { compileGridData, MarketDataGrid } from '../trading-mode-tooltip';
+import { compileGridData } from '../trading-mode-tooltip';
import { MarketModeValidationType } from '../../constants';
interface TimeInForceSelectorProps {
@@ -78,9 +78,7 @@ export const TimeInForceSelector = ({
return (
{t('This market is in auction until it reaches')}{' '}
- }
- >
+ }>
{t('sufficient liquidity')}
{'. '}
@@ -95,9 +93,7 @@ export const TimeInForceSelector = ({
return (
{t('This market is in auction due to')}{' '}
- }
- >
+ }>
{t('high price volatility')}
{'. '}
diff --git a/libs/deal-ticket/src/components/deal-ticket/type-selector.tsx b/libs/deal-ticket/src/components/deal-ticket/type-selector.tsx
index fe67e371e..973c2c5ff 100644
--- a/libs/deal-ticket/src/components/deal-ticket/type-selector.tsx
+++ b/libs/deal-ticket/src/components/deal-ticket/type-selector.tsx
@@ -1,9 +1,9 @@
import { FormGroup, InputError, Tooltip } from '@vegaprotocol/ui-toolkit';
-import { t } from '@vegaprotocol/react-helpers';
+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 { compileGridData, MarketDataGrid } from '../trading-mode-tooltip';
+import { compileGridData } from '../trading-mode-tooltip';
import { MarketModeValidationType } from '../../constants';
interface TypeSelectorProps {
@@ -33,9 +33,7 @@ export const TypeSelector = ({
return (
{t('This market is in auction until it reaches')}{' '}
- }
- >
+ }>
{t('sufficient liquidity')}
{'. '}
@@ -48,9 +46,7 @@ export const TypeSelector = ({
return (
{t('This market is in auction due to')}{' '}
- }
- >
+ }>
{t('high price volatility')}
{'. '}
diff --git a/libs/deal-ticket/src/components/trading-mode-tooltip/compile-grid-data.tsx b/libs/deal-ticket/src/components/trading-mode-tooltip/compile-grid-data.tsx
index 573efa392..1ce35ceb9 100644
--- a/libs/deal-ticket/src/components/trading-mode-tooltip/compile-grid-data.tsx
+++ b/libs/deal-ticket/src/components/trading-mode-tooltip/compile-grid-data.tsx
@@ -1,3 +1,4 @@
+import type { DataGridProps } from '@vegaprotocol/react-helpers';
import {
t,
getDateTimeFormat,
@@ -6,7 +7,6 @@ import {
import * as Schema from '@vegaprotocol/types';
import { Link as UILink } from '@vegaprotocol/ui-toolkit';
import type { ReactNode } from 'react';
-import type { MarketDataGridProps } from './market-data-grid';
import { Link } from 'react-router-dom';
import type { MarketDealTicket } from '@vegaprotocol/market-list';
@@ -14,7 +14,7 @@ export const compileGridData = (
market: MarketDealTicket,
onSelect?: (id: string) => void
): { label: ReactNode; value?: ReactNode }[] => {
- const grid: MarketDataGridProps['grid'] = [];
+ const grid: DataGridProps['grid'] = [];
const isLiquidityMonitoringAuction =
market.data.marketTradingMode ===
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION &&
diff --git a/libs/deal-ticket/src/components/trading-mode-tooltip/index.ts b/libs/deal-ticket/src/components/trading-mode-tooltip/index.ts
index e22a46214..b55039e70 100644
--- a/libs/deal-ticket/src/components/trading-mode-tooltip/index.ts
+++ b/libs/deal-ticket/src/components/trading-mode-tooltip/index.ts
@@ -1,3 +1,2 @@
-export * from './market-data-grid';
export * from './trading-mode-tooltip';
export * from './compile-grid-data';
diff --git a/libs/deal-ticket/src/components/trading-mode-tooltip/trading-mode-tooltip.tsx b/libs/deal-ticket/src/components/trading-mode-tooltip/trading-mode-tooltip.tsx
index 0033eda00..d60b52e8a 100644
--- a/libs/deal-ticket/src/components/trading-mode-tooltip/trading-mode-tooltip.tsx
+++ b/libs/deal-ticket/src/components/trading-mode-tooltip/trading-mode-tooltip.tsx
@@ -1,11 +1,10 @@
import type { ReactNode } from 'react';
import classNames from 'classnames';
import { useEnvironment } from '@vegaprotocol/environment';
-import { t } from '@vegaprotocol/react-helpers';
+import { DataGrid, t } from '@vegaprotocol/react-helpers';
import * as Schema from '@vegaprotocol/types';
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
import { createDocsLinks } from '@vegaprotocol/react-helpers';
-import { MarketDataGrid } from './market-data-grid';
type TradingModeTooltipProps = {
tradingMode: Schema.MarketTradingMode | null;
@@ -46,7 +45,7 @@ export const TradingModeTooltip = ({
)}
- {compiledGrid && }
+ {compiledGrid && }
);
}
@@ -72,7 +71,7 @@ export const TradingModeTooltip = ({
)}
- {compiledGrid && }
+ {compiledGrid && }
);
}
@@ -94,7 +93,7 @@ export const TradingModeTooltip = ({
)}
- {compiledGrid && }
+ {compiledGrid && }
);
}
diff --git a/libs/liquidity/src/lib/utils/liquidity-utils.spec.tsx b/libs/liquidity/src/lib/utils/liquidity-utils.spec.tsx
index d2f936dfc..a8b1c7566 100644
--- a/libs/liquidity/src/lib/utils/liquidity-utils.spec.tsx
+++ b/libs/liquidity/src/lib/utils/liquidity-utils.spec.tsx
@@ -1,3 +1,6 @@
+import { renderHook } from '@testing-library/react';
+import { Intent } from '@vegaprotocol/ui-toolkit';
+import BigNumber from 'bignumber.js';
import {
formatWithAsset,
sumLiquidityCommitted,
@@ -6,6 +9,7 @@ import {
getCandle24hAgo,
getChange,
EMPTY_VALUE,
+ useCheckLiquidityStatus,
} from './liquidity-utils';
const CANDLES_1 = [
@@ -118,3 +122,50 @@ describe('getChange', () => {
expect(result).toEqual(EMPTY_VALUE);
});
});
+
+describe('useCheckLiquidityStatus', () => {
+ it('should return amber if liquidity is enough', () => {
+ const { result } = renderHook(() =>
+ useCheckLiquidityStatus({
+ suppliedStake: '60',
+ targetStake: '100',
+ triggeringRatio: '0.5',
+ })
+ );
+
+ expect(result.current).toEqual({
+ status: Intent.Warning,
+ percentage: new BigNumber('60'),
+ });
+ });
+
+ it('should return red if liquidity is not enough', () => {
+ const { result } = renderHook(() =>
+ useCheckLiquidityStatus({
+ suppliedStake: '60',
+ targetStake: '100',
+ triggeringRatio: '1',
+ })
+ );
+
+ expect(result.current).toEqual({
+ status: Intent.Danger,
+ percentage: new BigNumber('60'),
+ });
+ });
+
+ it('should return green if liquidity is enough', () => {
+ const { result } = renderHook(() =>
+ useCheckLiquidityStatus({
+ suppliedStake: '101',
+ targetStake: '100',
+ triggeringRatio: '1',
+ })
+ );
+
+ expect(result.current).toEqual({
+ status: Intent.Success,
+ percentage: new BigNumber('101'),
+ });
+ });
+});
diff --git a/libs/liquidity/src/lib/utils/liquidity-utils.ts b/libs/liquidity/src/lib/utils/liquidity-utils.ts
index bbf66b255..49b052fde 100644
--- a/libs/liquidity/src/lib/utils/liquidity-utils.ts
+++ b/libs/liquidity/src/lib/utils/liquidity-utils.ts
@@ -2,6 +2,7 @@ import BigNumber from 'bignumber.js';
import { addDecimalsFormatNumber } from '@vegaprotocol/react-helpers';
import type { MarketNodeFragment } from './../__generated__/MarketsLiquidity';
+import { Intent } from '@vegaprotocol/ui-toolkit';
export type LiquidityProvisionMarket = MarketNodeFragment;
@@ -117,3 +118,46 @@ export const getTargetStake = (
) => {
return markets.find((m) => m.id === marketId)?.data?.targetStake || '0';
};
+
+export const useCheckLiquidityStatus = ({
+ suppliedStake,
+ targetStake,
+ triggeringRatio,
+}: {
+ suppliedStake: string | number;
+ targetStake: string | number;
+ triggeringRatio: string | number;
+}): {
+ status: Intent;
+ percentage: BigNumber;
+} => {
+ // percentage supplied
+ const percentage = new BigNumber(suppliedStake)
+ .dividedBy(targetStake)
+ .multipliedBy(100);
+ // IF supplied_stake >= target_stake THEN
+ if (new BigNumber(suppliedStake).gte(new BigNumber(targetStake))) {
+ // show a green status, e.g. "🟢 $13,666,999 liquidity supplied"
+ return {
+ status: Intent.Success,
+ percentage,
+ };
+ // ELSE IF supplied_stake > NETPARAM[market.liquidity.targetstake.triggering.ratio] * target_stake THEN
+ } else if (
+ new BigNumber(suppliedStake).gte(
+ new BigNumber(targetStake).multipliedBy(triggeringRatio)
+ )
+ ) {
+ // show an amber status, e.g. "🟠$3,456,123 liquidity supplied"
+ return {
+ status: Intent.Warning,
+ percentage,
+ };
+ // ELSE show a red status, e.g. "🔴 $600,002 liquidity supplied"
+ } else {
+ return {
+ status: Intent.Danger,
+ percentage,
+ };
+ }
+};
diff --git a/libs/market-list/src/lib/__generated__/market-data.ts b/libs/market-list/src/lib/__generated__/market-data.ts
index 73a645272..5139ded13 100644
--- a/libs/market-list/src/lib/__generated__/market-data.ts
+++ b/libs/market-list/src/lib/__generated__/market-data.ts
@@ -3,14 +3,14 @@ import * as Types from '@vegaprotocol/types';
import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client';
const defaultOptions = {} as const;
-export type MarketDataUpdateFieldsFragment = { __typename?: 'ObservableMarketData', marketId: string, bestBidPrice: string, bestOfferPrice: string, markPrice: string, trigger: Types.AuctionTrigger, staticMidPrice: string, marketTradingMode: Types.MarketTradingMode, marketState: Types.MarketState, indicativeVolume: string, indicativePrice: string, bestStaticBidPrice: string, bestStaticOfferPrice: string };
+export type MarketDataUpdateFieldsFragment = { __typename?: 'ObservableMarketData', marketId: string, bestBidPrice: string, bestOfferPrice: string, markPrice: string, trigger: Types.AuctionTrigger, staticMidPrice: string, marketTradingMode: Types.MarketTradingMode, marketState: Types.MarketState, indicativeVolume: string, indicativePrice: string, bestStaticBidPrice: string, bestStaticOfferPrice: string, targetStake?: string | null, suppliedStake?: string | null };
export type MarketDataUpdateSubscriptionVariables = Types.Exact<{
marketId: Types.Scalars['ID'];
}>;
-export type MarketDataUpdateSubscription = { __typename?: 'Subscription', marketsData: Array<{ __typename?: 'ObservableMarketData', marketId: string, bestBidPrice: string, bestOfferPrice: string, markPrice: string, trigger: Types.AuctionTrigger, staticMidPrice: string, marketTradingMode: Types.MarketTradingMode, marketState: Types.MarketState, indicativeVolume: string, indicativePrice: string, bestStaticBidPrice: string, bestStaticOfferPrice: string }> };
+export type MarketDataUpdateSubscription = { __typename?: 'Subscription', marketsData: Array<{ __typename?: 'ObservableMarketData', marketId: string, bestBidPrice: string, bestOfferPrice: string, markPrice: string, trigger: Types.AuctionTrigger, staticMidPrice: string, marketTradingMode: Types.MarketTradingMode, marketState: Types.MarketState, indicativeVolume: string, indicativePrice: string, bestStaticBidPrice: string, bestStaticOfferPrice: string, targetStake?: string | null, suppliedStake?: string | null }> };
export type MarketDataFieldsFragment = { __typename?: 'MarketData', bestBidPrice: string, bestOfferPrice: string, markPrice: string, trigger: Types.AuctionTrigger, staticMidPrice: string, marketTradingMode: Types.MarketTradingMode, marketState: Types.MarketState, indicativeVolume: string, indicativePrice: string, bestStaticBidPrice: string, bestStaticOfferPrice: string, targetStake?: string | null, suppliedStake?: string | null, auctionStart?: string | null, auctionEnd?: string | null, market: { __typename?: 'Market', id: string } };
@@ -35,6 +35,8 @@ export const MarketDataUpdateFieldsFragmentDoc = gql`
indicativePrice
bestStaticBidPrice
bestStaticOfferPrice
+ targetStake
+ suppliedStake
}
`;
export const MarketDataFieldsFragmentDoc = gql`
diff --git a/libs/market-list/src/lib/market-data.graphql b/libs/market-list/src/lib/market-data.graphql
index e01819086..9f86ae4bb 100644
--- a/libs/market-list/src/lib/market-data.graphql
+++ b/libs/market-list/src/lib/market-data.graphql
@@ -11,6 +11,8 @@ fragment MarketDataUpdateFields on ObservableMarketData {
indicativePrice
bestStaticBidPrice
bestStaticOfferPrice
+ targetStake
+ suppliedStake
}
subscription MarketDataUpdate($marketId: ID!) {
diff --git a/libs/react-helpers/src/hooks/use-network-params.ts b/libs/react-helpers/src/hooks/use-network-params.ts
index 24efccf30..9c20da7fd 100644
--- a/libs/react-helpers/src/hooks/use-network-params.ts
+++ b/libs/react-helpers/src/hooks/use-network-params.ts
@@ -102,6 +102,9 @@ export const NetworkParams = {
spam_protection_voting_min_tokens: 'spam_protection_voting_min_tokens',
spam_protection_proposal_min_tokens: 'spam_protection_proposal_min_tokens',
market_liquidity_stakeToCcySiskas: 'market_liquidity_stakeToCcySiskas',
+ market_liquidity_stakeToCcyVolume: 'market_liquidity_stakeToCcyVolume',
+ market_liquidity_targetstake_triggering_ratio:
+ 'market_liquidity_targetstake_triggering_ratio',
} as const;
type Params = typeof NetworkParams;
diff --git a/libs/react-helpers/src/index.ts b/libs/react-helpers/src/index.ts
index 65b755edf..754470ae4 100644
--- a/libs/react-helpers/src/index.ts
+++ b/libs/react-helpers/src/index.ts
@@ -14,3 +14,4 @@ export * from './lib/links';
export * from './lib/is-asset-erc20';
export * from './lib/remove-pagination-wrapper';
export * from './lib/__generated__/ChainId';
+export * from './lib/data-grid';
diff --git a/libs/deal-ticket/src/components/trading-mode-tooltip/market-data-grid.tsx b/libs/react-helpers/src/lib/data-grid/data-grid.tsx
similarity index 83%
rename from libs/deal-ticket/src/components/trading-mode-tooltip/market-data-grid.tsx
rename to libs/react-helpers/src/lib/data-grid/data-grid.tsx
index 00f3d46d6..4be0f9122 100644
--- a/libs/deal-ticket/src/components/trading-mode-tooltip/market-data-grid.tsx
+++ b/libs/react-helpers/src/lib/data-grid/data-grid.tsx
@@ -1,13 +1,13 @@
import type { ReactNode } from 'react';
-export type MarketDataGridProps = {
+export type DataGridProps = {
grid: {
label: string | ReactNode;
value?: ReactNode;
}[];
};
-export const MarketDataGrid = ({ grid }: MarketDataGridProps) => {
+export const DataGrid = ({ grid }: DataGridProps) => {
return (
<>
{grid.map(
diff --git a/libs/react-helpers/src/lib/data-grid/index.ts b/libs/react-helpers/src/lib/data-grid/index.ts
new file mode 100644
index 000000000..143006fef
--- /dev/null
+++ b/libs/react-helpers/src/lib/data-grid/index.ts
@@ -0,0 +1 @@
+export * from './data-grid';
diff --git a/libs/react-helpers/src/lib/index.ts b/libs/react-helpers/src/lib/index.ts
index 3002277f6..b07836439 100644
--- a/libs/react-helpers/src/lib/index.ts
+++ b/libs/react-helpers/src/lib/index.ts
@@ -11,3 +11,4 @@ export * from './remove-0x';
export * from './time';
export * from './links';
export * from './remove-pagination-wrapper';
+export * from './data-grid';