Compare commits

...
Author SHA1 Message Date
Matthew Russell 58fd3e2091 chore: add missing t func for text 2023-03-21 08:27:40 -07:00
Dariusz Majcherczyk f91ae48af9 test: skip test 2023-03-15 13:08:26 +01:00
Madalina Raicu 7ab3b2bed9 Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into fix/auction-triggers-liquidity 2023-03-15 10:56:10 +00:00
Art 67e602ebb1 feat(explorer): try again for tx details (#3195) 2023-03-15 08:24:42 +00:00
Art f407110e95 chore(environment): etherscan link (#3193) 2023-03-15 08:24:20 +00:00
Art 66a85cce2a chore(explorer): market info shared panels (#3192) 2023-03-15 08:21:12 +00:00
Art 93f8450ecb fix(utils): missing flags (#3194) 2023-03-15 08:20:41 +00:00
Madalina Raicu db9b6625d7 Merge branch 'fix/auction-triggers-liquidity' of github.com:vegaprotocol/frontend-monorepo into fix/auction-triggers-liquidity 2023-03-15 08:16:07 +00:00
Madalina Raicu 431e69d1c0 fix: status and tooltip for lp dashboard 2023-03-15 08:15:54 +00:00
dexturr 0447a6cf5d chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-15 06:09:39 +00:00
Matthew Russell 02829d88e4 fix: handle new auction trigger in deal ticket type validation, update market summary tests 2023-03-14 17:20:50 -07:00
dexturr 498be838c7 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-15 00:17:07 +00:00
Madalina Raicu 0815f3160a fix: remove import 2023-03-14 09:53:05 +00:00
Madalina Raicu fdd21eaa26 fix(trading): fix liquidity provision triggers mapping 2023-03-14 09:22:30 +00:00
Madalina Raicu 89b49ef622 fix: dropdown menu fix 2023-03-14 08:19:43 +00:00
Madalina Raicu def213e6ba Merge branch 'release/testnet' of github.com:vegaprotocol/frontend-monorepo into release/testnet 2023-03-14 08:17:04 +00:00
37 changed files with 1136 additions and 677 deletions
@@ -1,143 +1,52 @@
import {
addDecimalsFormatNumber,
formatNumberPercentage,
getMarketExpiryDateFormatted,
} from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n';
import type { MarketInfoWithData } from '@vegaprotocol/market-info';
import { MarketInfoTable } from '@vegaprotocol/market-info';
import { LiquidityInfoPanel } from '@vegaprotocol/market-info';
import { LiquidityMonitoringParametersInfoPanel } from '@vegaprotocol/market-info';
import {
MarketStateMapping,
MarketTradingModeMapping,
} from '@vegaprotocol/types';
import { AssetDetailsTable, useAssetDataProvider } from '@vegaprotocol/assets';
import { Splash } from '@vegaprotocol/ui-toolkit';
import BigNumber from 'bignumber.js';
import { useMemo } from 'react';
InstrumentInfoPanel,
KeyDetailsInfoPanel,
LiquidityPriceRangeInfoPanel,
MetadataInfoPanel,
OracleInfoPanel,
RiskFactorsInfoPanel,
RiskModelInfoPanel,
RiskParametersInfoPanel,
SettlementAssetInfoPanel,
} from '@vegaprotocol/market-info';
import { MarketInfoTable } from '@vegaprotocol/market-info';
import { Link } from 'react-router-dom';
export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
const quoteUnit = market?.tradableInstrument.instrument.product.quoteName;
const assetId = useMemo(
() => market?.tradableInstrument.instrument.product?.settlementAsset.id,
[market]
);
const { data: asset } = useAssetDataProvider(assetId ?? '');
if (!market) return null;
const keyDetails = {
decimalPlaces: market.decimalPlaces,
positionDecimalPlaces: market.positionDecimalPlaces,
tradingMode: market.tradingMode,
state: MarketStateMapping[market.state],
};
const assetDecimals =
market.tradableInstrument.instrument.product.settlementAsset.decimals;
const liquidityPriceRange = formatNumberPercentage(
new BigNumber(market.lpPriceRange).times(100)
);
const panels = [
{
title: t('Key details'),
content: (
<MarketInfoTable
noBorder={false}
data={{
name: market.tradableInstrument.instrument.name,
marketID: market.id,
tradingMode:
keyDetails.tradingMode &&
MarketTradingModeMapping[keyDetails.tradingMode],
marketDecimalPlaces: market.decimalPlaces,
positionDecimalPlaces: market.positionDecimalPlaces,
settlementAssetDecimalPlaces: assetDecimals,
}}
/>
),
content: <KeyDetailsInfoPanel noBorder={false} market={market} />,
},
{
title: t('Instrument'),
content: (
<MarketInfoTable
noBorder={false}
data={{
marketName: market.tradableInstrument.instrument.name,
code: market.tradableInstrument.instrument.code,
productType:
market.tradableInstrument.instrument.product.__typename,
...market.tradableInstrument.instrument.product,
}}
/>
),
content: <InstrumentInfoPanel noBorder={false} market={market} />,
},
{
title: t('Settlement asset'),
content: asset ? (
<AssetDetailsTable
asset={asset}
inline={true}
noBorder={false}
dtClassName="text-black dark:text-white text-ui !px-0 !font-normal"
ddClassName="text-black dark:text-white text-ui !px-0 !font-normal max-w-full"
/>
) : (
<Splash>{t('No data')}</Splash>
),
content: <SettlementAssetInfoPanel market={market} noBorder={false} />,
},
{
title: t('Metadata'),
content: (
<MarketInfoTable
noBorder={false}
data={{
expiryDate: getMarketExpiryDateFormatted(
market.tradableInstrument.instrument.metadata.tags
),
...market.tradableInstrument.instrument.metadata.tags
?.map((tag) => {
const [key, value] = tag.split(':');
return { [key]: value };
})
.reduce((acc, curr) => ({ ...acc, ...curr }), {}),
}}
/>
),
content: <MetadataInfoPanel noBorder={false} market={market} />,
},
{
title: t('Risk model'),
content: (
<MarketInfoTable
noBorder={false}
data={market.tradableInstrument.riskModel}
unformatted={true}
omits={[]}
/>
),
content: <RiskModelInfoPanel noBorder={false} market={market} />,
},
{
title: t('Risk parameters'),
content: (
<MarketInfoTable
noBorder={false}
data={market.tradableInstrument.riskModel.params}
unformatted={true}
omits={[]}
/>
),
content: <RiskParametersInfoPanel noBorder={false} market={market} />,
},
{
title: t('Risk factors'),
content: (
<MarketInfoTable
noBorder={false}
data={market.riskFactors}
unformatted={true}
omits={['market', '__typename']}
/>
),
content: <RiskFactorsInfoPanel noBorder={false} market={market} />,
},
...(market.priceMonitoringSettings?.parameters?.triggers || []).map(
(trigger, i) => ({
@@ -158,7 +67,10 @@ export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
<MarketInfoTable
noBorder={false}
data={{ referencePrice: trigger.referencePrice }}
decimalPlaces={assetDecimals}
decimalPlaces={
market.tradableInstrument.instrument.product.settlementAsset
.decimals
}
/>
</>
),
@@ -166,64 +78,26 @@ export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
{
title: t('Liquidity monitoring parameters'),
content: (
<MarketInfoTable
<LiquidityMonitoringParametersInfoPanel
noBorder={false}
data={{
triggeringRatio:
market.liquidityMonitoringParameters.triggeringRatio,
...market.liquidityMonitoringParameters.targetStakeParameters,
}}
market={market}
/>
),
},
{
title: t('Liquidity'),
content: <LiquidityInfoPanel market={market} noBorder={false} />,
},
{
title: t('Liquidity price range'),
content: (
<>
<p className="text-xs mb-4">
{`For liquidity orders to count towards a commitment, they must be
within the liquidity monitoring bounds.`}
</p>
<p className="text-xs mb-4">
{`The liquidity price range is a ${liquidityPriceRange} difference from the mid
price.`}
</p>
<MarketInfoTable
noBorder={false}
data={{
liquidityPriceRange: `${liquidityPriceRange} of mid price`,
lowestPrice:
market.data?.midPrice &&
`${addDecimalsFormatNumber(
new BigNumber(1)
.minus(market.lpPriceRange)
.times(market.data.midPrice)
.toString(),
market.decimalPlaces
)} ${quoteUnit}`,
highestPrice:
market.data?.midPrice &&
`${addDecimalsFormatNumber(
new BigNumber(1)
.plus(market.lpPriceRange)
.times(market.data.midPrice)
.toString(),
market.decimalPlaces
)} ${quoteUnit}`,
}}
></MarketInfoTable>
</>
<LiquidityPriceRangeInfoPanel market={market} noBorder={false} />
),
},
{
title: t('Oracle'),
content: (
<MarketInfoTable
noBorder={false}
data={
market.tradableInstrument.instrument.product.dataSourceSpecBinding
}
>
<OracleInfoPanel noBorder={false} market={market}>
<Link
className="text-xs hover:underline"
to={`/oracles#${market.tradableInstrument.instrument.product.dataSourceSpecForSettlementData.id}`}
@@ -236,7 +110,7 @@ export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
>
{t('View termination oracle specification')}
</Link>
</MarketInfoTable>
</OracleInfoPanel>
),
},
];
@@ -244,7 +118,7 @@ export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
return (
<>
{panels.map((p) => (
<div className="mb-3">
<div key={p.title} className="mb-3">
<h2 className="font-alpha calt text-xl">{p.title}</h2>
{p.content}
</div>
@@ -1,4 +1,5 @@
import { t } from '@vegaprotocol/i18n';
import { Button } from '@vegaprotocol/ui-toolkit';
import { StatusMessage } from '../status-message';
interface RenderFetchedProps {
@@ -7,6 +8,7 @@ interface RenderFetchedProps {
loading: boolean | undefined;
className?: string;
errorMessage?: string;
refetch?: () => void;
}
export const RenderFetched = ({
@@ -15,6 +17,7 @@ export const RenderFetched = ({
children,
className,
errorMessage = t('Error retrieving data'),
refetch,
}: RenderFetchedProps) => {
if (loading) {
return (
@@ -23,7 +26,20 @@ export const RenderFetched = ({
}
if (error) {
return <StatusMessage className={className}>{errorMessage}</StatusMessage>;
return (
<>
<StatusMessage className={className}>{errorMessage}</StatusMessage>
{refetch && (
<Button
onClick={() => {
refetch();
}}
>
{t('Try again')}
</Button>
)}
</>
);
}
return children;
@@ -8,7 +8,7 @@ import { useScrollToLocation } from '../../hooks/scroll-to-location';
import { useDocumentTitle } from '../../hooks/use-document-title';
import compact from 'lodash/compact';
import { JsonViewerDialog } from '../../components/dialogs/json-viewer-dialog';
import { marketInfoProvider } from '@vegaprotocol/market-info';
import { marketInfoWithDataProvider } from '@vegaprotocol/market-info';
import { PageTitle } from '../../components/page-helpers/page-title';
export const MarketPage = () => {
@@ -17,7 +17,7 @@ export const MarketPage = () => {
const { marketId } = useParams<{ marketId: string }>();
const { data, loading, error } = useDataProvider({
dataProvider: marketInfoProvider,
dataProvider: marketInfoWithDataProvider,
skipUpdates: true,
variables: {
marketId: marketId || '',
@@ -22,6 +22,7 @@ const Tx = () => {
const {
state: { data, loading, error },
refetch,
} = useFetch<BlockExplorerTransaction>(
`${DATA_SOURCES.blockExplorerUrl}/transactions/${toNonHex(hash)}`
);
@@ -56,6 +57,7 @@ const Tx = () => {
error={error}
loading={loading}
errorMessage={errorMessage}
refetch={refetch}
>
<TxDetails
className="mb-28"
@@ -21,7 +21,7 @@ import { JsonViewerDialog } from '../../components/dialogs/json-viewer-dialog';
import { PageTitle } from '../../components/page-helpers/page-title';
import BigNumber from 'bignumber.js';
import {
ContractAddressLink,
EtherscanLink,
DApp,
TOKEN_VALIDATOR,
useLinks,
@@ -224,7 +224,7 @@ export const ValidatorsPage = () => {
<KeyValueTableRow>
<div>{t('Ethereum address')}</div>
<div className="break-all text-xs">
<ContractAddressLink address={v.ethereumAddress} />{' '}
<EtherscanLink address={v.ethereumAddress} />{' '}
<CopyWithTooltip text={v.ethereumAddress}>
<button title={t('Copy address to clipboard')}>
<Icon size={3} name="duplicate" />
+10 -22
View File
@@ -1,7 +1,6 @@
import {
KeyValueTable,
KeyValueTableRow,
Link,
RoundedWrapper,
} from '@vegaprotocol/ui-toolkit';
import { Link as RouterLink } from 'react-router-dom';
@@ -11,7 +10,7 @@ import { useParams } from 'react-router';
import { Navigate } from 'react-router-dom';
import { formatNumber } from '@vegaprotocol/utils';
import { useEnvironment } from '@vegaprotocol/environment';
import { EtherscanLink } from '@vegaprotocol/environment';
import { TrancheItem } from '../redemption/tranche-item';
import Routes from '../routes';
import { TrancheLabel } from './tranche-label';
@@ -19,7 +18,6 @@ import { useTranches } from '../../lib/tranches/tranches-store';
export const Tranche = () => {
const tranches = useTranches((state) => state.tranches);
const { ETHERSCAN_URL } = useEnvironment();
const { t } = useTranslation();
const { trancheId } = useParams<{ trancheId: string; address: string }>();
const { chainId } = useWeb3React();
@@ -59,25 +57,15 @@ export const Tranche = () => {
</KeyValueTableRow>
{tranche.users.map((user) => (
<KeyValueTableRow key={user}>
{
<Link
title={t('View on Etherscan (opens in a new tab)')}
href={`${ETHERSCAN_URL}/address/${user}`}
target="_blank"
>
{user}
</Link>
}
{
<RouterLink
className="underline"
title={t('View vesting information')}
to={`${Routes.REDEEM}/${user}`}
data-testid="redeem-link"
>
{t('View vesting information')}
</RouterLink>
}
<EtherscanLink address={user} data-testid="link" />
<RouterLink
className="underline"
title={t('View vesting information')}
to={`${Routes.REDEEM}/${user}`}
data-testid="redeem-link"
>
{t('View vesting information')}
</RouterLink>
</KeyValueTableRow>
))}
</KeyValueTable>
@@ -5,6 +5,7 @@ import * as Schema from '@vegaprotocol/types';
import { t } from '@vegaprotocol/i18n';
import { Indicator } from '../indicator';
import type { AuctionTrigger } from '@vegaprotocol/types';
export const Status = ({
tradingMode,
@@ -31,7 +32,8 @@ export const Status = ({
};
const status = getStatus();
const tooltipDescription = t(getTooltipDescription(status));
const tooltipDescription =
tradingMode && getTooltipDescription(tradingMode, trigger);
return (
<div>
@@ -52,24 +54,43 @@ export const Status = ({
);
};
const getTooltipDescription = (status: string) => {
let tooltipDescription = '';
const getTooltipDescription = (
status: Schema.MarketTradingMode,
trigger?: Schema.AuctionTrigger
) => {
switch (status) {
case Schema.MarketTradingModeMapping.TRADING_MODE_CONTINUOUS:
tooltipDescription =
'This is the standard trading mode where trades are executed whenever orders are received';
break;
case `${Schema.MarketTradingModeMapping.TRADING_MODE_MONITORING_AUCTION} - ${Schema.AuctionTriggerMapping.AUCTION_TRIGGER_LIQUIDITY}`:
tooltipDescription =
'This market is in auction until it reaches sufficient liquidity';
break;
case Schema.MarketTradingModeMapping.TRADING_MODE_OPENING_AUCTION:
tooltipDescription =
'This is a new market in an opening auction to determine a fair mid-price before starting continuous trading.';
break;
case Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS:
return t(
'This is the standard trading mode where trades are executed whenever orders are received'
);
case Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION:
return getMonitoringDescriptionTooltip(trigger);
case Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION:
return t(
'This is a new market in an opening auction to determine a fair mid-price before starting continuous trading.'
);
default:
break;
return '';
}
};
const getMonitoringDescriptionTooltip = (trigger?: AuctionTrigger) => {
switch (trigger) {
case Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET:
return t(
`This market is in auction until it reaches sufficient liquidity.`
);
case Schema.AuctionTrigger.AUCTION_TRIGGER_UNABLE_TO_DEPLOY_LP_ORDERS:
return t(
`This market may have sufficient liquidity but there are not enough priced limit orders in the order book, which are required to deploy liquidity commitment pegged orders.`
);
case Schema.AuctionTrigger.AUCTION_TRIGGER_PRICE:
return t(`This market is in auction due to high price volatility.`);
case Schema.AuctionTrigger.AUCTION_TRIGGER_OPENING:
return t(
`This is a new market in an opening auction to determine a fair mid-price before starting continuous trading`
);
default:
return '';
}
return tooltipDescription;
};
+78 -26
View File
@@ -3,9 +3,9 @@
"tranche_id": 54,
"tranche_start": "2023-04-06T00:00:00.000Z",
"tranche_end": "2023-05-06T00:00:00.000Z",
"total_added": "1050",
"total_added": "1338",
"total_removed": "0",
"locked_amount": "1050",
"locked_amount": "1338",
"deposits": [
{
"amount": "111",
@@ -26,6 +26,16 @@
"amount": "33",
"user": "0x0bBf7580e036eA5D69ABe679CC90117EeC2e3dc1",
"tx": "0x591046ca7581e17fc9b6a99bca457d7abe411c8ef8445259a0954128b71b93fa"
},
{
"amount": "177",
"user": "0x15024E62134A8BFFCce11f5ce58CeCDe853038D7",
"tx": "0x67855754e5b66b548c11d1c5377c8b7786d107d6064902318ba11dd6eb33b8d0"
},
{
"amount": "111",
"user": "0xAc1c2783d64c29CDB79608f5B66a37Fd1ea35dD6",
"tx": "0x99aeaedef27b5fb693485f4e21d434e343b30fa100945a4ff65386de8801c87e"
}
],
"withdrawals": [],
@@ -89,6 +99,36 @@
"total_tokens": "33",
"withdrawn_tokens": "0",
"remaining_tokens": "33"
},
{
"address": "0x15024E62134A8BFFCce11f5ce58CeCDe853038D7",
"deposits": [
{
"amount": "177",
"user": "0x15024E62134A8BFFCce11f5ce58CeCDe853038D7",
"tranche_id": 54,
"tx": "0x67855754e5b66b548c11d1c5377c8b7786d107d6064902318ba11dd6eb33b8d0"
}
],
"withdrawals": [],
"total_tokens": "177",
"withdrawn_tokens": "0",
"remaining_tokens": "177"
},
{
"address": "0xAc1c2783d64c29CDB79608f5B66a37Fd1ea35dD6",
"deposits": [
{
"amount": "111",
"user": "0xAc1c2783d64c29CDB79608f5B66a37Fd1ea35dD6",
"tranche_id": 54,
"tx": "0x99aeaedef27b5fb693485f4e21d434e343b30fa100945a4ff65386de8801c87e"
}
],
"withdrawals": [],
"total_tokens": "111",
"withdrawn_tokens": "0",
"remaining_tokens": "111"
}
]
},
@@ -197,7 +237,7 @@
"tranche_end": "2023-04-06T00:00:00.000Z",
"total_added": "14099",
"total_removed": "22.78816420236",
"locked_amount": "10116.2904342144563784",
"locked_amount": "9888.9977516427704009",
"deposits": [
{
"amount": "30",
@@ -2890,7 +2930,7 @@
"tranche_end": "2023-12-05T00:00:00.000Z",
"total_added": "86666.297",
"total_removed": "0",
"locked_amount": "62979.820364513475562325",
"locked_amount": "62861.1571212942085110557",
"deposits": [
{
"amount": "86666.297",
@@ -2956,7 +2996,7 @@
"tranche_end": "2023-06-01T00:00:00.000Z",
"total_added": "2500",
"total_removed": "0",
"locked_amount": "1074.767405626780575",
"locked_amount": "1067.9026124338625",
"deposits": [
{
"amount": "2500",
@@ -3077,7 +3117,7 @@
"tranche_end": "2023-09-01T00:00:00.000Z",
"total_added": "17500",
"total_removed": "0",
"locked_amount": "16191.59605852455625",
"locked_amount": "16144.06482739533",
"deposits": [
{
"amount": "12500",
@@ -3344,7 +3384,7 @@
"tranche_end": "2023-08-01T00:00:00.000Z",
"total_added": "37500",
"total_removed": "3992.79801615",
"locked_amount": "28848.70175337630375",
"locked_amount": "28745.160949969305",
"deposits": [
{
"amount": "7500",
@@ -3587,7 +3627,7 @@
"tranche_end": "2023-12-05T00:00:00.000Z",
"total_added": "129999.45",
"total_removed": "0",
"locked_amount": "62922.359202855716386305",
"locked_amount": "62803.8042249150901849635",
"deposits": [
{
"amount": "129999.45",
@@ -3653,7 +3693,7 @@
"tranche_end": "2023-09-03T00:00:00.000Z",
"total_added": "62600",
"total_removed": "0",
"locked_amount": "29540.865759766612976",
"locked_amount": "29455.15402080162128",
"deposits": [
{
"amount": "10000",
@@ -3846,7 +3886,7 @@
"tranche_end": "2023-09-17T00:00:00.000Z",
"total_added": "5000",
"total_removed": "0",
"locked_amount": "2551.2748921867075",
"locked_amount": "2544.428906646372",
"deposits": [
{
"amount": "5000",
@@ -4057,7 +4097,7 @@
"tranche_end": "2023-04-05T00:00:00.000Z",
"total_added": "97499.58",
"total_removed": "0",
"locked_amount": "4943.1745180207498219134",
"locked_amount": "4826.8831285567535664111",
"deposits": [
{
"amount": "97499.58",
@@ -4090,7 +4130,7 @@
"tranche_end": "2023-04-05T00:00:00.000Z",
"total_added": "135173.4239508",
"total_removed": "98230.390980249184455396",
"locked_amount": "6756.4661626558330097254912248",
"locked_amount": "6597.515910129377760093140184",
"deposits": [
{
"amount": "135173.4239508",
@@ -4136,7 +4176,7 @@
"tranche_end": "2023-04-05T00:00:00.000Z",
"total_added": "32499.86",
"total_removed": "0",
"locked_amount": "2079.5081556733892347894",
"locked_amount": "2030.5863763707597222158",
"deposits": [
{
"amount": "32499.86",
@@ -4169,7 +4209,7 @@
"tranche_end": "2023-04-05T00:00:00.000Z",
"total_added": "10833.29",
"total_removed": "0",
"locked_amount": "676.8597256021920673029",
"locked_amount": "660.9361611648969862",
"deposits": [
{
"amount": "10833.29",
@@ -4202,7 +4242,7 @@
"tranche_end": "2023-04-05T00:00:00.000Z",
"total_added": "22749.93",
"total_removed": "4720.860935375",
"locked_amount": "2530.252828190445260868",
"locked_amount": "2470.7269878599475445005",
"deposits": [
{
"amount": "6500",
@@ -4354,7 +4394,7 @@
"tranche_end": "2023-05-01T00:00:00.000Z",
"total_added": "22500",
"total_removed": "5529.83377455",
"locked_amount": "5872.7569636279935",
"locked_amount": "5810.63248158379425",
"deposits": [
{
"amount": "7500",
@@ -4717,7 +4757,7 @@
"tranche_end": "2023-06-02T00:00:00.000Z",
"total_added": "1939928.38",
"total_removed": "928642.9598472029154",
"locked_amount": "421166.780391818236125948",
"locked_amount": "418510.6360640652716794746",
"deposits": [
{
"amount": "1852091.69",
@@ -38181,7 +38221,7 @@
"tranche_end": "2023-06-05T00:00:00.000Z",
"total_added": "3732368.4671",
"total_removed": "700133.348465855088393",
"locked_amount": "671688.03149281876437158491",
"locked_amount": "667606.462432296455376981036",
"deposits": [
{
"amount": "1998.95815",
@@ -39563,7 +39603,7 @@
"tranche_end": "2023-12-05T00:00:00.000Z",
"total_added": "15870102.715470999700000001",
"total_removed": "803126.94523812819680452",
"locked_amount": "7681450.2188207884932082890643127254920249",
"locked_amount": "7666977.23699395663856772391215730126493643",
"deposits": [
{
"amount": "16249.93",
@@ -45690,7 +45730,7 @@
"tranche_end": "2023-05-05T00:00:00.000Z",
"total_added": "14597706.0446472999",
"total_removed": "5735873.982235800798313006",
"locked_amount": "1370020.569202310181297838894174209",
"locked_amount": "1356659.204790641720440640129577783",
"deposits": [
{
"amount": "129284.449",
@@ -53034,7 +53074,7 @@
"tranche_end": "2023-04-05T00:00:00.000Z",
"total_added": "5778205.3912159303",
"total_removed": "3362269.76579626473241024",
"locked_amount": "224400.009167071028580659616895331",
"locked_amount": "219120.853279161821111689561756935",
"deposits": [
{
"amount": "552496.6455",
@@ -55139,8 +55179,8 @@
"tranche_start": "2022-06-05T00:00:00.000Z",
"tranche_end": "2023-06-05T00:00:00.000Z",
"total_added": "472355.6199999996",
"total_removed": "37327.7791032710685",
"locked_amount": "106432.80812251448100119836478946",
"total_removed": "37637.6576293990685",
"locked_amount": "105786.04519533285014909089193304",
"deposits": [
{
"amount": "3000",
@@ -61789,6 +61829,11 @@
"user": "0xAc5bd5a3890B12B0da7cF1Ad846F6b8b260B60CC",
"tx": "0x0217cf9cf1bc6f7cb36d51c5531e8f857b0c4982debfcdcda652f116fe01f80b"
},
{
"amount": "309.878526128",
"user": "0x1010101036EA85caAC4BB82D953f26cAf14a9Ebc",
"tx": "0xd6774c065c0e886d82445f16909e9dec106e3c6714cad682ed4102470403aace"
},
{
"amount": "129.867928716",
"user": "0x09996E1a67c371400bD5f52DF841f77B1741eB9d",
@@ -70084,10 +70129,17 @@
"tx": "0xc7dd4c2b995cc486fcd8b7892cd79f8fb393ada004dc68cf66ec82d99b35763c"
}
],
"withdrawals": [],
"withdrawals": [
{
"amount": "309.878526128",
"user": "0x1010101036EA85caAC4BB82D953f26cAf14a9Ebc",
"tranche_id": 5,
"tx": "0xd6774c065c0e886d82445f16909e9dec106e3c6714cad682ed4102470403aace"
}
],
"total_tokens": "400",
"withdrawn_tokens": "0",
"remaining_tokens": "400"
"withdrawn_tokens": "309.878526128",
"remaining_tokens": "90.121473872"
},
{
"address": "0x64D50eceEC4D3428d4Ea43365A3335Cb7CBCA3fD",
@@ -71,7 +71,8 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
validateMarketDataRow(3, 'Quote Name', 'BTC');
});
it('settlement asset displayed', () => {
// need to check why data are not visible
it.skip('settlement asset displayed', () => {
cy.getByTestId(marketTitle).contains('Settlement asset').click();
cy.window().then((win) => {
cy.stub(win, 'prompt').returns('DISABLED WINDOW PROMPT');
@@ -21,7 +21,7 @@ describe('Market proposal notification', { tags: '@smoke' }, () => {
cy.mockTradingPage(
Schema.MarketState.STATE_ACTIVE,
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET
);
cy.mockGQL((req) => {
aliasGQLQuery(
@@ -62,7 +62,7 @@ describe('Market trading page', () => {
cy.mockTradingPage(
Schema.MarketState.STATE_ACTIVE,
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET
);
cy.mockSubscription();
cy.visit('/#/markets/market-0');
@@ -148,7 +148,7 @@ describe('Market trading page', () => {
cy.getByTestId(itemHeader).should('have.text', 'Trading mode');
cy.getByTestId(itemValue).should(
'have.text',
'Monitoring auction - liquidity'
'Monitoring auction - liquidity (target not met)'
);
});
});
@@ -12,7 +12,7 @@ describe('markets table', { tags: '@smoke' }, () => {
cy.mockTradingPage(
Schema.MarketState.STATE_ACTIVE,
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET
);
cy.mockSubscription();
cy.visit('/');
@@ -161,7 +161,7 @@ describe(
cy.mockTradingPage(
Schema.MarketState.STATE_SUSPENDED,
Schema.MarketTradingMode.TRADING_MODE_BATCH_AUCTION,
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET
);
cy.mockSubscription();
cy.visit('/#/markets/market-0');
@@ -230,7 +230,7 @@ describe(
cy.mockTradingPage(
Schema.MarketState.STATE_SUSPENDED,
Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION,
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET
);
cy.mockSubscription();
cy.visit('/#/markets/market-0');
@@ -299,7 +299,7 @@ describe(
cy.mockTradingPage(
Schema.MarketState.STATE_SUSPENDED,
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET
);
cy.mockSubscription();
cy.visit('/#/markets/market-0');
@@ -585,7 +585,7 @@ describe('suspended market validation', { tags: '@regression' }, () => {
cy.mockTradingPage(
Schema.MarketState.STATE_SUSPENDED,
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET
);
const accounts = accountsQuery();
cy.mockGQL((req) => {
@@ -93,7 +93,8 @@ export const MarketLiquiditySupplied = ({
percentage.gte(100) &&
market?.marketTradingMode ===
MarketTradingMode.TRADING_MODE_MONITORING_AUCTION &&
market.trigger === AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY;
market.trigger ===
AuctionTrigger.AUCTION_TRIGGER_UNABLE_TO_DEPLOY_LP_ORDERS;
const description = marketId ? (
<section>
@@ -1,6 +1,6 @@
import type { ReactNode } from 'react';
import { useAssetsDataProvider } from '@vegaprotocol/assets';
import { ETHERSCAN_TX, useEtherscanLink } from '@vegaprotocol/environment';
import { EtherscanLink } from '@vegaprotocol/environment';
import { formatNumber, toBigNum } from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n';
import type { Toast, ToastContent } from '@vegaprotocol/ui-toolkit';
@@ -8,7 +8,7 @@ import { ToastHeading } from '@vegaprotocol/ui-toolkit';
import { Panel } from '@vegaprotocol/ui-toolkit';
import { CLOSE_AFTER } from '@vegaprotocol/ui-toolkit';
import { useToasts } from '@vegaprotocol/ui-toolkit';
import { ExternalLink, Intent, ProgressBar } from '@vegaprotocol/ui-toolkit';
import { Intent, ProgressBar } from '@vegaprotocol/ui-toolkit';
import { useCallback } from 'react';
import compact from 'lodash/compact';
import type { EthStoredTxState } from '@vegaprotocol/web3';
@@ -103,7 +103,7 @@ const EthTxPendingToastContent = ({ tx }: EthTxToastContentProps) => {
<>
<ToastHeading>{t('Awaiting confirmation')}</ToastHeading>
<p>{t('Please wait for your transaction to be confirmed.')}</p>
<EtherscanLink tx={tx} />
{tx.txHash && <EtherscanLink tx={tx.txHash} />}
<EthTransactionDetails tx={tx} />
</>
);
@@ -126,26 +126,12 @@ const EthTxErrorToastContent = ({ tx }: EthTxToastContentProps) => {
);
};
const EtherscanLink = ({ tx }: EthTxToastContentProps) => {
const etherscanLink = useEtherscanLink();
return tx.txHash ? (
<p className="break-all">
<ExternalLink
href={etherscanLink(ETHERSCAN_TX.replace(':hash', tx.txHash))}
rel="noreferrer"
>
{t('View on Etherscan')}
</ExternalLink>
</p>
) : null;
};
const EthTxConfirmedToastContent = ({ tx }: EthTxToastContentProps) => {
return (
<>
<ToastHeading>{t('Transaction confirmed')}</ToastHeading>
<p>{t('Your transaction has been confirmed.')}</p>
<EtherscanLink tx={tx} />
{tx.txHash && <EtherscanLink tx={tx.txHash} />}
<EthTransactionDetails tx={tx} />
</>
);
@@ -162,7 +148,7 @@ const EthTxCompletedToastContent = ({ tx }: EthTxToastContentProps) => {
{t('Your transaction has been completed.')}{' '}
{isDeposit && t('Waiting for deposit confirmation.')}
</p>
<EtherscanLink tx={tx} />
{tx.txHash && <EtherscanLink tx={tx.txHash} />}
<EthTransactionDetails tx={tx} />
</>
);
+2 -2
View File
@@ -1,4 +1,4 @@
import { ContractAddressLink } from '@vegaprotocol/environment';
import { EtherscanLink } from '@vegaprotocol/environment';
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n';
import type * as Schema from '@vegaprotocol/types';
@@ -108,7 +108,7 @@ export const rows: Rows = [
return (
<>
<ContractAddressLink address={asset.source.contractAddress} />{' '}
<EtherscanLink address={asset.source.contractAddress} />{' '}
<CopyWithTooltip text={asset.source.contractAddress}>
<button title={t('Copy address to clipboard')}>
<Icon size={3} name="duplicate" />
@@ -30,9 +30,12 @@ export const compileGridData = (
): { label: ReactNode; value?: ReactNode }[] => {
const grid: SimpleGridProps['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_TARGET_NOT_MET) ||
marketData?.trigger ===
Schema.AuctionTrigger.AUCTION_TRIGGER_UNABLE_TO_DEPLOY_LP_ORDERS;
const formatStake = (value: string) => {
const formattedValue = addDecimalsFormatNumber(
@@ -9,7 +9,6 @@ import * as Schema from '@vegaprotocol/types';
import { ExternalLink, SimpleGrid } from '@vegaprotocol/ui-toolkit';
import { compileGridData } from './compile-grid-data';
import { useMarket, useStaticMarketData } from '@vegaprotocol/market-list';
import BigNumber from 'bignumber.js';
type TradingModeTooltipProps = {
marketId?: string;
@@ -115,23 +114,39 @@ export const TradingModeTooltip = ({
}
case Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION: {
switch (trigger) {
case Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY: {
const notEnoughLiquidity = new BigNumber(
marketData.suppliedStake || 0
).isLessThan(marketData.targetStake || 0);
case Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET: {
return (
<section data-testid="trading-mode-tooltip">
<p className={classNames({ 'mb-4': Boolean(compiledGrid) })}>
<span className="mb-2">
{notEnoughLiquidity &&
t(
'This market is in auction until it reaches sufficient liquidity.'
)}
{!notEnoughLiquidity &&
t(
'This market may have sufficient liquidity but there are not enough priced limit orders in the order book, which are required to deploy liquidity commitment pegged orders.'
)}
</span>{' '}
{t(
'This market is in auction until it reaches sufficient liquidity.'
)}
</span>
{VEGA_DOCS_URL && (
<ExternalLink
href={
createDocsLinks(VEGA_DOCS_URL)
.AUCTION_TYPE_LIQUIDITY_MONITORING
}
>
{t('Find out more')}
</ExternalLink>
)}
</p>
{compiledGrid && <SimpleGrid grid={compiledGrid} />}
</section>
);
}
case Schema.AuctionTrigger.AUCTION_TRIGGER_UNABLE_TO_DEPLOY_LP_ORDERS: {
return (
<section data-testid="trading-mode-tooltip">
<p className={classNames({ 'mb-4': Boolean(compiledGrid) })}>
<span className="mb-2">
{t(
'This market may have sufficient liquidity but there are not enough priced limit orders in the order book, which are required to deploy liquidity commitment pegged orders.'
)}
</span>
{VEGA_DOCS_URL && (
<ExternalLink
href={
@@ -13,7 +13,10 @@ export const validateTimeInForce = (
const isPriceTrigger =
trigger === Schema.AuctionTrigger.AUCTION_TRIGGER_PRICE;
const isLiquidityTrigger =
trigger === Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY;
trigger ===
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET ||
trigger ===
Schema.AuctionTrigger.AUCTION_TRIGGER_UNABLE_TO_DEPLOY_LP_ORDERS;
if (isMarketInAuction(marketTradingMode)) {
if (
+4 -1
View File
@@ -17,7 +17,10 @@ export const validateType = (
const isPriceTrigger =
trigger === Schema.AuctionTrigger.AUCTION_TRIGGER_PRICE;
const isLiquidityTrigger =
trigger === Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY;
trigger ===
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET ||
trigger ===
Schema.AuctionTrigger.AUCTION_TRIGGER_UNABLE_TO_DEPLOY_LP_ORDERS;
if (isMonitoringAuction && isPriceTrigger) {
return MarketModeValidationType.PriceMonitoringAuction;
@@ -1,7 +1,7 @@
import type { Asset } from '@vegaprotocol/assets';
import { useEnvironment } from '@vegaprotocol/environment';
import { EtherscanLink } from '@vegaprotocol/environment';
import { t } from '@vegaprotocol/i18n';
import { ExternalLink, Intent, Notification } from '@vegaprotocol/ui-toolkit';
import { Intent, Notification } from '@vegaprotocol/ui-toolkit';
import { formatNumber } from '@vegaprotocol/utils';
import type { EthStoredTxState } from '@vegaprotocol/web3';
import { EthTxStatus, useEthTransactionStore } from '@vegaprotocol/web3';
@@ -126,14 +126,10 @@ const ApprovalTxFeedback = ({
selectedAsset: Asset;
allowance?: BigNumber;
}) => {
const { ETHERSCAN_URL } = useEnvironment();
if (!tx) return null;
const txLink = tx.txHash && (
<ExternalLink href={`${ETHERSCAN_URL}/tx/${tx.txHash}`}>
{t('View on Etherscan')}
</ExternalLink>
<EtherscanLink tx={tx.txHash}>{t('View on Etherscan')}</EtherscanLink>
);
if (tx.status === EthTxStatus.Error) {
+3 -10
View File
@@ -8,7 +8,6 @@ import {
} from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n';
import type { AgGridReact } from 'ag-grid-react';
import { Link } from '@vegaprotocol/ui-toolkit';
import { AgGridDynamic as AgGrid } from '@vegaprotocol/datagrid';
import type {
VegaICellRendererParams,
@@ -16,14 +15,13 @@ import type {
TypedDataAgGrid,
} from '@vegaprotocol/datagrid';
import type { DepositFieldsFragment } from './__generated__/Deposit';
import { useEnvironment } from '@vegaprotocol/environment';
import { EtherscanLink } from '@vegaprotocol/environment';
import { DepositStatusMapping } from '@vegaprotocol/types';
export const DepositsTable = forwardRef<
AgGridReact,
TypedDataAgGrid<DepositFieldsFragment>
>((props, ref) => {
const { ETHERSCAN_URL } = useEnvironment();
return (
<AgGrid
ref={ref}
@@ -77,14 +75,9 @@ export const DepositsTable = forwardRef<
if (!data) return null;
if (!value) return '-';
return (
<Link
title={t('View transaction on Etherscan')}
href={`${ETHERSCAN_URL}/tx/${value}`}
data-testid="etherscan-link"
target="_blank"
>
<EtherscanLink tx={value} data-testid="etherscan-link">
{truncateByChars(value)}
</Link>
</EtherscanLink>
);
}}
/>
@@ -1,7 +1,7 @@
import type { Asset } from '@vegaprotocol/assets';
import { useEnvironment } from '@vegaprotocol/environment';
import { EtherscanLink } from '@vegaprotocol/environment';
import { t } from '@vegaprotocol/i18n';
import { ExternalLink, Intent, Notification } from '@vegaprotocol/ui-toolkit';
import { Intent, Notification } from '@vegaprotocol/ui-toolkit';
import { EthTxStatus, useEthTransactionStore } from '@vegaprotocol/web3';
import { getFaucetError } from './get-faucet-error';
@@ -19,7 +19,6 @@ export const FaucetNotification = ({
selectedAsset,
faucetTxId,
}: FaucetNotificationProps) => {
const { ETHERSCAN_URL } = useEnvironment();
const tx = useEthTransactionStore((state) => {
return state.transactions.find((t) => t?.id === faucetTxId);
});
@@ -79,9 +78,9 @@ export const FaucetNotification = ({
</p>
{tx.txHash && (
<p>
<ExternalLink href={`${ETHERSCAN_URL}/tx/${tx.txHash}`}>
<EtherscanLink tx={tx.txHash}>
{t('View on Etherscan')}
</ExternalLink>
</EtherscanLink>
</p>
)}
</>
@@ -107,9 +106,9 @@ export const FaucetNotification = ({
</p>
{tx.txHash && (
<p>
<ExternalLink href={`${ETHERSCAN_URL}/tx/${tx.txHash}`}>
<EtherscanLink tx={tx.txHash}>
{t('View on Etherscan')}
</ExternalLink>
</EtherscanLink>
</p>
)}
</>
@@ -1,13 +0,0 @@
import { t } from '@vegaprotocol/i18n';
import { Link } from '@vegaprotocol/ui-toolkit';
import { useEtherscanLink } from '../hooks';
export const ContractAddressLink = ({ address }: { address: string }) => {
const etherscanLink = useEtherscanLink();
const href = etherscanLink(`/address/${address}`);
return (
<Link href={href} target="_blank" title={t('View on etherscan')}>
{address}
</Link>
);
};
@@ -0,0 +1,38 @@
import { t } from '@vegaprotocol/i18n';
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
import type { ComponentProps } from 'react';
import { ETHERSCAN_ADDRESS, ETHERSCAN_TX, useEtherscanLink } from '../hooks';
export const EtherscanLink = ({
address,
tx,
children,
...props
}: {
address?: string;
tx?: string;
} & ComponentProps<typeof ExternalLink>) => {
const etherscanLink = useEtherscanLink();
let href = '';
if ((!address && !tx) || (address && tx)) {
return null;
}
if (address) {
href = etherscanLink(ETHERSCAN_ADDRESS.replace(':hash', address));
}
if (tx) {
href = etherscanLink(ETHERSCAN_TX.replace(':hash', tx));
}
return (
<ExternalLink
href={href}
title={t('View on Etherscan (opens in a new tab)')}
{...props}
>
{children || address || tx}
</ExternalLink>
);
};
+1 -1
View File
@@ -2,4 +2,4 @@ export * from './network-loader';
export * from './network-switcher';
export * from './node-guard';
export * from './node-switcher';
export * from './contract-address-link';
export * from './etherscan-link';
+1
View File
@@ -103,6 +103,7 @@ export const TOKEN_VALIDATOR = '/validators/:id';
export const EXPLORER_TX = '/txs/:hash';
// Etherscan pages
export const ETHERSCAN_ADDRESS = '/address/:hash';
export const ETHERSCAN_TX = '/tx/:hash';
// Console pages
@@ -3,3 +3,4 @@ export * from './info-market';
export * from './tooltip-mapping';
export * from './__generated__/MarketInfo';
export * from './market-info-data-provider';
export * from './market-info-panels';
@@ -1,17 +1,5 @@
import { AssetDetailsTable, useAssetDataProvider } from '@vegaprotocol/assets';
import { useEnvironment } from '@vegaprotocol/environment';
import {
totalFeesPercentage,
calcCandleVolume,
} from '@vegaprotocol/market-list';
import {
addDecimalsFormatNumber,
formatNumber,
formatNumberPercentage,
removePaginationWrapper,
TokenLinks,
getMarketExpiryDateFormatted,
} from '@vegaprotocol/utils';
import { removePaginationWrapper, TokenLinks } from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n';
import { useDataProvider, useYesterday } from '@vegaprotocol/react-helpers';
import * as Schema from '@vegaprotocol/types';
@@ -22,15 +10,31 @@ import {
Link as UILink,
Splash,
} from '@vegaprotocol/ui-toolkit';
import BigNumber from 'bignumber.js';
import { useMemo } from 'react';
import { generatePath, Link } from 'react-router-dom';
import { MarketInfoTable } from './info-key-value-table';
import { marketInfoWithDataAndCandlesProvider } from './market-info-data-provider';
import type { MarketInfoWithDataAndCandles } from './market-info-data-provider';
import { MarketProposalNotification } from '@vegaprotocol/proposals';
import {
CurrentFeesInfoPanel,
InstrumentInfoPanel,
InsurancePoolInfoPanel,
KeyDetailsInfoPanel,
LiquidityInfoPanel,
LiquidityMonitoringParametersInfoPanel,
LiquidityPriceRangeInfoPanel,
MarketPriceInfoPanel,
MarketVolumeInfoPanel,
MetadataInfoPanel,
OracleInfoPanel,
PriceMonitoringBoundsInfoPanel,
RiskFactorsInfoPanel,
RiskModelInfoPanel,
RiskParametersInfoPanel,
SettlementAssetInfoPanel,
} from './market-info-panels';
export interface InfoProps {
market: MarketInfoWithDataAndCandles;
@@ -80,15 +84,6 @@ export const MarketInfoContainer = ({
export const Info = ({ market, onSelect }: InfoProps) => {
const { VEGA_TOKEN_URL, VEGA_EXPLORER_URL } = useEnvironment();
const headerClassName = 'uppercase text-lg';
const assetSymbol =
market?.tradableInstrument.instrument.product?.settlementAsset.symbol || '';
const quoteUnit =
market?.tradableInstrument.instrument.product?.quoteName || '';
const assetId = useMemo(
() => market?.tradableInstrument.instrument.product?.settlementAsset.id,
[market]
);
const { data: asset } = useAssetDataProvider(assetId ?? '');
if (!market) return null;
@@ -96,272 +91,75 @@ export const Info = ({ market, onSelect }: InfoProps) => {
market.accountsConnection?.edges
);
const last24hourVolume = market.candles && calcCandleVolume(market.candles);
const marketDataPanels = [
{
title: t('Current fees'),
content: (
<>
<MarketInfoTable
data={{
...market.fees.factors,
totalFees: totalFeesPercentage(market.fees.factors),
}}
asPercentage={true}
/>
<p className="text-xs">
{t(
'All fees are paid by price takers and are a % of the trade notional value. Fees are not paid during auction uncrossing.'
)}
</p>
</>
),
content: <CurrentFeesInfoPanel market={market} />,
},
{
title: t('Market price'),
content: (
<>
<MarketInfoTable
data={{
markPrice: market.data?.markPrice,
bestBidPrice: market.data?.bestBidPrice,
bestOfferPrice: market.data?.bestOfferPrice,
quoteUnit: market.tradableInstrument.instrument.product.quoteName,
}}
decimalPlaces={market.decimalPlaces}
/>
<p className="text-xs mt-4">
{t(
'There is 1 unit of the settlement asset (%s) to every 1 quote unit (%s).',
[assetSymbol, quoteUnit]
)}
</p>
</>
),
content: <MarketPriceInfoPanel market={market} />,
},
{
title: t('Market volume'),
content: (
<MarketInfoTable
data={{
'24hourVolume':
last24hourVolume && last24hourVolume !== '0'
? addDecimalsFormatNumber(
last24hourVolume,
market.positionDecimalPlaces
)
: '-',
openInterest: market.data?.openInterest,
bestBidVolume: market.data?.bestBidVolume,
bestOfferVolume: market.data?.bestOfferVolume,
bestStaticBidVolume: market.data?.bestStaticBidVolume,
bestStaticOfferVolume: market.data?.bestStaticOfferVolume,
}}
decimalPlaces={market.positionDecimalPlaces}
/>
),
content: <MarketVolumeInfoPanel market={market} />,
},
...marketAccounts
.filter((a) => a.type === Schema.AccountType.ACCOUNT_TYPE_INSURANCE)
.map((a) => ({
title: t(`Insurance pool`),
content: (
<MarketInfoTable
data={{
balance: a.balance,
}}
assetSymbol={assetSymbol}
decimalPlaces={
market.tradableInstrument.instrument.product.settlementAsset
.decimals
}
/>
),
content: <InsurancePoolInfoPanel market={market} account={a} />,
})),
];
const keyDetails = {
decimalPlaces: market.decimalPlaces,
positionDecimalPlaces: market.positionDecimalPlaces,
tradingMode: market.tradingMode,
state: Schema.MarketStateMapping[market.state],
};
const assetDecimals =
market.tradableInstrument.instrument.product.settlementAsset.decimals;
const liquidityPriceRange = formatNumberPercentage(
new BigNumber(market.lpPriceRange).times(100)
);
const marketSpecPanels = [
{
title: t('Key details'),
content: (
<MarketInfoTable
data={{
name: market.tradableInstrument.instrument.name,
marketID: market.id,
tradingMode:
keyDetails.tradingMode &&
Schema.MarketTradingModeMapping[keyDetails.tradingMode],
marketDecimalPlaces: market.decimalPlaces,
positionDecimalPlaces: market.positionDecimalPlaces,
settlementAssetDecimalPlaces: assetDecimals,
}}
/>
),
content: <KeyDetailsInfoPanel market={market} />,
},
{
title: t('Instrument'),
content: (
<MarketInfoTable
data={{
marketName: market.tradableInstrument.instrument.name,
code: market.tradableInstrument.instrument.code,
productType:
market.tradableInstrument.instrument.product.__typename,
...market.tradableInstrument.instrument.product,
}}
/>
),
content: <InstrumentInfoPanel market={market} />,
},
{
title: t('Settlement asset'),
content: asset ? (
<>
<AssetDetailsTable
asset={asset}
inline={true}
noBorder={true}
dtClassName="text-black dark:text-white text-ui !px-0 !font-normal"
ddClassName="text-black dark:text-white text-ui !px-0 !font-normal max-w-full"
/>
<p className="text-xs mt-4">
{t(
'There is 1 unit of the settlement asset (%s) to every 1 quote unit (%s).',
[assetSymbol, quoteUnit]
)}
</p>
</>
) : (
<Splash>{t('No data')}</Splash>
),
content: <SettlementAssetInfoPanel market={market} />,
},
{
title: t('Metadata'),
content: (
<MarketInfoTable
data={{
expiryDate: getMarketExpiryDateFormatted(
market.tradableInstrument.instrument.metadata.tags
),
...market.tradableInstrument.instrument.metadata.tags
?.map((tag) => {
const [key, value] = tag.split(':');
return { [key]: value };
})
.reduce((acc, curr) => ({ ...acc, ...curr }), {}),
}}
/>
),
content: <MetadataInfoPanel market={market} />,
},
{
title: t('Risk model'),
content: (
<MarketInfoTable
data={market.tradableInstrument.riskModel}
unformatted={true}
omits={[]}
/>
),
content: <RiskModelInfoPanel market={market} />,
},
{
title: t('Risk parameters'),
content: (
<MarketInfoTable
data={market.tradableInstrument.riskModel.params}
unformatted={true}
omits={[]}
/>
),
content: <RiskParametersInfoPanel market={market} />,
},
{
title: t('Risk factors'),
content: (
<MarketInfoTable
data={market.riskFactors}
unformatted={true}
omits={['market', '__typename']}
/>
),
content: <RiskFactorsInfoPanel market={market} />,
},
...(market.priceMonitoringSettings?.parameters?.triggers || []).map(
(trigger, i) => {
const bounds = market.data?.priceMonitoringBounds?.[i];
return {
title: t(`Price monitoring bounds ${i + 1}`),
content: (
<div className="text-xs">
<div className="grid grid-cols-2 text-xs mb-4">
<p className="col-span-1">
{t('%s probability price bounds', [
formatNumberPercentage(
new BigNumber(trigger.probability).times(100)
),
])}
</p>
<p className="col-span-1 text-right">
{t('Within %s seconds', [formatNumber(trigger.horizonSecs)])}
</p>
</div>
<div className="pl-2 pb-0 text-xs border-l-2">
{bounds && (
<MarketInfoTable
data={{
highestPrice: bounds.maxValidPrice,
lowestPrice: bounds.minValidPrice,
}}
decimalPlaces={market.decimalPlaces}
assetSymbol={quoteUnit}
/>
)}
</div>
<p className="mt-4">
{t('Results in %s seconds auction if breached', [
trigger.auctionExtensionSecs.toString(),
])}
</p>
</div>
),
};
}
(_, triggerIndex) => ({
title: t(`Price monitoring bounds ${triggerIndex + 1}`),
content: (
<PriceMonitoringBoundsInfoPanel
market={market}
triggerIndex={triggerIndex}
/>
),
})
),
{
title: t('Liquidity monitoring parameters'),
content: (
<MarketInfoTable
data={{
triggeringRatio:
market.liquidityMonitoringParameters.triggeringRatio,
...market.liquidityMonitoringParameters.targetStakeParameters,
}}
/>
),
content: <LiquidityMonitoringParametersInfoPanel market={market} />,
},
{
title: t('Liquidity'),
content: (
<MarketInfoTable
data={{
targetStake: market.data && market.data.targetStake,
suppliedStake: market.data && market.data?.suppliedStake,
marketValueProxy: market.data && market.data.marketValueProxy,
}}
decimalPlaces={assetDecimals}
assetSymbol={assetSymbol}
>
<LiquidityInfoPanel market={market}>
<Link
to={`/liquidity/${market.id}`}
onClick={() => onSelect(market.id)}
@@ -369,57 +167,17 @@ export const Info = ({ market, onSelect }: InfoProps) => {
>
<UILink>{t('View liquidity provision table')}</UILink>
</Link>
</MarketInfoTable>
</LiquidityInfoPanel>
),
},
{
title: t('Liquidity price range'),
content: (
<>
<p className="text-xs mb-4">
{`For liquidity orders to count towards a commitment, they must be
within the liquidity monitoring bounds.`}
</p>
<p className="text-xs mb-4">
{`The liquidity price range is a ${liquidityPriceRange} difference from the mid
price.`}
</p>
<div className="pl-2 pb-0 text-xs border-l-2">
<MarketInfoTable
data={{
liquidityPriceRange: `${liquidityPriceRange} of mid price`,
lowestPrice:
market.data?.midPrice &&
`${addDecimalsFormatNumber(
new BigNumber(1)
.minus(market.lpPriceRange)
.times(market.data.midPrice)
.toString(),
market.decimalPlaces
)} ${quoteUnit}`,
highestPrice:
market.data?.midPrice &&
`${addDecimalsFormatNumber(
new BigNumber(1)
.plus(market.lpPriceRange)
.times(market.data.midPrice)
.toString(),
market.decimalPlaces
)} ${quoteUnit}`,
}}
></MarketInfoTable>
</div>
</>
),
content: <LiquidityPriceRangeInfoPanel market={market} />,
},
{
title: t('Oracle'),
content: (
<MarketInfoTable
data={
market.tradableInstrument.instrument.product.dataSourceSpecBinding
}
>
<OracleInfoPanel market={market}>
<ExternalLink
href={`${VEGA_EXPLORER_URL}/oracles#${market.tradableInstrument.instrument.product.dataSourceSpecForSettlementData.id}`}
>
@@ -430,7 +188,7 @@ export const Info = ({ market, onSelect }: InfoProps) => {
>
{t('View termination oracle specification')}
</ExternalLink>
</MarketInfoTable>
</OracleInfoPanel>
),
},
];
@@ -0,0 +1,418 @@
import type { ComponentProps } from 'react';
import { useMemo } from 'react';
import { AssetDetailsTable, useAssetDataProvider } from '@vegaprotocol/assets';
import { t } from '@vegaprotocol/i18n';
import {
calcCandleVolume,
totalFeesPercentage,
} from '@vegaprotocol/market-list';
import { Splash } from '@vegaprotocol/ui-toolkit';
import {
addDecimalsFormatNumber,
formatNumber,
formatNumberPercentage,
getMarketExpiryDateFormatted,
} from '@vegaprotocol/utils';
import type { Get } from 'type-fest';
import { MarketInfoTable } from './info-key-value-table';
import type {
MarketInfo,
MarketInfoWithData,
MarketInfoWithDataAndCandles,
} from './market-info-data-provider';
import BigNumber from 'bignumber.js';
import { MarketTradingModeMapping } from '@vegaprotocol/types';
type PanelProps = Pick<
ComponentProps<typeof MarketInfoTable>,
'children' | 'noBorder'
>;
type MarketInfoProps = {
market: MarketInfo;
};
type MarketInfoWithDataProps = {
market: MarketInfoWithData;
};
type MarketInfoWithDataAndCandlesProps = {
market: MarketInfoWithDataAndCandles;
};
export const CurrentFeesInfoPanel = ({
market,
...props
}: MarketInfoProps & PanelProps) => (
<>
<MarketInfoTable
data={{
...market.fees.factors,
totalFees: totalFeesPercentage(market.fees.factors),
}}
asPercentage={true}
{...props}
/>
<p className="text-xs">
{t(
'All fees are paid by price takers and are a % of the trade notional value. Fees are not paid during auction uncrossing.'
)}
</p>
</>
);
export const MarketPriceInfoPanel = ({
market,
...props
}: MarketInfoWithDataProps & PanelProps) => {
const assetSymbol =
market?.tradableInstrument.instrument.product?.settlementAsset.symbol || '';
const quoteUnit =
market?.tradableInstrument.instrument.product?.quoteName || '';
return (
<>
<MarketInfoTable
data={{
markPrice: market.data?.markPrice,
bestBidPrice: market.data?.bestBidPrice,
bestOfferPrice: market.data?.bestOfferPrice,
quoteUnit: market.tradableInstrument.instrument.product.quoteName,
}}
decimalPlaces={market.decimalPlaces}
{...props}
/>
<p className="text-xs mt-4">
{t(
'There is 1 unit of the settlement asset (%s) to every 1 quote unit (%s).',
[assetSymbol, quoteUnit]
)}
</p>
</>
);
};
export const MarketVolumeInfoPanel = ({
market,
...props
}: MarketInfoWithDataAndCandlesProps & PanelProps) => {
const last24hourVolume = market.candles && calcCandleVolume(market.candles);
return (
<MarketInfoTable
data={{
'24hourVolume':
last24hourVolume && last24hourVolume !== '0'
? addDecimalsFormatNumber(
last24hourVolume,
market.positionDecimalPlaces
)
: '-',
openInterest: market.data?.openInterest,
bestBidVolume: market.data?.bestBidVolume,
bestOfferVolume: market.data?.bestOfferVolume,
bestStaticBidVolume: market.data?.bestStaticBidVolume,
bestStaticOfferVolume: market.data?.bestStaticOfferVolume,
}}
decimalPlaces={market.positionDecimalPlaces}
{...props}
/>
);
};
export const InsurancePoolInfoPanel = ({
market,
account,
...props
}: {
account: NonNullable<
Get<MarketInfoWithData, 'accountsConnection.edges[0].node'>
>;
} & MarketInfoProps &
PanelProps) => {
const assetSymbol =
market?.tradableInstrument.instrument.product?.settlementAsset.symbol || '';
return (
<MarketInfoTable
data={{
balance: account.balance,
}}
assetSymbol={assetSymbol}
decimalPlaces={
market.tradableInstrument.instrument.product.settlementAsset.decimals
}
{...props}
/>
);
};
export const KeyDetailsInfoPanel = ({
market,
}: MarketInfoProps & PanelProps) => {
const assetDecimals =
market.tradableInstrument.instrument.product.settlementAsset.decimals;
return (
<MarketInfoTable
data={{
name: market.tradableInstrument.instrument.name,
marketID: market.id,
tradingMode:
market.tradingMode && MarketTradingModeMapping[market.tradingMode],
marketDecimalPlaces: market.decimalPlaces,
positionDecimalPlaces: market.positionDecimalPlaces,
settlementAssetDecimalPlaces: assetDecimals,
}}
/>
);
};
export const InstrumentInfoPanel = ({
market,
...props
}: MarketInfoProps & PanelProps) => (
<MarketInfoTable
data={{
marketName: market.tradableInstrument.instrument.name,
code: market.tradableInstrument.instrument.code,
productType: market.tradableInstrument.instrument.product.__typename,
...market.tradableInstrument.instrument.product,
}}
{...props}
/>
);
export const SettlementAssetInfoPanel = ({
market,
noBorder = true,
}: MarketInfoProps & PanelProps) => {
const assetSymbol =
market?.tradableInstrument.instrument.product?.settlementAsset.symbol || '';
const quoteUnit =
market?.tradableInstrument.instrument.product?.quoteName || '';
const assetId = useMemo(
() => market?.tradableInstrument.instrument.product?.settlementAsset.id,
[market]
);
const { data: asset } = useAssetDataProvider(assetId ?? '');
return asset ? (
<>
<AssetDetailsTable
asset={asset}
inline={true}
noBorder={noBorder}
dtClassName="text-black dark:text-white text-ui !px-0 !font-normal"
ddClassName="text-black dark:text-white text-ui !px-0 !font-normal max-w-full"
/>
<p className="text-xs mt-4">
{t(
'There is 1 unit of the settlement asset (%s) to every 1 quote unit (%s).',
[assetSymbol, quoteUnit]
)}
</p>
</>
) : (
<Splash>{t('No data')}</Splash>
);
};
export const MetadataInfoPanel = ({
market,
...props
}: MarketInfoProps & PanelProps) => (
<MarketInfoTable
data={{
expiryDate: getMarketExpiryDateFormatted(
market.tradableInstrument.instrument.metadata.tags
),
...market.tradableInstrument.instrument.metadata.tags
?.map((tag) => {
const [key, value] = tag.split(':');
return { [key]: value };
})
.reduce((acc, curr) => ({ ...acc, ...curr }), {}),
}}
{...props}
/>
);
export const RiskModelInfoPanel = ({
market,
...props
}: MarketInfoProps & PanelProps) => (
<MarketInfoTable
data={market.tradableInstrument.riskModel}
unformatted={true}
omits={[]}
{...props}
/>
);
export const RiskParametersInfoPanel = ({
market,
...props
}: MarketInfoProps & PanelProps) => (
<MarketInfoTable
data={market.tradableInstrument.riskModel.params}
unformatted={true}
omits={[]}
{...props}
/>
);
export const RiskFactorsInfoPanel = ({
market,
...props
}: MarketInfoProps & PanelProps) => (
<MarketInfoTable
data={market.riskFactors}
unformatted={true}
omits={['market', '__typename']}
{...props}
/>
);
export const PriceMonitoringBoundsInfoPanel = ({
market,
triggerIndex,
...props
}: {
triggerIndex: number;
} & MarketInfoWithDataProps &
PanelProps) => {
const quoteUnit =
market?.tradableInstrument.instrument.product?.quoteName || '';
const trigger =
market.priceMonitoringSettings?.parameters?.triggers?.[triggerIndex];
const bounds = market.data?.priceMonitoringBounds?.[triggerIndex];
if (!trigger) {
console.error(
`Could not find data for trigger ${triggerIndex} (market id: ${market.id})`
);
return null;
}
return (
<div className="text-xs">
<div className="grid grid-cols-2 text-xs mb-4">
<p className="col-span-1">
{t('%s probability price bounds', [
formatNumberPercentage(
new BigNumber(trigger.probability).times(100)
),
])}
</p>
<p className="col-span-1 text-right">
{t('Within %s seconds', [formatNumber(trigger.horizonSecs)])}
</p>
</div>
<div className="pl-2 pb-0 text-xs border-l-2">
{bounds && (
<MarketInfoTable
data={{
highestPrice: bounds.maxValidPrice,
lowestPrice: bounds.minValidPrice,
}}
decimalPlaces={market.decimalPlaces}
assetSymbol={quoteUnit}
{...props}
/>
)}
</div>
<p className="mt-4">
{t('Results in %s seconds auction if breached', [
trigger.auctionExtensionSecs.toString(),
])}
</p>
</div>
);
};
export const LiquidityMonitoringParametersInfoPanel = ({
market,
...props
}: MarketInfoProps & PanelProps) => (
<MarketInfoTable
data={{
triggeringRatio: market.liquidityMonitoringParameters.triggeringRatio,
...market.liquidityMonitoringParameters.targetStakeParameters,
}}
{...props}
/>
);
export const LiquidityInfoPanel = ({
market,
...props
}: MarketInfoWithDataProps & PanelProps) => {
const assetDecimals =
market.tradableInstrument.instrument.product.settlementAsset.decimals;
const assetSymbol =
market?.tradableInstrument.instrument.product?.settlementAsset.symbol || '';
return (
<MarketInfoTable
data={{
targetStake: market.data && market.data.targetStake,
suppliedStake: market.data && market.data?.suppliedStake,
marketValueProxy: market.data && market.data.marketValueProxy,
}}
decimalPlaces={assetDecimals}
assetSymbol={assetSymbol}
{...props}
/>
);
};
export const LiquidityPriceRangeInfoPanel = ({
market,
...props
}: MarketInfoWithDataProps & PanelProps) => {
const quoteUnit =
market?.tradableInstrument.instrument.product?.quoteName || '';
const liquidityPriceRange = formatNumberPercentage(
new BigNumber(market.lpPriceRange).times(100)
);
return (
<>
<p className="text-xs mb-4">
{`For liquidity orders to count towards a commitment, they must be
within the liquidity monitoring bounds.`}
</p>
<p className="text-xs mb-4">
{`The liquidity price range is a ${liquidityPriceRange} difference from the mid
price.`}
</p>
<div className="pl-2 pb-0 text-xs border-l-2">
<MarketInfoTable
data={{
liquidityPriceRange: `${liquidityPriceRange} of mid price`,
lowestPrice:
market.data?.midPrice &&
`${addDecimalsFormatNumber(
new BigNumber(1)
.minus(market.lpPriceRange)
.times(market.data.midPrice)
.toString(),
market.decimalPlaces
)} ${quoteUnit}`,
highestPrice:
market.data?.midPrice &&
`${addDecimalsFormatNumber(
new BigNumber(1)
.plus(market.lpPriceRange)
.times(market.data.midPrice)
.toString(),
market.decimalPlaces
)} ${quoteUnit}`,
}}
></MarketInfoTable>
</div>
</>
);
};
export const OracleInfoPanel = ({
market,
...props
}: MarketInfoProps & PanelProps) => (
<MarketInfoTable
data={market.tradableInstrument.instrument.product.dataSourceSpecBinding}
{...props}
/>
);
@@ -74,7 +74,7 @@ const marketsDataFieldsFragments: MarketsDataFieldsFragment[] = [
bestBidPrice: '0',
bestOfferPrice: '0',
markPrice: '4612690058',
trigger: Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY,
trigger: Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET,
__typename: 'MarketData',
},
{
@@ -91,7 +91,7 @@ const marketsDataFieldsFragments: MarketsDataFieldsFragment[] = [
bestBidPrice: '0',
bestOfferPrice: '0',
markPrice: '4612690058',
trigger: Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY,
trigger: Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET,
__typename: 'MarketData',
},
];
+2 -2
View File
@@ -5,9 +5,9 @@ import * as Apollo from '@apollo/client';
const defaultOptions = {} as const;
export type PositionFieldsFragment = { __typename?: 'Position', realisedPNL: string, openVolume: string, unrealisedPNL: string, averageEntryPrice: string, updatedAt?: any | null, positionStatus: Types.PositionStatus, lossSocializationAmount: string, market: { __typename?: 'Market', id: string } };
export type PositionsQueryVariables = {
export type PositionsQueryVariables = Types.Exact<{
partyId: Types.Scalars['ID'];
};
}>;
export type PositionsQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, positionsConnection?: { __typename?: 'PositionConnection', edges?: Array<{ __typename?: 'PositionEdge', node: { __typename?: 'Position', realisedPNL: string, openVolume: string, unrealisedPNL: string, averageEntryPrice: string, updatedAt?: any | null, positionStatus: Types.PositionStatus, lossSocializationAmount: string, market: { __typename?: 'Market', id: string } } }> | null } | null } | null };
+4 -2
View File
@@ -313,12 +313,14 @@ export type AuctionEvent = {
export enum AuctionTrigger {
/** Auction because market has a frequent batch auction trading mode */
AUCTION_TRIGGER_BATCH = 'AUCTION_TRIGGER_BATCH',
/** Liquidity monitoring */
AUCTION_TRIGGER_LIQUIDITY = 'AUCTION_TRIGGER_LIQUIDITY',
/** Liquidity monitoring due to unmet target stake */
AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET = 'AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET',
/** Opening auction */
AUCTION_TRIGGER_OPENING = 'AUCTION_TRIGGER_OPENING',
/** Price monitoring */
AUCTION_TRIGGER_PRICE = 'AUCTION_TRIGGER_PRICE',
/** Liquidity monitoring due to not being able to deploy LP orders because there's nothing to peg on one or both sides of the book */
AUCTION_TRIGGER_UNABLE_TO_DEPLOY_LP_ORDERS = 'AUCTION_TRIGGER_UNABLE_TO_DEPLOY_LP_ORDERS',
/** Invalid trigger (or no auction) */
AUCTION_TRIGGER_UNSPECIFIED = 'AUCTION_TRIGGER_UNSPECIFIED'
}
+3 -1
View File
@@ -63,7 +63,9 @@ export const AuctionTriggerMapping: {
[T in AuctionTrigger]: string;
} = {
AUCTION_TRIGGER_BATCH: 'batch',
AUCTION_TRIGGER_LIQUIDITY: 'liquidity',
AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET: 'liquidity (target not met)',
AUCTION_TRIGGER_UNABLE_TO_DEPLOY_LP_ORDERS:
'liquidity (unable to deploy liquidity provision orders)',
AUCTION_TRIGGER_OPENING: 'opening',
AUCTION_TRIGGER_PRICE: 'price',
AUCTION_TRIGGER_UNSPECIFIED: 'unspecified',
+53 -12
View File
@@ -29,7 +29,6 @@ import { countryCodeToFlagEmoji, FALLBACK_FLAG } from './flag-emoji';
// 🇿
const cases = [
['AC', '🇦🇨'],
['AD', '🇦🇩'],
['AE', '🇦🇪'],
['AF', '🇦🇫'],
@@ -38,11 +37,13 @@ const cases = [
['AL', '🇦🇱'],
['AM', '🇦🇲'],
['AO', '🇦🇴'],
['AQ', '🇦🇶'],
['AR', '🇦🇷'],
['AS', '🇦🇸'],
['AT', '🇦🇹'],
['AQ', '🇦🇶'],
['AU', '🇦🇺'],
['AW', '🇦🇼'],
['AX', '🇦🇽'],
['AZ', '🇦🇿'],
['BA', '🇧🇦'],
['BB', '🇧🇧'],
@@ -57,10 +58,11 @@ const cases = [
['BM', '🇧🇲'],
['BN', '🇧🇳'],
['BO', '🇧🇴'],
['BQ', '🇧🇶'],
['BR', '🇧🇷'],
['BS', '🇧🇸'],
['BT', '🇧🇹'],
['BQ', '🇧🇶'],
['BV', '🇧🇻'],
['BW', '🇧🇼'],
['BY', '🇧🇾'],
['BZ', '🇧🇿'],
@@ -76,19 +78,19 @@ const cases = [
['CM', '🇨🇲'],
['CN', '🇨🇳'],
['CO', '🇨🇴'],
['CP', '🇨🇵'],
['CR', '🇨🇷'],
['CU', '🇨🇺'],
['CV', '🇨🇻'],
['CW', '🇨🇼'],
['CX', '🇨🇽'],
['CY', '🇨🇾'],
['CZ', '🇨🇿'],
['DE', '🇩🇪'],
['DG', '🇩🇬'],
['DJ', '🇩🇯'],
['DK', '🇩🇰'],
['DM', '🇩🇲'],
['DO', '🇩🇴'],
['DZ', '🇩🇿'],
['EA', '🇪🇦'],
['EC', '🇪🇨'],
['EE', '🇪🇪'],
['EG', '🇪🇬'],
@@ -114,10 +116,11 @@ const cases = [
['GM', '🇬🇲'],
['GN', '🇬🇳'],
['GP', '🇬🇵'],
['GQ', '🇬🇶'],
['GR', '🇬🇷'],
['GS', '🇬🇸'],
['GT', '🇬🇹'],
['GQ', '🇬🇶'],
['GU', '🇬🇺'],
['GW', '🇬🇼'],
['GY', '🇬🇾'],
['HK', '🇭🇰'],
@@ -125,17 +128,17 @@ const cases = [
['HN', '🇭🇳'],
['HR', '🇭🇷'],
['HT', '🇭🇹'],
['IC', '🇮🇨'],
['HU', '🇭🇺'],
['ID', '🇮🇩'],
['IE', '🇮🇪'],
['IL', '🇮🇱'],
['IM', '🇮🇲'],
['IN', '🇮🇳'],
['IO', '🇮🇴'],
['IQ', '🇮🇶'],
['IR', '🇮🇷'],
['IS', '🇮🇸'],
['IT', '🇮🇹'],
['IQ', '🇮🇶'],
['JE', '🇯🇪'],
['JM', '🇯🇲'],
['JO', '🇯🇴'],
@@ -159,6 +162,8 @@ const cases = [
['LR', '🇱🇷'],
['LS', '🇱🇸'],
['LT', '🇱🇹'],
['LU', '🇱🇺'],
['LV', '🇱🇻'],
['LY', '🇱🇾'],
['MA', '🇲🇦'],
['MC', '🇲🇨'],
@@ -173,11 +178,14 @@ const cases = [
['MN', '🇲🇳'],
['MO', '🇲🇴'],
['MP', '🇲🇵'],
['MQ', '🇲🇶'],
['MR', '🇲🇷'],
['MS', '🇲🇸'],
['MT', '🇲🇹'],
['MQ', '🇲🇶'],
['MU', '🇲🇺'],
['MV', '🇲🇻'],
['MW', '🇲🇼'],
['MX', '🇲🇽'],
['MY', '🇲🇾'],
['MZ', '🇲🇿'],
['NA', '🇳🇦'],
@@ -190,6 +198,7 @@ const cases = [
['NO', '🇳🇴'],
['NP', '🇳🇵'],
['NR', '🇳🇷'],
['NU', '🇳🇺'],
['NZ', '🇳🇿'],
['OM', '🇴🇲'],
['PA', '🇵🇦'],
@@ -206,9 +215,11 @@ const cases = [
['PT', '🇵🇹'],
['PW', '🇵🇼'],
['PY', '🇵🇾'],
['QA', '🇶🇦'],
['RE', '🇷🇪'],
['RO', '🇷🇴'],
['RS', '🇷🇸'],
['RU', '🇷🇺'],
['RW', '🇷🇼'],
['SA', '🇸🇦'],
['SB', '🇸🇧'],
@@ -227,9 +238,10 @@ const cases = [
['SR', '🇸🇷'],
['SS', '🇸🇸'],
['ST', '🇸🇹'],
['SV', '🇸🇻'],
['SX', '🇸🇽'],
['SY', '🇸🇾'],
['SZ', '🇸🇿'],
['TA', '🇹🇦'],
['TC', '🇹🇨'],
['TD', '🇹🇩'],
['TF', '🇹🇫'],
@@ -243,10 +255,22 @@ const cases = [
['TO', '🇹🇴'],
['TR', '🇹🇷'],
['TT', '🇹🇹'],
['TV', '🇹🇻'],
['TW', '🇹🇼'],
['TZ', '🇹🇿'],
['QA', '🇶🇦'],
['UA', '🇺🇦'],
['UG', '🇺🇬'],
['UM', '🇺🇲'],
['US', '🇺🇸'],
['UY', '🇺🇾'],
['UZ', '🇺🇿'],
['VA', '🇻🇦'],
['VC', '🇻🇨'],
['VE', '🇻🇪'],
['VG', '🇻🇬'],
['VI', '🇻🇮'],
['VN', '🇻🇳'],
['VU', '🇻🇺'],
['WF', '🇼🇫'],
['WS', '🇼🇸'],
['YE', '🇾🇪'],
@@ -254,6 +278,23 @@ const cases = [
['ZA', '🇿🇦'],
['ZM', '🇿🇲'],
['ZW', '🇿🇼'],
// UK
['ENGLAND', '🏴󠁧󠁢󠁥󠁮󠁧󠁿'],
['GB-ENG', '🏴󠁧󠁢󠁥󠁮󠁧󠁿'],
['ENG', '🏴󠁧󠁢󠁥󠁮󠁧󠁿'],
['SCOTLAND', '🏴󠁧󠁢󠁳󠁣󠁴󠁿'],
['GB-SCT', '🏴󠁧󠁢󠁳󠁣󠁴󠁿'],
['SCT', '🏴󠁧󠁢󠁳󠁣󠁴󠁿'],
['WALES', '🏴󠁧󠁢󠁷󠁬󠁳󠁿'],
['GB-WLS', '🏴󠁧󠁢󠁷󠁬󠁳󠁿'],
['WLS', '🏴󠁧󠁢󠁷󠁬󠁳󠁿'],
['CYMRU', '🏴󠁧󠁢󠁷󠁬󠁳󠁿'],
['GB-CYM', '🏴󠁧󠁢󠁷󠁬󠁳󠁿'],
['CYM', '🏴󠁧󠁢󠁷󠁬󠁳󠁿'],
['NORTHERN IRELAND', '🇬🇧'],
['GB-NIR', '🇬🇧'],
['NIR', '🇬🇧'],
['UK', '🇬🇧'],
// unknown
['AA', FALLBACK_FLAG],
['XX', FALLBACK_FLAG],
+291 -11
View File
@@ -2,23 +2,303 @@ import compact from 'lodash/compact';
export const FALLBACK_FLAG = '🏳';
const KNOWN_CODES = `AC AD AE AF AG AI AL AM AO AR AS AT AQ AW AZ BA BB BD BE BF
BG BH BI BJ BL BM BN BO BR BS BT BQ BW BY BZ CA CC CD CF CG CH CI CK CL CM CN
CO CP CR CW CY CZ DE DG DJ DK DM DO DZ EA EC EE EG EH ER ES ET FI FJ FK FM FO
FR GA GB GD GE GF GG GH GI GL GM GN GP GR GS GT GQ GW GY HK HM HN HR HT IC ID
IE IL IM IN IO IR IS IT IQ JE JM JO JP KE KG KH KI KM KN KP KR KW KY KZ LA LB
LC LI LK LR LS LT LY MA MC MD ME MF MG MH MK ML MM MN MO MP MR MS MT MQ MW MY
MZ NA NC NE NF NG NI NL NO NP NR NZ OM PA PE PF PG PH PK PL PM PN PR PS PT PW
PY RE RO RS RW SA SB SC SD SE SG SH SI SJ SK SL SM SN SO SR SS ST SY SZ TA TC
TD TF TG TH TJ TK TL TM TN TO TR TT TW TZ QA VG WF WS YE YT ZA ZM ZW`;
const KNOWN_CODES = [
'AD',
'AE',
'AF',
'AG',
'AI',
'AL',
'AM',
'AO',
'AQ',
'AR',
'AS',
'AT',
'AU',
'AW',
'AX',
'AZ',
'BA',
'BB',
'BD',
'BE',
'BF',
'BG',
'BH',
'BI',
'BJ',
'BL',
'BM',
'BN',
'BO',
'BQ',
'BR',
'BS',
'BT',
'BV',
'BW',
'BY',
'BZ',
'CA',
'CC',
'CD',
'CF',
'CG',
'CH',
'CI',
'CK',
'CL',
'CM',
'CN',
'CO',
'CR',
'CU',
'CV',
'CW',
'CX',
'CY',
'CZ',
'DE',
'DJ',
'DK',
'DM',
'DO',
'DZ',
'EC',
'EE',
'EG',
'EH',
'ER',
'ES',
'ET',
'FI',
'FJ',
'FK',
'FM',
'FO',
'FR',
'GA',
'GB',
'GD',
'GE',
'GF',
'GG',
'GH',
'GI',
'GL',
'GM',
'GN',
'GP',
'GQ',
'GR',
'GS',
'GT',
'GU',
'GW',
'GY',
'HK',
'HM',
'HN',
'HR',
'HT',
'HU',
'ID',
'IE',
'IL',
'IM',
'IN',
'IO',
'IQ',
'IR',
'IS',
'IT',
'JE',
'JM',
'JO',
'JP',
'KE',
'KG',
'KH',
'KI',
'KM',
'KN',
'KP',
'KR',
'KW',
'KY',
'KZ',
'LA',
'LB',
'LC',
'LI',
'LK',
'LR',
'LS',
'LT',
'LU',
'LV',
'LY',
'MA',
'MC',
'MD',
'ME',
'MF',
'MG',
'MH',
'MK',
'ML',
'MM',
'MN',
'MO',
'MP',
'MQ',
'MR',
'MS',
'MT',
'MU',
'MV',
'MW',
'MX',
'MY',
'MZ',
'NA',
'NC',
'NE',
'NF',
'NG',
'NI',
'NL',
'NO',
'NP',
'NR',
'NU',
'NZ',
'OM',
'PA',
'PE',
'PF',
'PG',
'PH',
'PK',
'PL',
'PM',
'PN',
'PR',
'PS',
'PT',
'PW',
'PY',
'QA',
'RE',
'RO',
'RS',
'RU',
'RW',
'SA',
'SB',
'SC',
'SD',
'SE',
'SG',
'SH',
'SI',
'SJ',
'SK',
'SL',
'SM',
'SN',
'SO',
'SR',
'SS',
'ST',
'SV',
'SX',
'SY',
'SZ',
'TC',
'TD',
'TF',
'TG',
'TH',
'TJ',
'TK',
'TL',
'TM',
'TN',
'TO',
'TR',
'TT',
'TV',
'TW',
'TZ',
'UA',
'UG',
'UM',
'US',
'UY',
'UZ',
'VA',
'VC',
'VE',
'VG',
'VI',
'VN',
'VU',
'WF',
'WS',
'YE',
'YT',
'ZA',
'ZM',
'ZW',
];
export const countryCodeToFlagEmoji = (countryCode: string) => {
const ENGLAND = '🏴󠁧󠁢󠁥󠁮󠁧󠁿';
const SCOTLAND = '🏴󠁧󠁢󠁳󠁣󠁴󠁿';
const WALES = '🏴󠁧󠁢󠁷󠁬󠁳󠁿';
const NORTHERN_IRELAND = '🇬🇧';
const UK = new Map([
['ENGLAND', ENGLAND],
['GB-ENG', ENGLAND],
['ENG', ENGLAND],
['SCOTLAND', SCOTLAND],
['GB-SCT', SCOTLAND],
['SCT', SCOTLAND],
['WALES', WALES],
['GB-WLS', WALES],
['WLS', WALES],
['CYMRU', WALES],
['GB-CYM', WALES],
['CYM', WALES],
['NORTHERN IRELAND', NORTHERN_IRELAND],
['GB-NIR', NORTHERN_IRELAND],
['NIR', NORTHERN_IRELAND],
['UNITED KINGDOM', '🇬🇧'],
['UK', '🇬🇧'],
]);
const EU = new Map([['EU', '🇪🇺']]);
const getCode = (countryCode: string): string => {
const code = countryCode.trim().toUpperCase();
const known = compact(KNOWN_CODES.split(' ').map((ch) => ch.trim()));
return code;
};
export const countryCodeToFlagEmoji = (countryCode: string): string => {
const code = getCode(countryCode);
const known = compact(KNOWN_CODES.map((ch) => ch.trim()));
if (known.includes(code)) {
return code.replace(/./g, (char) =>
String.fromCodePoint(0x1f1a5 + char.toUpperCase().charCodeAt(0))
);
}
if (UK.has(code)) {
return UK.get(code) as string;
}
if (EU.has(code)) {
return EU.get(code) as string;
}
return FALLBACK_FLAG;
};
@@ -1,6 +1,6 @@
import { t } from '@vegaprotocol/i18n';
import { Link } from '@vegaprotocol/ui-toolkit';
import { useEnvironment } from '@vegaprotocol/environment';
import { EtherscanLink, useEnvironment } from '@vegaprotocol/environment';
import { EthTxStatus } from '../use-ethereum-transaction';
const ACTIVE_CLASSES = 'text-black dark:text-white';
@@ -62,14 +62,14 @@ export const TxRow = ({
}`}
>
<span>{t('Ethereum transaction complete')}</span>
<Link
href={`${ETHERSCAN_URL}/tx/${txHash}`}
title={t('View on Etherscan')}
className="text-vega-pink dark:text-vega-yellow"
target="_blank"
>
{t('View transaction on Etherscan')}
</Link>
{txHash && (
<EtherscanLink
tx={txHash}
className="text-vega-pink dark:text-vega-yellow"
>
{t('View transaction on Etherscan')}
</EtherscanLink>
)}
</p>
);
}
+11 -33
View File
@@ -9,14 +9,14 @@ import {
} from '@vegaprotocol/utils';
import { useBottomPlaceholder } from '@vegaprotocol/react-helpers';
import { t } from '@vegaprotocol/i18n';
import { Link, ButtonLink } from '@vegaprotocol/ui-toolkit';
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
import { AgGridDynamic as AgGrid } from '@vegaprotocol/datagrid';
import type {
TypedDataAgGrid,
VegaICellRendererParams,
VegaValueFormatterParams,
} from '@vegaprotocol/datagrid';
import { useEnvironment } from '@vegaprotocol/environment';
import { EtherscanLink } from '@vegaprotocol/environment';
import type { WithdrawalFieldsFragment } from './__generated__/Withdrawal';
import { useEthWithdrawApprovalsStore } from '@vegaprotocol/web3';
import * as Schema from '@vegaprotocol/types';
@@ -27,7 +27,6 @@ export const WithdrawalsTable = (
props: TypedDataAgGrid<WithdrawalFieldsFragment>
) => {
const gridRef = useRef<AgGridReact | null>(null);
const { ETHERSCAN_URL } = useEnvironment();
const createWithdrawApproval = useEthWithdrawApprovalsStore(
(store) => store.create
);
@@ -66,7 +65,6 @@ export const WithdrawalsTable = (
headerName={t('Recipient')}
field="details.receiverAddress"
cellRenderer="RecipientCell"
cellRendererParams={{ ethUrl: ETHERSCAN_URL }}
valueFormatter={({
value,
data,
@@ -126,7 +124,6 @@ export const WithdrawalsTable = (
complete: (withdrawal: WithdrawalFieldsFragment) => {
createWithdrawApproval(withdrawal);
},
ethUrl: ETHERSCAN_URL,
}}
cellRendererSelector={({
data,
@@ -160,20 +157,12 @@ export const CompleteCell = ({ data, complete }: CompleteCellProps) => {
export const EtherscanLinkCell = ({
value,
ethUrl,
}: VegaValueFormatterParams<WithdrawalFieldsFragment, 'txHash'> & {
ethUrl: string;
}) => {
}: VegaValueFormatterParams<WithdrawalFieldsFragment, 'txHash'>) => {
if (!value) return '-';
return (
<Link
title={t('View transaction on Etherscan')}
href={`${ethUrl}/tx/${value}`}
data-testid="etherscan-link"
target="_blank"
>
<EtherscanLink tx={value} data-testid="etherscan-link">
{truncateByChars(value)}
</Link>
</EtherscanLink>
);
};
@@ -193,28 +182,17 @@ export const StatusCell = ({ data }: { data: WithdrawalFieldsFragment }) => {
return <span>{t('Failed')}</span>;
};
export interface RecipientCellProps
extends VegaICellRendererParams<
WithdrawalFieldsFragment,
'details.receiverAddress'
> {
ethUrl: string;
}
const RecipientCell = ({
ethUrl,
value,
valueFormatted,
}: RecipientCellProps) => {
}: VegaICellRendererParams<
WithdrawalFieldsFragment,
'details.receiverAddress'
>) => {
return (
<Link
title={t('View on Etherscan (opens in a new tab)')}
href={`${ethUrl}/address/${value}`}
data-testid="etherscan-link"
target="_blank"
>
<EtherscanLink address={value} data-testid="etherscan-link">
{valueFormatted}
</Link>
</EtherscanLink>
);
};