feat(trading): eligibility active rewards (#6010)

Co-authored-by: Dariusz Majcherczyk <dariusz.majcherczyk@gmail.com>
This commit is contained in:
m.ray 2024-03-15 18:41:48 +02:00 committed by GitHub
parent 88f99031d1
commit 7b162104b6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 1258 additions and 858 deletions

View File

@ -41,10 +41,6 @@ import {
} from '../../lib/hooks/use-games';
import { useEpochInfoQuery } from '../../lib/hooks/__generated__/Epoch';
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
import {
ActiveRewardCard,
DispatchMetricInfo,
} from '../../components/rewards-container/active-rewards';
import { type MarketMap, useMarketsMapProvider } from '@vegaprotocol/markets';
import format from 'date-fns/format';
import {
@ -52,6 +48,10 @@ import {
isScopedToTeams,
useRewards,
} from '../../lib/hooks/use-rewards';
import {
ActiveRewardCard,
DispatchMetricInfo,
} from '../../components/rewards-container/reward-card';
export const CompetitionsTeam = () => {
const t = useT();

View File

@ -1,6 +1,9 @@
import { ActiveRewardCard } from '../rewards-container/active-rewards';
import { useT } from '../../lib/use-t';
import { type EnrichedRewardTransfer } from '../../lib/hooks/use-rewards';
import { useVegaWallet } from '@vegaprotocol/wallet-react';
import { useStakeAvailable } from '../../lib/hooks/use-stake-available';
import { useMyTeam } from '../../lib/hooks/use-my-team';
import { ActiveRewardCard } from '../rewards-container/reward-card';
export const GamesContainer = ({
data,
@ -10,6 +13,19 @@ export const GamesContainer = ({
currentEpoch: number;
}) => {
const t = useT();
const { pubKey } = useVegaWallet();
const { team } = useMyTeam();
const { stakeAvailable, isEligible, requiredStake } = useStakeAvailable();
const requirements = pubKey
? {
isEligible,
stakeAvailable,
requiredStake,
team,
pubKey,
}
: undefined;
if (!data || data.length === 0) {
return (
@ -35,6 +51,7 @@ export const GamesContainer = ({
key={i}
transferNode={game}
currentEpoch={currentEpoch}
requirements={requirements}
/>
);
})}

View File

@ -1,5 +1,5 @@
import { render, screen } from '@testing-library/react';
import { ActiveRewardCard, applyFilter } from './active-rewards';
import { applyFilter } from './active-rewards';
import {
AccountType,
AssetStatus,
@ -11,6 +11,17 @@ import {
type Transfer,
} from '@vegaprotocol/types';
import { type EnrichedRewardTransfer } from '../../lib/hooks/use-rewards';
import { ActiveRewardCard } from './reward-card';
jest.mock('../../lib/hooks/__generated__/Rewards', () => ({
useTWAPQuery: () => ({
data: {
timeWeightedNotionalPosition: {
timeWeightedNotionalPosition: '1.00',
},
},
}),
}));
describe('ActiveRewards', () => {
const reward: EnrichedRewardTransfer = {
@ -71,7 +82,7 @@ describe('ActiveRewards', () => {
};
it('renders with valid props', () => {
render(<ActiveRewardCard transferNode={reward} currentEpoch={115432} />);
render(<ActiveRewardCard transferNode={reward} currentEpoch={115500} />);
expect(
screen.getByText(/Liquidity provision fees received/i)

View File

@ -1,57 +1,25 @@
import { useT } from '../../lib/use-t';
import { addDecimalsFormatNumber, formatNumber } from '@vegaprotocol/utils';
import classNames from 'classnames';
import {
type VegaIconSize,
Tooltip,
VegaIcon,
VegaIconNames,
TradingInput,
TinyScroll,
truncateMiddle,
} from '@vegaprotocol/ui-toolkit';
import {
type TransferNode,
DistributionStrategyDescriptionMapping,
DistributionStrategyMapping,
EntityScope,
EntityScopeMapping,
DispatchMetric,
DispatchMetricDescription,
DispatchMetricLabels,
EntityScopeLabelMapping,
MarketState,
type DispatchStrategy,
IndividualScopeMapping,
IndividualScopeDescriptionMapping,
AccountType,
DistributionStrategy,
IndividualScope,
type Asset,
} from '@vegaprotocol/types';
import { Card } from '../card/card';
import { type ReactNode, useState } from 'react';
import {
type AssetFieldsFragment,
type BasicAssetDetails,
} from '@vegaprotocol/assets';
import { useState } from 'react';
import { type AssetFieldsFragment } from '@vegaprotocol/assets';
import { type MarketFieldsFragment } from '@vegaprotocol/markets';
import {
type EnrichedRewardTransfer,
useRewards,
} from '../../lib/hooks/use-rewards';
import compact from 'lodash/compact';
enum CardColour {
BLUE = 'BLUE',
GREEN = 'GREEN',
GREY = 'GREY',
ORANGE = 'ORANGE',
PINK = 'PINK',
PURPLE = 'PURPLE',
WHITE = 'WHITE',
YELLOW = 'YELLOW',
}
import { useRewards } from '../../lib/hooks/use-rewards';
import { useMyTeam } from '../../lib/hooks/use-my-team';
import { useVegaWallet } from '@vegaprotocol/wallet-react';
import { useStakeAvailable } from '../../lib/hooks/use-stake-available';
import { ActiveRewardCard } from './reward-card';
export type Filter = {
searchTerm: string;
@ -110,6 +78,18 @@ export const ActiveRewards = ({ currentEpoch }: { currentEpoch: number }) => {
const { data } = useRewards({
onlyActive: true,
});
const { pubKey } = useVegaWallet();
const { team } = useMyTeam();
const { stakeAvailable, isEligible, requiredStake } = useStakeAvailable();
const requirements = pubKey
? {
isEligible,
stakeAvailable,
requiredStake,
team,
pubKey,
}
: undefined;
const [filter, setFilter] = useState<Filter>({
searchTerm: '',
@ -148,719 +128,10 @@ export const ActiveRewards = ({ currentEpoch }: { currentEpoch: number }) => {
key={i}
transferNode={node}
currentEpoch={currentEpoch}
requirements={requirements}
/>
))}
</TinyScroll>
</Card>
);
};
type ActiveRewardCardProps = {
transferNode: EnrichedRewardTransfer;
currentEpoch: number;
};
export const ActiveRewardCard = ({
transferNode,
currentEpoch,
}: ActiveRewardCardProps) => {
// don't display the cards that are scoped to not trading markets
const marketSettled = transferNode.markets?.filter(
(m) =>
m?.state &&
[
MarketState.STATE_TRADING_TERMINATED,
MarketState.STATE_SETTLED,
MarketState.STATE_CANCELLED,
MarketState.STATE_CLOSED,
].includes(m.state)
);
// hide the card if all of the markets are being marked as e.g. settled
if (
marketSettled?.length === transferNode.markets?.length &&
Boolean(transferNode.markets && transferNode.markets.length > 0)
) {
return null;
}
if (
!transferNode.transfer.kind.dispatchStrategy &&
transferNode.transfer.toAccountType ===
AccountType.ACCOUNT_TYPE_GLOBAL_REWARD
) {
return (
<StakingRewardCard
colour={CardColour.WHITE}
rewardAmount={addDecimalsFormatNumber(
transferNode.transfer.amount,
transferNode.transfer.asset?.decimals || 0,
6
)}
rewardAsset={transferNode.transfer.asset || undefined}
endsIn={
transferNode.transfer.kind.endEpoch != null
? transferNode.transfer.kind.endEpoch - currentEpoch
: undefined
}
/>
);
}
let colour =
DispatchMetricColourMap[
transferNode.transfer.kind.dispatchStrategy.dispatchMetric
];
// grey out of any of the markets is suspended or
// if the asset is not currently traded on any of the active markets
const marketSuspended =
transferNode.markets?.filter(
(m) =>
m?.state === MarketState.STATE_SUSPENDED ||
m?.state === MarketState.STATE_SUSPENDED_VIA_GOVERNANCE
).length === transferNode.markets?.length &&
Boolean(transferNode.markets && transferNode.markets.length > 0);
if (marketSuspended || !transferNode.isAssetTraded) {
colour = CardColour.GREY;
}
return (
<RewardCard
colour={colour}
rewardAmount={addDecimalsFormatNumber(
transferNode.transfer.amount,
transferNode.transfer.asset?.decimals || 0,
6
)}
rewardAsset={transferNode.dispatchAsset}
transferAsset={transferNode.transfer.asset || undefined}
endsIn={
transferNode.transfer.kind.endEpoch != null
? transferNode.transfer.kind.endEpoch - currentEpoch
: undefined
}
dispatchStrategy={transferNode.transfer.kind.dispatchStrategy}
dispatchMetricInfo={<DispatchMetricInfo reward={transferNode} />}
/>
);
};
const RewardCard = ({
colour,
rewardAmount,
rewardAsset,
transferAsset,
vegaAsset,
dispatchStrategy,
endsIn,
dispatchMetricInfo,
}: {
colour: CardColour;
rewardAmount: string;
/** The asset linked to the dispatch strategy via `dispatchMetricAssetId` property. */
rewardAsset?: BasicAssetDetails;
/** The VEGA asset details, required to format the min staking amount. */
transferAsset?: Asset | undefined;
/** The VEGA asset details, required to format the min staking amount. */
vegaAsset?: BasicAssetDetails;
/** The transfer's dispatch strategy. */
dispatchStrategy: DispatchStrategy;
/** The number of epochs until the transfer stops. */
endsIn?: number;
dispatchMetricInfo?: ReactNode;
}) => {
const t = useT();
return (
<div>
<div
className={classNames(
'bg-gradient-to-r col-span-full p-0.5 lg:col-auto h-full',
'rounded-lg',
CardColourStyles[colour].gradientClassName
)}
data-testid="active-rewards-card"
>
<div
className={classNames(
CardColourStyles[colour].mainClassName,
'bg-gradient-to-b bg-vega-clight-800 dark:bg-vega-cdark-800 h-full w-full rounded-md p-4 flex flex-col gap-4'
)}
>
<div className="flex justify-between gap-4">
{/** ENTITY SCOPE */}
<div className="flex flex-col gap-2 items-center text-center">
<EntityIcon entityScope={dispatchStrategy.entityScope} />
{dispatchStrategy.entityScope && (
<span className="text-muted text-xs" data-testid="entity-scope">
{EntityScopeLabelMapping[dispatchStrategy.entityScope] ||
t('Unspecified')}
</span>
)}
</div>
{/** AMOUNT AND DISTRIBUTION STRATEGY */}
<div className="flex flex-col gap-2 items-center text-center">
{/** AMOUNT */}
<h3 className="flex flex-col gap-1 text-2xl shrink-1 text-center">
<span className="font-glitch" data-testid="reward-value">
{rewardAmount}
</span>
<span className="font-alpha" data-testid="reward-asset">
{transferAsset?.symbol || ''}
</span>
</h3>
{/** DISTRIBUTION STRATEGY */}
<Tooltip
description={t(
DistributionStrategyDescriptionMapping[
dispatchStrategy.distributionStrategy
]
)}
underline={true}
>
<span className="text-xs" data-testid="distribution-strategy">
{
DistributionStrategyMapping[
dispatchStrategy.distributionStrategy
]
}
</span>
</Tooltip>
</div>
{/** DISTRIBUTION DELAY */}
<div className="flex flex-col gap-2 items-center text-center">
<CardIcon
iconName={VegaIconNames.LOCK}
tooltip={t(
'Number of epochs after distribution to delay vesting of rewards by'
)}
/>
<span
className="text-muted text-xs whitespace-nowrap"
data-testid="locked-for"
>
{t('numberEpochs', '{{count}} epochs', {
count: dispatchStrategy.lockPeriod,
})}
</span>
</div>
</div>
<span className="border-[0.5px] dark:border-vega-cdark-500 border-vega-clight-500" />
{/** DISPATCH METRIC */}
{dispatchMetricInfo ? (
dispatchMetricInfo
) : (
<span data-testid="dispatch-metric-info">
{DispatchMetricLabels[dispatchStrategy.dispatchMetric]}
</span>
)}
<div className="flex items-center gap-8 flex-wrap">
{/** ENDS IN */}
{endsIn != null && (
<span className="flex flex-col">
<span className="text-muted text-xs">{t('Ends in')} </span>
<span data-testid="ends-in" data-endsin={endsIn}>
{endsIn >= 0
? t('numberEpochs', '{{count}} epochs', {
count: endsIn,
})
: t('Ended')}
</span>
</span>
)}
{/** WINDOW LENGTH */}
<span className="flex flex-col">
<span className="text-muted text-xs">{t('Assessed over')}</span>
<span data-testid="assessed-over">
{t('numberEpochs', '{{count}} epochs', {
count: dispatchStrategy.windowLength,
})}
</span>
</span>
{/** CAPPED AT */}
{dispatchStrategy.capRewardFeeMultiple && (
<span className="flex flex-col">
<span className="text-muted text-xs">{t('Capped at')}</span>
<Tooltip
description={t(
'Reward will be capped at {{capRewardFeeMultiple}} X of taker fees paid in the epoch',
{
capRewardFeeMultiple:
dispatchStrategy.capRewardFeeMultiple,
}
)}
>
<span data-testid="cappedAt">
x{dispatchStrategy.capRewardFeeMultiple}
</span>
</Tooltip>
</span>
)}
</div>
{/** DISPATCH METRIC DESCRIPTION */}
{dispatchStrategy?.dispatchMetric && (
<p className="text-muted text-sm h-[3rem]">
{t(DispatchMetricDescription[dispatchStrategy?.dispatchMetric])}
</p>
)}
<span className="border-[0.5px] dark:border-vega-cdark-500 border-vega-clight-500" />
{/** REQUIREMENTS */}
{dispatchStrategy && (
<RewardRequirements
dispatchStrategy={dispatchStrategy}
rewardAsset={rewardAsset}
vegaAsset={vegaAsset}
/>
)}
</div>
</div>
</div>
);
};
const StakingRewardCard = ({
colour,
rewardAmount,
rewardAsset,
endsIn,
}: {
colour: CardColour;
rewardAmount: string;
/** The asset linked to the dispatch strategy via `dispatchMetricAssetId` property. */
rewardAsset?: Asset;
/** The number of epochs until the transfer stops. */
endsIn?: number;
/** The VEGA asset details, required to format the min staking amount. */
vegaAsset?: BasicAssetDetails;
}) => {
const t = useT();
return (
<div>
<div
className={classNames(
'bg-gradient-to-r col-span-full p-0.5 lg:col-auto h-full',
'rounded-lg',
CardColourStyles[colour].gradientClassName
)}
data-testid="active-rewards-card"
>
<div
className={classNames(
CardColourStyles[colour].mainClassName,
'bg-gradient-to-b bg-vega-clight-800 dark:bg-vega-cdark-800 h-full w-full rounded-md p-4 flex flex-col gap-4'
)}
>
<div className="flex justify-between gap-4">
{/** ENTITY SCOPE */}
<div className="flex flex-col gap-2 items-center text-center">
<EntityIcon entityScope={EntityScope.ENTITY_SCOPE_INDIVIDUALS} />
{
<span className="text-muted text-xs" data-testid="entity-scope">
{EntityScopeLabelMapping[
EntityScope.ENTITY_SCOPE_INDIVIDUALS
] || t('Unspecified')}
</span>
}
</div>
{/** AMOUNT AND DISTRIBUTION STRATEGY */}
<div className="flex flex-col gap-2 items-center text-center">
{/** AMOUNT */}
<h3 className="flex flex-col gap-1 text-2xl shrink-1 text-center">
<span className="font-glitch" data-testid="reward-value">
{rewardAmount}
</span>
<span className="font-alpha">{rewardAsset?.symbol || ''}</span>
</h3>
{/** DISTRIBUTION STRATEGY */}
<Tooltip
description={t(
DistributionStrategyDescriptionMapping[
DistributionStrategy.DISTRIBUTION_STRATEGY_PRO_RATA
]
)}
underline={true}
>
<span className="text-xs" data-testid="distribution-strategy">
{
DistributionStrategyMapping[
DistributionStrategy.DISTRIBUTION_STRATEGY_PRO_RATA
]
}
</span>
</Tooltip>
</div>
{/** DISTRIBUTION DELAY */}
<div className="flex flex-col gap-2 items-center text-center">
<CardIcon
iconName={VegaIconNames.LOCK}
tooltip={t(
'Number of epochs after distribution to delay vesting of rewards by'
)}
/>
<span
className="text-muted text-xs whitespace-nowrap"
data-testid="locked-for"
>
{t('numberEpochs', '{{count}} epochs', {
count: 0,
})}
</span>
</div>
</div>
<span className="border-[0.5px] dark:border-vega-cdark-500 border-vega-clight-500" />
{/** DISPATCH METRIC */}
{
<span data-testid="dispatch-metric-info">
{t('Staking rewards')}
</span>
}
<div className="flex items-center gap-8 flex-wrap">
{/** ENDS IN */}
{endsIn != null && (
<span className="flex flex-col">
<span className="text-muted text-xs">{t('Ends in')} </span>
<span data-testid="ends-in" data-endsin={endsIn}>
{endsIn >= 0
? t('numberEpochs', '{{count}} epochs', {
count: endsIn,
})
: t('Ended')}
</span>
</span>
)}
{/** WINDOW LENGTH */}
<span className="flex flex-col">
<span className="text-muted text-xs">{t('Assessed over')}</span>
<span data-testid="assessed-over">
{t('numberEpochs', '{{count}} epochs', {
count: 1,
})}
</span>
</span>
</div>
{/** DISPATCH METRIC DESCRIPTION */}
{
<p className="text-muted text-sm h-[3rem]">
{t(
'Global staking reward for staking $VEGA on the network via the Governance app'
)}
</p>
}
<span className="border-[0.5px] dark:border-vega-cdark-500 border-vega-clight-500" />
{/** REQUIREMENTS */}
<dl className="flex justify-between flex-wrap items-center gap-3 text-xs">
<div className="flex flex-col gap-1">
<dt className="flex items-center gap-1 text-muted">
{t('Team scope')}
</dt>
<dd className="flex items-center gap-1" data-testid="scope">
<Tooltip
description={
IndividualScopeDescriptionMapping[
IndividualScope.INDIVIDUAL_SCOPE_ALL
]
}
>
<span>{t('Individual')}</span>
</Tooltip>
</dd>
</div>
<div className="flex flex-col gap-1">
<dt className="flex items-center gap-1 text-muted">
{t('Staked VEGA')}
</dt>
<dd
className="flex items-center gap-1"
data-testid="staking-requirement"
>
{formatNumber(1, 2)}
</dd>
</div>
<div className="flex flex-col gap-1">
<dt className="flex items-center gap-1 text-muted">
{t('Average position')}
</dt>
<dd
className="flex items-center gap-1"
data-testid="average-position"
>
{formatNumber(0, 2)}
</dd>
</div>
</dl>
</div>
</div>
</div>
);
};
export const DispatchMetricInfo = ({
reward,
}: {
reward: EnrichedRewardTransfer;
}) => {
const t = useT();
const dispatchStrategy = reward.transfer.kind.dispatchStrategy;
const marketNames = compact(
reward.markets?.map((m) => m.tradableInstrument.instrument.name)
);
let additionalDispatchMetricInfo = null;
// if asset found then display asset symbol
if (reward.dispatchAsset) {
additionalDispatchMetricInfo = <span>{reward.dispatchAsset.symbol}</span>;
}
// but if scoped to only one market then display market name
if (marketNames.length === 1) {
additionalDispatchMetricInfo = <span>{marketNames[0]}</span>;
}
// or if scoped to many markets then indicate it's scoped to "specific markets"
if (marketNames.length > 1) {
additionalDispatchMetricInfo = (
<Tooltip description={marketNames}>
<span>{t('Specific markets')}</span>
</Tooltip>
);
}
return (
<span data-testid="dispatch-metric-info">
{DispatchMetricLabels[dispatchStrategy.dispatchMetric]}
{additionalDispatchMetricInfo != null && (
<> {additionalDispatchMetricInfo}</>
)}
</span>
);
};
const RewardRequirements = ({
dispatchStrategy,
rewardAsset,
vegaAsset,
}: {
dispatchStrategy: DispatchStrategy;
rewardAsset?: BasicAssetDetails;
vegaAsset?: BasicAssetDetails;
}) => {
const t = useT();
const entityLabel = EntityScopeLabelMapping[dispatchStrategy.entityScope];
return (
<dl className="flex justify-between flex-wrap items-center gap-3 text-xs">
<div className="flex flex-col gap-1">
<dt className="flex items-center gap-1 text-muted">
{entityLabel
? t('{{entity}} scope', {
entity: entityLabel,
})
: t('Scope')}
</dt>
<dd className="flex items-center gap-1" data-testid="scope">
<RewardEntityScope dispatchStrategy={dispatchStrategy} />
</dd>
</div>
<div className="flex flex-col gap-1">
<dt className="flex items-center gap-1 text-muted">
{t('Staked VEGA')}
</dt>
<dd
className="flex items-center gap-1"
data-testid="staking-requirement"
>
{addDecimalsFormatNumber(
dispatchStrategy?.stakingRequirement || 0,
vegaAsset?.decimals || 18
)}
</dd>
</div>
<div className="flex flex-col gap-1">
<dt className="flex items-center gap-1 text-muted">
{t('Average position')}
</dt>
<dd className="flex items-center gap-1" data-testid="average-position">
{addDecimalsFormatNumber(
dispatchStrategy?.notionalTimeWeightedAveragePositionRequirement ||
0,
rewardAsset?.decimals || 0
)}
</dd>
</div>
</dl>
);
};
const RewardEntityScope = ({
dispatchStrategy,
}: {
dispatchStrategy: DispatchStrategy;
}) => {
const t = useT();
if (dispatchStrategy.entityScope === EntityScope.ENTITY_SCOPE_TEAMS) {
return (
<Tooltip
description={
dispatchStrategy.teamScope?.length ? (
<div className="text-xs">
<p className="mb-1">{t('Eligible teams')}</p>
<ul>
{dispatchStrategy.teamScope.map((teamId) => {
if (!teamId) return null;
return <li key={teamId}>{truncateMiddle(teamId)}</li>;
})}
</ul>
</div>
) : (
t('All teams are eligible')
)
}
>
<span>
{dispatchStrategy.teamScope?.length
? t('Some teams')
: t('All teams')}
</span>
</Tooltip>
);
}
if (
dispatchStrategy.entityScope === EntityScope.ENTITY_SCOPE_INDIVIDUALS &&
dispatchStrategy.individualScope
) {
return (
<Tooltip
description={
IndividualScopeDescriptionMapping[dispatchStrategy.individualScope]
}
>
<span>{IndividualScopeMapping[dispatchStrategy.individualScope]}</span>
</Tooltip>
);
}
return t('Unspecified');
};
const CardColourStyles: Record<
CardColour,
{ gradientClassName: string; mainClassName: string }
> = {
[CardColour.BLUE]: {
gradientClassName: 'from-vega-blue-500 to-vega-green-400',
mainClassName: 'from-vega-blue-400 dark:from-vega-blue-600 to-20%',
},
[CardColour.GREEN]: {
gradientClassName: 'from-vega-green-500 to-vega-yellow-500',
mainClassName: 'from-vega-green-400 dark:from-vega-green-600 to-20%',
},
[CardColour.GREY]: {
gradientClassName: 'from-vega-cdark-500 to-vega-clight-200',
mainClassName: 'from-vega-cdark-400 dark:from-vega-cdark-600 to-20%',
},
[CardColour.ORANGE]: {
gradientClassName: 'from-vega-orange-500 to-vega-pink-400',
mainClassName: 'from-vega-orange-400 dark:from-vega-orange-600 to-20%',
},
[CardColour.PINK]: {
gradientClassName: 'from-vega-pink-500 to-vega-purple-400',
mainClassName: 'from-vega-pink-400 dark:from-vega-pink-600 to-20%',
},
[CardColour.PURPLE]: {
gradientClassName: 'from-vega-purple-500 to-vega-blue-400',
mainClassName: 'from-vega-purple-400 dark:from-vega-purple-600 to-20%',
},
[CardColour.WHITE]: {
gradientClassName:
'from-vega-clight-600 dark:from-vega-clight-900 to-vega-yellow-500 dark:to-vega-yellow-400',
mainClassName: 'from-white dark:from-vega-clight-100 to-20%',
},
[CardColour.YELLOW]: {
gradientClassName: 'from-vega-yellow-500 to-vega-orange-400',
mainClassName: 'from-vega-yellow-400 dark:from-vega-yellow-600 to-20%',
},
};
const DispatchMetricColourMap: Record<DispatchMetric, CardColour> = {
// Liquidity provision fees received
[DispatchMetric.DISPATCH_METRIC_LP_FEES_RECEIVED]: CardColour.BLUE,
// Price maker fees paid
[DispatchMetric.DISPATCH_METRIC_MAKER_FEES_PAID]: CardColour.PINK,
// Price maker fees earned
[DispatchMetric.DISPATCH_METRIC_MAKER_FEES_RECEIVED]: CardColour.GREEN,
// Total market value
[DispatchMetric.DISPATCH_METRIC_MARKET_VALUE]: CardColour.WHITE,
// Average position
[DispatchMetric.DISPATCH_METRIC_AVERAGE_POSITION]: CardColour.ORANGE,
// Relative return
[DispatchMetric.DISPATCH_METRIC_RELATIVE_RETURN]: CardColour.PURPLE,
// Return volatility
[DispatchMetric.DISPATCH_METRIC_RETURN_VOLATILITY]: CardColour.YELLOW,
// Validator ranking
[DispatchMetric.DISPATCH_METRIC_VALIDATOR_RANKING]: CardColour.WHITE,
};
const CardIcon = ({
size = 18,
iconName,
tooltip,
}: {
size?: VegaIconSize;
iconName: VegaIconNames;
tooltip: string;
}) => {
return (
<Tooltip description={<span>{tooltip}</span>}>
<span className="flex items-center p-2 rounded-full border border-gray-600">
<VegaIcon name={iconName} size={size} />
</span>
</Tooltip>
);
};
const EntityScopeIconMap: Record<EntityScope, VegaIconNames> = {
[EntityScope.ENTITY_SCOPE_TEAMS]: VegaIconNames.TEAM,
[EntityScope.ENTITY_SCOPE_INDIVIDUALS]: VegaIconNames.MAN,
};
const EntityIcon = ({
entityScope,
size = 18,
}: {
entityScope: EntityScope;
size?: VegaIconSize;
}) => {
return (
<Tooltip
description={
entityScope ? <span>{EntityScopeMapping[entityScope]}</span> : undefined
}
>
<span className="flex items-center p-2 rounded-full border border-gray-600">
<VegaIcon
name={EntityScopeIconMap[entityScope] || VegaIconNames.QUESTION_MARK}
size={size}
/>
</span>
</Tooltip>
);
};

File diff suppressed because it is too large Load Diff

View File

@ -304,7 +304,7 @@ export const RewardsContainer = () => {
);
};
type VestingBalances = NonNullable<
export type VestingBalances = NonNullable<
RewardsPageQuery['party']
>['vestingBalancesSummary'];

View File

@ -10,7 +10,8 @@ from typing import Generator, Tuple
from wallet_config import PARTY_A, PARTY_B, PARTY_C, PARTY_D, MM_WALLET, MM_WALLET2
COMPETITIONS_URL = "/#/competitions/"
TEAMS_URL = "/#/competitions/teams/"
TEAMS_URL = "/#/competitions/teams/"
@pytest.fixture(scope="module")
def setup_environment(request, browser) -> Generator[Tuple[Page, VegaServiceNull, dict], None, None]:
@ -19,6 +20,7 @@ def setup_environment(request, browser) -> Generator[Tuple[Page, VegaServiceNull
setup_data = setup_teams_and_games(vega_instance)
yield vega_instance, setup_data
@pytest.fixture(scope="module")
def competitions_page(setup_environment, browser, request) -> Generator[Tuple[Page, str, VegaServiceNull], None, None]:
vega_instance, setup_data = setup_environment
@ -29,6 +31,7 @@ def competitions_page(setup_environment, browser, request) -> Generator[Tuple[Pa
page.goto(COMPETITIONS_URL)
yield page, team_name, vega_instance
@pytest.fixture(scope="module")
def team_page(setup_environment, browser, request) -> Generator[Tuple[Page, str, VegaServiceNull], None, None]:
vega_instance, setup_data = setup_environment
@ -40,6 +43,7 @@ def team_page(setup_environment, browser, request) -> Generator[Tuple[Page, str,
page.goto(f"{TEAMS_URL}{team_id}")
yield page, team_name, team_id, vega_instance
def setup_teams_and_games(vega: VegaServiceNull):
tDAI_market = setup_continuous_market(vega, custom_quantum=100000)
tDAI_asset_id = vega.find_asset_id(symbol="tDAI")
@ -53,18 +57,17 @@ def setup_teams_and_games(vega: VegaServiceNull):
vega.update_network_parameter(
MM_WALLET.name, parameter="reward.asset", new_value=tDAI_asset_id
)
next_epoch(vega=vega)
vega.create_asset(
MM_WALLET.name,
name="VEGA",
symbol="VEGA",
decimals=5,
max_faucet_amount=1e10,
quantum=100000,
)
MM_WALLET.name,
name="VEGA",
symbol="VEGA",
decimals=5,
max_faucet_amount=1e10,
quantum=100000,
)
vega.wait_fn(1)
vega.wait_for_total_catchup()
VEGA_asset_id = vega.find_asset_id(symbol="VEGA")
@ -233,7 +236,7 @@ def create_team(vega: VegaServiceNull):
return team_name
def test_team_page_games_table(team_page:Tuple[Page, str, str, VegaServiceNull]):
def test_team_page_games_table(team_page: Tuple[Page, str, str, VegaServiceNull]):
page, team_name, team_id, vega = team_page
page.get_by_test_id("games-toggle").click()
expect(page.get_by_test_id("games-toggle")).to_have_text("Results (10)")
@ -248,7 +251,7 @@ def test_team_page_games_table(team_page:Tuple[Page, str, str, VegaServiceNull])
expect(page.get_by_test_id("participatingMembers-0")).to_have_text("3")
def test_team_page_members_table(team_page:Tuple[Page, str, str, VegaServiceNull]):
def test_team_page_members_table(team_page: Tuple[Page, str, str, VegaServiceNull]):
page, team_name, team_id, vega = team_page
page.get_by_test_id("members-toggle").click()
expect(page.get_by_test_id("members-toggle")).to_have_text("Members (4)")
@ -257,7 +260,7 @@ def test_team_page_members_table(team_page:Tuple[Page, str, str, VegaServiceNull
expect(page.get_by_test_id("joinedAtEpoch-0")).to_have_text("9")
def test_team_page_headline(team_page:Tuple[Page, str, str, VegaServiceNull]):
def test_team_page_headline(team_page: Tuple[Page, str, str, VegaServiceNull]):
page, team_name, team_id, vega = team_page
expect(page.get_by_test_id("team-name")).to_have_text(team_name)
expect(page.get_by_test_id("members-count-stat")).to_have_text("4")
@ -270,7 +273,7 @@ def test_team_page_headline(team_page:Tuple[Page, str, str, VegaServiceNull]):
expect(page.get_by_test_id("rewards-paid-stat")).to_have_text("500")
def test_switch_teams(team_page:Tuple[Page, str, str, VegaServiceNull]):
def test_switch_teams(team_page: Tuple[Page, str, str, VegaServiceNull]):
page, team_name, team_id, vega = team_page
page.get_by_test_id("switch-team-button").click()
page.get_by_test_id("confirm-switch-button").click()
@ -282,7 +285,7 @@ def test_switch_teams(team_page:Tuple[Page, str, str, VegaServiceNull]):
expect(page.get_by_test_id("members-count-stat")).to_have_text("5")
def test_leaderboard(competitions_page:Tuple[Page, str, VegaServiceNull]):
def test_leaderboard(competitions_page: Tuple[Page, str, VegaServiceNull]):
page, team_name, vega = competitions_page
page.reload()
expect(
@ -302,7 +305,7 @@ def test_leaderboard(competitions_page:Tuple[Page, str, VegaServiceNull]):
expect(page.get_by_test_id("volume-0")).to_have_text("0")
def test_game_card(competitions_page:Tuple[Page, str, VegaServiceNull]):
def test_game_card(competitions_page: Tuple[Page, str, VegaServiceNull]):
page, team_name, vega = competitions_page
expect(page.get_by_test_id("active-rewards-card")).to_have_count(1)
game_1 = page.get_by_test_id("active-rewards-card").first
@ -311,17 +314,19 @@ def test_game_card(competitions_page:Tuple[Page, str, VegaServiceNull]):
expect(game_1.get_by_test_id("locked-for")).to_have_text("1 epoch")
expect(game_1.get_by_test_id("reward-value")).to_have_text("100.00")
expect(game_1.get_by_test_id("reward-asset")).to_have_text("VEGA")
expect(game_1.get_by_test_id("distribution-strategy")).to_have_text("Pro rata")
expect(game_1.get_by_test_id("distribution-strategy")
).to_have_text("Pro rata")
expect(game_1.get_by_test_id("dispatch-metric-info")).to_have_text(
"Price maker fees paid • tDAI"
)
expect(game_1.get_by_test_id("assessed-over")).to_have_text("15 epochs")
expect(game_1.get_by_test_id("scope")).to_have_text("All teams")
expect(game_1.get_by_test_id("staking-requirement")).to_have_text("0.00")
expect(game_1.get_by_test_id("average-position")).to_have_text("0.00")
page.pause()
expect(game_1.get_by_test_id("scope")).to_have_text("Eligible")
expect(game_1.get_by_test_id("staking-requirement")).to_have_text("-")
expect(game_1.get_by_test_id("average-position")).to_have_text("-")
def test_create_team(competitions_page:Tuple[Page, str, VegaServiceNull]):
def test_create_team(competitions_page: Tuple[Page, str, VegaServiceNull]):
page, team_id, vega = competitions_page
change_keys(page, vega, MM_WALLET2.name)
page.get_by_test_id("create-public-team-button").click()

View File

@ -111,6 +111,22 @@ query ActiveRewards(
}
}
query TWAP($partyId: ID!, $assetId: ID!, $gameId: ID!, $epochSeq: Int) {
timeWeightedNotionalPosition(
partyId: $partyId
gameId: $gameId
assetId: $assetId
epochSeq: $epochSeq
) {
assetId
partyId
gameId
timeWeightedNotionalPosition
lastUpdated
epoch
}
}
query RewardsHistory(
$partyId: ID!
$epochRewardSummariesPagination: Pagination

View File

@ -20,6 +20,16 @@ export type ActiveRewardsQueryVariables = Types.Exact<{
export type ActiveRewardsQuery = { __typename?: 'Query', transfersConnection?: { __typename?: 'TransferConnection', edges?: Array<{ __typename?: 'TransferEdge', node: { __typename?: 'TransferNode', transfer: { __typename?: 'Transfer', amount: string, id: string, from: string, fromAccountType: Types.AccountType, to: string, toAccountType: Types.AccountType, reference?: string | null, status: Types.TransferStatus, timestamp: any, gameId?: string | null, reason?: string | null, asset?: { __typename?: 'Asset', id: string, symbol: string, decimals: number, name: string, quantum: string, status: Types.AssetStatus } | null, kind: { __typename?: 'OneOffGovernanceTransfer' } | { __typename?: 'OneOffTransfer' } | { __typename?: 'RecurringGovernanceTransfer' } | { __typename?: 'RecurringTransfer', startEpoch: number, endEpoch?: number | null, dispatchStrategy?: { __typename?: 'DispatchStrategy', capRewardFeeMultiple?: string | null, dispatchMetric: Types.DispatchMetric, dispatchMetricAssetId: string, marketIdsInScope?: Array<string> | null, entityScope: Types.EntityScope, individualScope?: Types.IndividualScope | null, teamScope?: Array<string | null> | null, nTopPerformers?: string | null, stakingRequirement: string, notionalTimeWeightedAveragePositionRequirement: string, windowLength: number, lockPeriod: number, distributionStrategy: Types.DistributionStrategy, rankTable?: Array<{ __typename?: 'RankTable', startRank: number, shareRatio: number } | null> | null } | null } }, fees?: Array<{ __typename?: 'TransferFee', transferId: string, amount: string, epoch: number } | null> | null } } | null> | null } | null };
export type TWAPQueryVariables = Types.Exact<{
partyId: Types.Scalars['ID'];
assetId: Types.Scalars['ID'];
gameId: Types.Scalars['ID'];
epochSeq?: Types.InputMaybe<Types.Scalars['Int']>;
}>;
export type TWAPQuery = { __typename?: 'Query', timeWeightedNotionalPosition?: { __typename?: 'TimeWeightedNotionalPosition', assetId: string, partyId: string, gameId: string, timeWeightedNotionalPosition: string, lastUpdated: any, epoch: number } | null };
export type RewardsHistoryQueryVariables = Types.Exact<{
partyId: Types.Scalars['ID'];
epochRewardSummariesPagination?: Types.InputMaybe<Types.Pagination>;
@ -213,6 +223,54 @@ export function useActiveRewardsLazyQuery(baseOptions?: Apollo.LazyQueryHookOpti
export type ActiveRewardsQueryHookResult = ReturnType<typeof useActiveRewardsQuery>;
export type ActiveRewardsLazyQueryHookResult = ReturnType<typeof useActiveRewardsLazyQuery>;
export type ActiveRewardsQueryResult = Apollo.QueryResult<ActiveRewardsQuery, ActiveRewardsQueryVariables>;
export const TWAPDocument = gql`
query TWAP($partyId: ID!, $assetId: ID!, $gameId: ID!, $epochSeq: Int) {
timeWeightedNotionalPosition(
partyId: $partyId
gameId: $gameId
assetId: $assetId
epochSeq: $epochSeq
) {
assetId
partyId
gameId
timeWeightedNotionalPosition
lastUpdated
epoch
}
}
`;
/**
* __useTWAPQuery__
*
* To run a query within a React component, call `useTWAPQuery` and pass it any options that fit your needs.
* When your component renders, `useTWAPQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useTWAPQuery({
* variables: {
* partyId: // value for 'partyId'
* assetId: // value for 'assetId'
* gameId: // value for 'gameId'
* epochSeq: // value for 'epochSeq'
* },
* });
*/
export function useTWAPQuery(baseOptions: Apollo.QueryHookOptions<TWAPQuery, TWAPQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<TWAPQuery, TWAPQueryVariables>(TWAPDocument, options);
}
export function useTWAPLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<TWAPQuery, TWAPQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<TWAPQuery, TWAPQueryVariables>(TWAPDocument, options);
}
export type TWAPQueryHookResult = ReturnType<typeof useTWAPQuery>;
export type TWAPLazyQueryHookResult = ReturnType<typeof useTWAPLazyQuery>;
export type TWAPQueryResult = Apollo.QueryResult<TWAPQuery, TWAPQueryVariables>;
export const RewardsHistoryDocument = gql`
query RewardsHistory($partyId: ID!, $epochRewardSummariesPagination: Pagination, $partyRewardsPagination: Pagination, $fromEpoch: Int, $toEpoch: Int) {
epochRewardSummaries(

View File

@ -126,6 +126,7 @@ export function createClient({
'NodeCheck',
'NodeCheckTimeUpdate',
'BlockStatistics',
'TWAP',
].includes(operation.operationName)
) {
return;

View File

@ -99,7 +99,7 @@ const VEGA = 'VEGA';
export type BasicAssetDetails = Pick<
AssetFieldsFragment,
'symbol' | 'decimals' | 'quantum'
'symbol' | 'decimals' | 'quantum' | 'id'
>;
/**
* Tries to find WETH asset configuration on Vega in order to provide its
@ -116,6 +116,7 @@ export const useWETH = (): BasicAssetDetails => {
symbol: WETH,
decimals: 18,
quantum: '500000000000000', // 1 WETH ~= 2000 qUSD
id: '',
};
};
@ -130,5 +131,6 @@ export const useVEGA = (): BasicAssetDetails => {
symbol: VEGA,
decimals: 18,
quantum: '1000000000000000000', // 1 VEGA ~= 1 qUSD
id: '',
};
};

View File

@ -6,7 +6,6 @@
"24h volume": "24h volume",
"A percentage of commission earned by the referrer": "A percentage of commission earned by the referrer",
"A successor to this market has been proposed": "A successor to this market has been proposed",
"As a team creator, you cannot switch teams": "As a team creator, you cannot switch teams",
"About the referral program": "About the referral program",
"Active": "Active",
"Activity Streak": "Activity Streak",
@ -14,27 +13,34 @@
"All teams": "All teams",
"All teams are eligible": "All teams are eligible",
"Amount earned": "Amount earned",
"Amount earned this epoch": "Amount earned this epoch",
"Anonymous": "Anonymous",
"Anyone with the referral link can apply it to their key(s) of choice via an on chain transaction": "Anyone with the referral link can apply it to their key(s) of choice via an on chain transaction",
"Assessed over": "Assessed over",
"Are you sure you want to join team: {{team}}": "Are you sure you want to join team: {{team}}",
"As a team creator, you cannot switch teams": "As a team creator, you cannot switch teams",
"Assessed over": "Assessed over",
"Asset (1)": "Asset (1)",
"Assets": "Assets",
"Available to withdraw this epoch": "Available to withdraw this epoch",
"Average position": "Average position",
"Avatar URL": "Avatar URL",
"Average position": "Average position",
"Base commission rate": "Base commission rate",
"Base rate": "Base rate",
"Best bid": "Best bid",
"Best offer": "Best offer",
"Browse": "Browse",
"Browse existing public teams to find your perfect match.": "Browse existing public teams to find your perfect match.",
"By using the Vega Console, you acknowledge that you have read and understood the <0>Vega Console Disclaimer</0>": "By using the Vega Console, you acknowledge that you have read and understood the <0>Vega Console Disclaimer</0>",
"Capped at": "Capped at",
"Cancel": "Cancel",
"Change (24h)": "Change (24h)",
"Changes have been proposed for this market. <0>View proposals</0>": "Changes have been proposed for this market. <0>View proposals</0>",
"Changes successfully saved to your team.": "Changes successfully saved to your team.",
"Chart": "Chart",
"Chart by <0>TradingView</0>": "Chart by <0>TradingView</0>",
"Check the cards below to see what community-created, on-chain games are active and how to compete. Joining a team also lets you take part in the on-chain <0>referral program</0>.": "Check the cards below to see what community-created, on-chain games are active and how to compete. Joining a team also lets you take part in the on-chain <0>referral program</0>.",
"Choose a team": "Choose a team",
"Choose a team to get involved": "Choose a team to get involved",
"Close": "Close",
"Close menu": "Close menu",
"Closed": "Closed",
@ -43,10 +49,11 @@
"Code must be 64 characters in length": "Code must be 64 characters in length",
"Code must be be valid hex": "Code must be be valid hex",
"Collateral": "Collateral",
"Competitions": "Competitions",
"Conduct your own due diligence and consult your financial advisor before making any investment decisions.": "Conduct your own due diligence and consult your financial advisor before making any investment decisions.",
"Confrim": "Confrim",
"Confirm in wallet...": "Confirm in wallet...",
"Confirming transaction...": "Confirming transaction...",
"Confirm": "Confirm",
"Connect": "Connect",
"Connect wallet": "Connect wallet",
"Connect your wallet to join the team": "Connect your wallet to join the team",
@ -59,13 +66,18 @@
"Could not configure web3 provider": "Could not configure web3 provider",
"Could not initialize app": "Could not initialize app",
"Countdown": "Countdown",
"Create a referral code": "Create a referral code",
"Create": "Create",
"Create a team": "Create a team",
"Create a new team, share your code with potential members, or set a whitelist for an exclusive group.": "Create a new team, share your code with potential members, or set a whitelist for an exclusive group.",
"Create a private team": "Create a private team",
"Create a public team": "Create a public team",
"Create a referral code": "Create a referral code",
"Create a simple referral code to enjoy the referrer commission outlined in the current referral program": "Create a simple referral code to enjoy the referrer commission outlined in the current referral program",
"Create a team": "Create a team",
"Create solo team": "Create solo team",
"Make your referral code a Team to compete in Competitions with your friends, appear in leaderboards on the <0>Competitions Homepage</0>, and earn rewards": "Make your referral code a Team to compete in Competitions with your friends, appear in leaderboards on the <0>Competitions Homepage</0>, and earn rewards",
"Cumulative amount earned": "Cumulative amount earned",
"Current tier": "Current tier",
"Currently no active games on the network.": "Currently no active games on the network.",
"Currently no active teams on the network.": "Currently no active teams on the network.",
"DISCLAIMER_P1": "Vega is a decentralised peer-to-peer protocol that can be used to trade derivatives with cryptoassets. The Vega Protocol is an implementation layer (layer one) protocol made of free, public, open-source or source-available software. Use of the Vega Protocol involves various risks, including but not limited to, losses while digital assets are supplied to the Vega Protocol and losses due to the fluctuation of prices of assets.",
"DISCLAIMER_P2": "Before using the Vega Protocol, review the relevant documentation at docs.vega.xyz to make sure that you understand how it works. Conduct your own due diligence and consult your financial advisor before making any investment decisions.",
"DISCLAIMER_P3": "As described in the Vega Protocol core license, the Vega Protocol is provided “as is”, at your own risk, and without warranties of any kind. Although Gobalsky Labs Limited developed much of the initial code for the Vega Protocol, it does not provide or control the Vega Protocol, which is run by third parties deploying it on a bespoke blockchain. Upgrades and modifications to the Vega Protocol are managed in a community-driven way by holders of the VEGA governance token.",
@ -73,6 +85,7 @@
"DISCLAIMER_P5": "This website is hosted on a decentralised network, the Interplanetary File System (“IPFS”). The IPFS decentralised web is made up of all the computers (nodes) connected to it. Data is therefore stored on many different computers.",
"DISCLAIMER_P6": "The information provided on this website does not constitute investment advice, financial advice, trading advice, or any other sort of advice and you should not treat any of the website's content as such. No party recommends that any cryptoasset should be bought, sold, or held by you via this website. No party ensures the accuracy of information listed on this website or holds any responsibility for any missing or wrong information. You understand that you are using any and all information available here at your own risk.",
"DISCLAIMER_P7": "Additionally, just as you can access email protocols such as SMTP through multiple email clients, you can potentially access the Vega Protocol through many web or mobile interfaces. You are responsible for doing your own diligence on those interfaces to understand the associated risks and any fees.",
"Daily reward amount": "Daily reward amount",
"Dark mode": "Dark mode",
"Date Joined": "Date Joined",
"Depending on data node retention you may not be able see the full 30 days": "Depending on data node retention you may not be able see the full 30 days",
@ -90,15 +103,13 @@
"Earned by me": "Earned by me",
"Edit alias": "Edit alias",
"Eligible teams": "Eligible teams",
"Enactment date reached and usual auction exit checks pass": "Enactment date reached and usual auction exit checks pass",
"Enactment date": "Enactment date",
"[empty]": "[empty]",
"Enactment date reached and usual auction exit checks pass": "Enactment date reached and usual auction exit checks pass",
"End time": "End time",
"Ends in": "Ends in",
"Entity scope": "Entity scope",
"{{entity}} scope": "{{entity}} scope",
"Environment not configured": "Environment not configured",
"Epoch": "Epoch",
"epochs in referral set": "epochs in referral set",
"Epochs in set": "Epochs in set",
"Epochs to next tier": "Epochs to next tier",
"Expected in {{distance}}": "Expected in {{distance}}",
@ -124,22 +135,25 @@
"Funding payments": "Funding payments",
"Funding rate": "Funding rate",
"Futures": "Futures",
"Game details": "Game details",
"Games ({{count}})": "Games ({{count}})",
"Results ({{count}})": "Results ({{count}})",
"Generate a referral code to share with your friends and start earning commission.": "Generate a referral code to share with your friends and start earning commission.",
"Generate code": "Generate code",
"Get rewards for providing liquidity.": "Get rewards for providing liquidity.",
"Get started": "Get started",
"Get the Vega Wallet": "Get the Vega Wallet",
"Give Feedback": "Give Feedback",
"Global staking reward for staking $VEGA on the network via the Governance app": "Global staking reward for staking $VEGA on the network via the Governance app",
"Go back and try again": "Go back and try again",
"Go back to the competitions": "Go back to the competitions",
"Go back to the team's profile": "Go back to the team's profile",
"Got an idea for a competition? Anyone can define and fund one -- <0>propose an on-chain game</0> yourself.": "Got an idea for a competition? Anyone can define and fund one -- <0>propose an on-chain game</0> yourself.",
"Got to competitions": "Go to competitions",
"Governance": "Governance",
"Governance vote for this market has been rejected": "Governance vote for this market has been rejected",
"Governance vote for this market is valid and has been accepted": "Governance vote for this market is valid and has been accepted",
"Governance vote has passed and market is awaiting opening auction exit": "Governance vote has passed and market is awaiting opening auction exit",
"Governance vote passed to close the market": "Governance vote passed to close the market",
"Global staking reward for staking $VEGA on the network via the Governance app": "Global staking reward for staking $VEGA on the network via the Governance app",
"Help identify bugs and improve the service by sharing anonymous usage data.": "Help identify bugs and improve the service by sharing anonymous usage data.",
"Help us identify bugs and improve Vega Governance by sharing anonymous usage data.": "Help us identify bugs and improve Vega Governance by sharing anonymous usage data.",
"Hide closed markets": "Hide closed markets",
@ -155,25 +169,29 @@
"INTERVAL_I4H": "4H",
"INTERVAL_I5M": "5m",
"INTERVAL_I6H": "6h",
"INTERVAL_I8H": "8h",
"INTERVAL_I7D": "W",
"INTERVAL_I8H": "8h",
"Improve vega console": "Improve vega console",
"Inactive": "Inactive",
"Index Price": "Index Price",
"Indicators": "Indicators",
"Invalid image URL": "Invalid image URL",
"Invalid URL": "Invalid URL",
"Individual": "Individual",
"Infrastructure": "Infrastructure",
"Interval: {{interval}}": "Interval: {{interval}}",
"Invalid URL": "Invalid URL",
"Invalid image URL": "Invalid image URL",
"Invite friends and earn rewards from the trading fees they pay. Stake those rewards to earn multipliers on future rewards.": "Invite friends and earn rewards from the trading fees they pay. Stake those rewards to earn multipliers on future rewards.",
"It appears that the connection to the node <0>{{VEGA_URL}}</0> does not return necessary data, try switching to another node.": "It appears that the connection to the node <0>{{VEGA_URL}}</0> does not return necessary data, try switching to another node.",
"It looks like you're connection is slow, try switching to another node.": "It looks like you're connection is slow, try switching to another node.",
"Join a team": "Join a team",
"Join team": "Join team",
"Joined": "Joined",
"Joined at": "Joined at",
"Joined epoch": "Joined epoch",
"Key name": "Key name",
"gameCount_one": "Last game result",
"gameCount_other": "Last {{count}} game results",
"Last {{games}} games result_one": "Last game result",
"Last {{games}} games result_other": "Last {{games}} games result",
"Leaderboard": "Leaderboard",
"Learn about providing liquidity": "Learn about providing liquidity",
"Learn more": "Learn more",
"Ledger entries": "Ledger entries",
@ -183,8 +201,9 @@
"Locked {{assetSymbol}}": "Locked {{assetSymbol}}",
"Low fees and no cost to place orders": "Low fees and no cost to place orders",
"Mainnet status & incidents": "Mainnet status & incidents",
"Make withdrawal": "Make withdrawal",
"Make team private": "Make team private",
"Make withdrawal": "Make withdrawal",
"Make your referral code a Team to compete in Competitions with your friends, appear in leaderboards on the <0>Competitions Homepage</0>, and earn rewards": "Make your referral code a Team to compete in Competitions with your friends, appear in leaderboards on the <0>Competitions Homepage</0>, and earn rewards",
"Maker": "Maker",
"Mark Price": "Mark Price",
"Mark price": "Mark price",
@ -193,31 +212,32 @@
"Market specification": "Market specification",
"Market triggers cancellation or governance vote has passed to cancel": "Market triggers cancellation or governance vote has passed to cancel",
"Markets": "Markets",
"Member ID": "Member ID",
"Members": "Members",
"Members ({{count}})": "Members ({{count}})",
"Member ID": "Member ID",
"Menu": "Menu",
"Metamask Snap <0>quick start</0>": "Metamask Snap <0>quick start</0>",
"Min. epochs": "Min. epochs",
"Min. trading volume": "Min. trading volume",
"My current volume": "My current volume",
"My liquidity provision": "My liquidity provision",
"My team": "My team",
"My trading fees": "My trading fees",
"Name": "Name",
"No MetaMask version that supports snaps detected. Learn more about <0>MetaMask Snaps</0>": "No MetaMask version that supports snaps detected. Learn more about <0>MetaMask Snaps</0>",
"No alias": "No alias",
"No closed orders": "No closed orders",
"No data": "No data",
"No deposits": "No deposits",
"No funding history data": "No funding history data",
"No future markets.": "No future markets.",
"No games": "No games",
"No game results available": "No game results available",
"No games": "No games",
"No ledger entries to export": "No ledger entries to export",
"No market": "No market",
"No markets": "No markets",
"No markets.": "No markets.",
"No members": "No members",
"No MetaMask version that supports snaps detected. Learn more about <0>MetaMask Snaps</0>": "No MetaMask version that supports snaps detected. Learn more about <0>MetaMask Snaps</0>",
"No open orders": "No open orders",
"No orders": "No orders",
"No party accepts any liability for any losses whatsoever.": "No party accepts any liability for any losses whatsoever.",
@ -250,31 +270,26 @@
"Owner": "Owner",
"PRNT": "PRNT",
"Page not found": "Page not found",
"Parent of a market": "Parent of a market",
"Parent market": "Parent market",
"Parent of a market": "Parent of a market",
"Pennant": "Pennant",
"Perpetuals": "Perpetuals",
"place_ordinal_one": "{{count}}st",
"place_ordinal_two": "{{count}}nd",
"place_ordinal_few": "{{count}}rd",
"place_ordinal_other": "{{count}}th",
"Please choose another market from the <0>market list</0>": "Please choose another market from the <0>market list</0>",
"Please connect Vega wallet": "Please connect Vega wallet",
"Portfolio": "Portfolio",
"Positions": "Positions",
"Price": "Price",
"Profile": "Profile",
"Profile updated": "Profile updated",
"Program ends:": "Program ends:",
"Propose a new market": "Propose a new market",
"Proposed final price is {{price}} {{assetSymbol}}.": "Proposed final price is {{price}} {{assetSymbol}}.",
"Proposed markets": "Proposed markets",
"Provide a link so users can learn more about your team": "Provide a link so users can learn more about your team",
"Provide a URL to a hosted image": "Provide a URL to a hosted image",
"Provide a link so users can learn more about your team": "Provide a link so users can learn more about your team",
"Providing liquidity": "Providing liquidity",
"Public key allow list": "Public key allow list",
"Purpose built proof of stake blockchain": "Purpose built proof of stake blockchain",
"qUSD": "qUSD",
"qUSD provides a rough USD equivalent of balances across all assets using the value of \"Quantum\" for that asset": "qUSD provides a rough USD equivalent of balances across all assets using the value of \"Quantum\" for that asset",
"Rank": "Rank",
"Read the terms": "Read the terms",
"Ready to trade": "Ready to trade",
@ -294,16 +309,22 @@
"Required for next tier": "Required for next tier",
"Reset Columns": "Reset Columns",
"Resources": "Resources",
"Results ({{count}})": "Results ({{count}})",
"Results {{games}}": "Results {{games}}",
"Reward asset": "Reward asset",
"Reward bonus": "Reward bonus",
"Reward {{reward}}x": "Reward {{reward}}x",
"Rewards": "Rewards",
"Rewards earned": "Rewards earned",
"Rewards funded using the pro-rata strategy should be distributed pro-rata by each entity's reward metric scaled by any active multipliers that party has": " Rewards funded using the pro-rata strategy should be distributed pro-rata by each entity's reward metric scaled by any active multipliers that party has",
"Rewards history": "Rewards history",
"Rewards multipliers": "Rewards multipliers",
"Rewards paid out": "Rewards paid out",
"Reward will be capped at {{capRewardFeeMultiple}} X of taker fees paid in the epoch": "Reward will be capped at {{capRewardFeeMultiple}} X of taker fees paid in the epoch",
"SCCR": "SCCR",
"Search": "Search",
"See all markets": "See all markets",
"See all the live games on the cards below. Every on-chain game is community funded and designed. <0>Find out how to create one</0>.": "See all the live games on the cards below. Every on-chain game is community funded and designed. <0>Find out how to create one</0>.",
"Select market": "Select market",
"Set party alias": "Set party alias",
"Settings": "Settings",
@ -314,6 +335,7 @@
"Share data": "Share data",
"Share usage data": "Share usage data",
"Show closed markets": "Show closed markets",
"Solo team / lone wolf": "Solo team / lone wolf",
"Something went wrong": "Something went wrong",
"Spot": "Spot",
"Spot markets coming soon.": "Spot markets coming soon.",
@ -322,6 +344,7 @@
"Stake some $VEGA now": "Stake some $VEGA now",
"Staked VEGA": "Staked VEGA",
"Staking multiplier": "Staking multiplier",
"Staking rewards": "Staking rewards",
"Start trading": "Start trading",
"Start trading on the worlds most advanced decentralised exchange.": "Start trading on the worlds most advanced decentralised exchange.",
"State": "State",
@ -338,13 +361,14 @@
"Switching team will move you from '{{fromTeam}}' to '{{toTeam}}' at the end of the epoch. Are you sure?": "Switching team will move you from '{{fromTeam}}' to '{{toTeam}}' at the end of the epoch. Are you sure?",
"Target stake": "Target stake",
"Team": "Team",
"Team name": "Team name",
"Team name cannot be empty": "Team name cannot be empty",
"Team creation transaction successful": "Team creation transaction successful",
"Team joined": "Team joined",
"Team name": "Team name",
"Team name cannot be empty": "Team name cannot be empty",
"Team switch successful. You will switch team at the end of the epoch.": "Team switch successful. You will switch team at the end of the epoch.",
"Teams can earn rewards if they meet the goals set in the on-chain trading competitions. Track your earned rewards here, and see which teams are top of the leaderboard this month.": "Teams can earn rewards if they meet the goals set in the on-chain trading competitions. Track your earned rewards here, and see which teams are top of the leaderboard this month.",
"The amount of fees paid to liquidity providers across the whole market during the last epoch {{epoch}}.": "The amount of fees paid to liquidity providers across the whole market during the last epoch {{epoch}}.",
"The average position requirement is {{averagePositionRequirements}}": "The average position requirement is {{averagePositionRequirements}}",
"The commission is taken from the infrastructure fee, maker fee, and liquidity provider fee, not from the referee": "The commission is taken from the infrastructure fee, maker fee, and liquidity provider fee, not from the referee",
"The external time weighted average price (TWAP) received from the data source defined in the data sourcing specification.": "The external time weighted average price (TWAP) received from the data source defined in the data sourcing specification.",
"The final price will be {{price}} {{assetSymbol}}.": "The final price will be {{price}} {{assetSymbol}}.",
@ -373,9 +397,6 @@
"Total games": "Total games",
"Total number of games this team has participated in": "Total number of games this team has participated in",
"Total volume": "Total volume",
"totalCommission": "Total commission (<0>last {{count}} epochs</0>)",
"totalCommission_one": "Total commission (<0>last {{count}} epoch</0>)",
"totalCommission_other": "Total commission (<0>last {{count}} epochs</0>)",
"Trader": "Trader",
"Trades": "Trades",
"Trading": "Trading",
@ -387,12 +408,11 @@
"TradingView": "TradingView",
"Transfer": "Transfer",
"Type": "Type",
"Staking rewards": "Staking rewards",
"URL": "URL",
"Unknown": "Unknown",
"Unknown settlement date": "Unknown settlement date",
"Unnamed key": "Unnamed key",
"Update team": "Update team",
"URL": "URL",
"Use a comma separated list to allow only specific public keys to join the team": "Use a comma separated list to allow only specific public keys to join the team",
"Vega Reward pot": "Vega Reward pot",
"Vega Wallet <0>full featured</0>": "Vega Wallet <0>full featured</0>",
@ -401,13 +421,14 @@
"Vesting multiplier": "Vesting multiplier",
"Vesting {{assetSymbol}}": "Vesting {{assetSymbol}}",
"Vesting {{vesting}}x": "Vesting {{vesting}}x",
"View all teams": "View all teams",
"View as public key": "View as public key",
"View liquidity provision table": "View liquidity provision table",
"View on Explorer": "View on Explorer",
"View oracle specification": "View oracle specification",
"View parent market": "View parent market",
"View proposals": "View proposals",
"View proposal": "View proposal",
"View proposals": "View proposals",
"View settlement asset details": "View settlement asset details",
"View successor market": "View successor market",
"View team": "View team",
@ -416,6 +437,7 @@
"Volume discount": "Volume discount",
"Volume to next tier": "Volume to next tier",
"Wallet": "Wallet",
"Want to compete but think the best team size is one? This is the option for you.": "Want to compete but think the best team size is one? This is the option for you.",
"We're sorry but we don't have an active referral programme currently running. You can propose a new programme <0>here</0>.": "We're sorry but we don't have an active referral programme currently running. You can propose a new programme <0>here</0>.",
"Welcome to Vega trading!": "Welcome to Vega trading!",
"Withdraw": "Withdraw",
@ -426,17 +448,23 @@
"You need a <0>Vega wallet</0> to start trading in this market.": "You need a <0>Vega wallet</0> to start trading in this market.",
"You need at least {{requiredStake}} VEGA staked to generate a referral code and participate in the referral program.": "You need at least {{requiredStake}} VEGA staked to generate a referral code and participate in the referral program.",
"You will no longer be able to hold a position on this market when it closes in {{duration}}.": "You will no longer be able to hold a position on this market when it closes in {{duration}}.",
"Your average position is {{averagePosition}}, but the requirement is {{averagePositionRequirements}}": "Your average position is {{averagePosition}}, but the requirement is {{averagePositionRequirements}}",
"Your code has been rejected": "Your code has been rejected",
"Your identity is always anonymous on Vega": "Your identity is always anonymous on Vega",
"Your key's private name, can be changed in your wallet": "Your key's private name, can be changed in your wallet",
"Your referral code": "Your referral code",
"Your tier": "Your tier",
"Your public alias, stored on chain": "Your public alias, stored on chain",
"Your referral code": "Your referral code",
"Your team ID:": "Your team ID:",
"Your tier": "Your tier",
"[empty]": "[empty]",
"checkOutProposalsAndVote": "Check out the terms of the proposals and vote:",
"checkOutProposalsAndVote_one": "Check out the terms of the proposal and vote:",
"checkOutProposalsAndVote_other": "Check out the terms of the proposals and vote:",
"epochStreak_one": "{{count}} epoch streak",
"epochs in referral set": "epochs in referral set",
"epochsStreak": "{{count}} epochs streak",
"gameCount_one": "Last game result",
"gameCount_other": "Last {{count}} game results",
"minTradingVolume": "Min. trading volume (last {{count}} epochs)",
"minTradingVolume_one": "Min. trading volume (last {{count}} epoch)",
"minTradingVolume_other": "Min. trading volume (last {{count}} epochs)",
@ -445,9 +473,15 @@
"myVolume_other": "My volume (last {{count}} epochs)",
"numberEpochs": "{{count}} epochs",
"numberEpochs_one": "{{count}} epoch",
"Rewards earned": "Rewards earned",
"Rewards paid out": "Rewards paid out",
"{{reward}}x": "{{reward}}x",
"place_ordinal_few": "{{count}}rd",
"place_ordinal_one": "{{count}}st",
"place_ordinal_other": "{{count}}th",
"place_ordinal_two": "{{count}}nd",
"qUSD": "qUSD",
"qUSD provides a rough USD equivalent of balances across all assets using the value of \"Quantum\" for that asset": "qUSD provides a rough USD equivalent of balances across all assets using the value of \"Quantum\" for that asset",
"totalCommission": "Total commission (<0>last {{count}} epochs</0>)",
"totalCommission_one": "Total commission (<0>last {{count}} epoch</0>)",
"totalCommission_other": "Total commission (<0>last {{count}} epochs</0>)",
"userActive": "{{active}} trader: {{count}} epochs so far",
"userInactive": "{{active}} trader: {{count}} epochs so far, you will lose your streak in {{remaining}} epochs!",
"volumeLastEpochs": "Volume (last {{count}} epochs)",
@ -460,40 +494,7 @@
"{{assetSymbol}} Reward pot": "{{assetSymbol}} Reward pot",
"{{checkedAssets}} Assets": "{{checkedAssets}} Assets",
"{{distance}} ago": "{{distance}} ago",
"{{entity}} scope": "{{entity}} scope",
"{{instrumentCode}} liquidity provision": "{{instrumentCode}} liquidity provision",
"My team": "My team",
"Profile": "Profile",
"Last {{games}} games result_one": "Last game result",
"Last {{games}} games result_other": "Last {{games}} games result",
"Leaderboard": "Leaderboard",
"View all teams": "View all teams",
"Competitions": "Competitions",
"Create a public team": "Create a public team",
"Create a private team": "Create a private team",
"Choose a team": "Choose a team",
"Join a team": "Join a team",
"Solo team / lone wolf": "Solo team / lone wolf",
"Choose a team to get involved": "Choose a team to get involved",
"Go back to the team's profile": "Go back to the team's profile",
"Go back to the competitions": "Go back to the competitions",
"Your team ID:": "Your team ID:",
"Changes successfully saved to your team.": "Changes successfully saved to your team.",
"Results {{games}}": "Results {{games}}",
"End time": "End time",
"Reward asset": "Reward asset",
"Daily reward amount": "Daily reward amount",
"Amount earned this epoch": "Amount earned this epoch",
"Cumulative amount earned": "Cumulative amount earned",
"Game details": "Game details",
"Check the cards below to see what community-created, on-chain games are active and how to compete. Joining a team also lets you take part in the on-chain <0>referral program</0>.": "Check the cards below to see what community-created, on-chain games are active and how to compete. Joining a team also lets you take part in the on-chain <0>referral program</0>.",
"Got an idea for a competition? Anyone can define and fund one -- <0>propose an on-chain game</0> yourself.": "Got an idea for a competition? Anyone can define and fund one -- <0>propose an on-chain game</0> yourself.",
"Create a new team, share your code with potential members, or set a whitelist for an exclusive group.": "Create a new team, share your code with potential members, or set a whitelist for an exclusive group.",
"Want to compete but think the best team size is one? This is the option for you.": "Want to compete but think the best team size is one? This is the option for you.",
"Browse existing public teams to find your perfect match.": "Browse existing public teams to find your perfect match.",
"See all the live games on the cards below. Every on-chain game is community funded and designed. <0>Find out how to create one</0>.": "See all the live games on the cards below. Every on-chain game is community funded and designed. <0>Find out how to create one</0>.",
"Teams can earn rewards if they meet the goals set in the on-chain trading competitions. Track your earned rewards here, and see which teams are top of the leaderboard this month.": "Teams can earn rewards if they meet the goals set in the on-chain trading competitions. Track your earned rewards here, and see which teams are top of the leaderboard this month.",
"Currently no active games on the network.": "Currently no active games on the network.",
"Currently no active teams on the network.": "Currently no active teams on the network.",
"It looks like you're connection is slow, try switching to another node.": "It looks like you're connection is slow, try switching to another node.",
"It appears that the connection to the node <0>{{VEGA_URL}}</0> does not return necessary data, try switching to another node.": "It appears that the connection to the node <0>{{VEGA_URL}}</0> does not return necessary data, try switching to another node."
"{{reward}}x": "{{reward}}x"
}