Compare commits

..
105 changed files with 1455 additions and 2455 deletions
+1 -2
View File
@@ -196,9 +196,9 @@ jobs:
cypress:
needs: [build-sources, check-e2e-needed]
name: '(CI) cypress'
if: ${{ needs.check-e2e-needed.outputs.run-tests == 'true' }}
uses: ./.github/workflows/cypress-run.yml
secrets: inherit
if: needs.check-e2e-needed.outputs.run-tests == 'true' && (contains(needs.build-sources.outputs.projects, 'governance') || contains(needs.build-sources.outputs.projects, 'explorer'))
with:
projects: ${{ needs.build-sources.outputs.projects-e2e }}
tags: '@smoke'
@@ -287,7 +287,6 @@ jobs:
steps:
- run: |
result="${{ needs.cypress.result }}"
echo "Result: $result"
if [[ $result == "success" || $result == "skipped" ]]; then
exit 0
else
@@ -7,7 +7,6 @@ import {
navigateTo,
navigation,
turnTelemetryOff,
setRiskAccepted,
} from '../../support/common.functions';
import {
clickOnValidatorFromList,
@@ -58,7 +57,6 @@ context(
// 1002-STKE-002, 1002-STKE-032
before('visit staking tab and connect vega wallet', function () {
cy.visit('/');
setRiskAccepted();
ethereumWalletConnect();
cy.connectVegaWallet();
vegaWalletSetSpecifiedApprovalAmount('1000');
@@ -5,7 +5,6 @@ import {
navigateTo,
navigation,
turnTelemetryOff,
setRiskAccepted,
} from '../../support/common.functions';
import {
stakingPageAssociateTokens,
@@ -58,7 +57,6 @@ context(
function () {
cy.clearLocalStorage();
turnTelemetryOff();
setRiskAccepted();
cy.mockChainId();
cy.reload();
waitForSpinner();
@@ -79,23 +79,23 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
});
});
it.skip('should have information on active nodes', function () {
it('should have information on active nodes', function () {
cy.getByTestId('node-information')
.first()
.should('contain.text', '2')
.should('contain.text', '1')
.and('contain.text', 'active nodes');
});
it.skip('should have information on consensus nodes', function () {
it('should have information on consensus nodes', function () {
cy.getByTestId('node-information')
.last()
.should('contain.text', '2')
.should('contain.text', '1')
.and('contain.text', 'consensus nodes');
});
it.skip('should contain link to specific validators', function () {
it('should contain link to specific validators', function () {
cy.getByTestId('validators')
.should('have.length', '2')
.should('have.length', '1')
.each(($validator) => {
cy.wrap($validator).find('a').should('have.attr', 'href');
});
@@ -153,7 +153,7 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
.invoke('text')
.should('not.eq', currentBlockHeight);
});
cy.getByTestId('subscription-cell').should('be.be.visible');
cy.getByTestId('subscription-cell').should('have.text', 'Yes');
});
cy.getByTestId('connect').should('be.disabled');
cy.getByTestId('node-url-custom').click({ force: true });
@@ -3,7 +3,6 @@
import { aliasGQLQuery } from '@vegaprotocol/cypress';
import {
navigation,
setRiskAccepted,
verifyPageHeader,
verifyTabHighlighted,
} from '../../support/common.functions';
@@ -188,7 +187,6 @@ context('Validators Page - verify elements on page', function () {
before('connect wallets and click on validator', function () {
cy.mockChainId();
cy.visit('/validators');
setRiskAccepted();
cy.connectVegaWallet();
clickOnValidatorFromList(0);
});
@@ -1,8 +1,5 @@
import { truncateByChars } from '@vegaprotocol/utils';
import {
setRiskAccepted,
waitForSpinner,
} from '../../support/common.functions';
import { waitForSpinner } from '../../support/common.functions';
import {
vegaWalletFaucetAssetsWithoutCheck,
vegaWalletTeardown,
@@ -14,6 +11,7 @@ const connectButton = 'connect-vega-wallet';
const getVegaLink = 'link';
const dialog = '[role="dialog"]:visible';
const dialogHeader = 'dialog-title';
const walletDialogHeader = 'wallet-dialog-title';
const connectorsList = 'connectors-list';
const dialogCloseBtn = 'dialog-close';
const accountNo = 'vega-account-truncated';
@@ -36,7 +34,6 @@ context(
() => {
before('visit token home page', () => {
cy.visit('/');
setRiskAccepted();
cy.get(walletContainer, { timeout: 60000 }).should('be.visible');
});
@@ -66,12 +63,17 @@ context(
it('should have Connect Vega header visible', () => {
cy.get(dialog).within(() => {
cy.getByTestId(connectorsList)
cy.getByTestId(walletDialogHeader)
.should('be.visible')
.and(
'have.text',
'Get the Vega WalletGet MetaMask>_Command Line WalletView as public key'
);
.and('have.text', 'Get a Vega wallet');
});
});
it('should have jsonRpc and hosted connection options visible on list', function () {
cy.getByTestId(connectorsList).within(() => {
cy.getByTestId('connector-jsonRpc')
.should('be.visible')
.and('have.text', 'Use the Desktop App/CLI');
});
});
@@ -86,6 +88,7 @@ context(
before('connect vega wallet', function () {
cy.mockChainId();
cy.visit('/');
cy.wait('@ChainId');
cy.connectVegaWallet();
vegaWalletTeardown();
});
@@ -102,12 +102,6 @@ export function turnTelemetryOff() {
);
}
export function setRiskAccepted() {
cy.window().then((win) =>
win.localStorage.setItem('vega_wallet_risk_accepted', 'true')
);
}
export function dissociateFromSecondWalletKey() {
const secondWalletKey = Cypress.env('vegaWalletPublicKey2Short');
cy.getByTestId('vega-in-wallet')
+2 -4
View File
@@ -26,9 +26,9 @@ export const AppLoader = ({ children }: { children: React.ReactElement }) => {
const { token, staking, vesting } = useContracts();
const setAssociatedBalances = useRefreshAssociatedBalances();
const [balancesLoaded, setBalancesLoaded] = React.useState(false);
const vegaWalletStatus = useEagerConnect();
const vegaConnecting = useEagerConnect();
const loaded = balancesLoaded && vegaWalletStatus !== 'connecting';
const loaded = balancesLoaded && !vegaConnecting;
React.useEffect(() => {
const run = async () => {
@@ -169,5 +169,3 @@ export const AppLoader = ({ children }: { children: React.ReactElement }) => {
}
return <Suspense fallback={loading}>{children}</Suspense>;
};
AppLoader.displayName = 'AppLoader';
@@ -1,44 +0,0 @@
import {
useLinks,
DApp,
CONSOLE_REWARDS_PAGE,
} from '@vegaprotocol/environment';
import {
ExternalLink,
Intent,
NotificationBanner,
VegaIcon,
VegaIconNames,
} from '@vegaprotocol/ui-toolkit';
import { Trans } from 'react-i18next';
import { useMatch } from 'react-router-dom';
import Routes from '../../routes/routes';
import { type ReactNode } from 'react';
const ConsoleRewardsLink = ({ children }: { children: ReactNode }) => {
const consoleLink = useLinks(DApp.Console);
return (
<ExternalLink
href={consoleLink(CONSOLE_REWARDS_PAGE)}
className="underline inline-flex gap-1 items-center"
title="Rewards in Console"
>
<span>{children}</span>
<VegaIcon size={12} name={VegaIconNames.OPEN_EXTERNAL} />
</ExternalLink>
);
};
export const RewardsMovedNotification = () => {
const onRewardsPage = useMatch(Routes.REWARDS);
if (!onRewardsPage) return null;
return (
<NotificationBanner intent={Intent.Warning}>
<Trans
i18nKey="rewardsMovedNotification"
components={[<ConsoleRewardsLink>Console</ConsoleRewardsLink>]}
/>
</NotificationBanner>
);
};
@@ -10,7 +10,6 @@ import {
ProtocolUpgradeProposalNotification,
} from '@vegaprotocol/proposals';
import { ViewingAsBanner } from '@vegaprotocol/ui-toolkit';
import { RewardsMovedNotification } from '../notifications/rewards-moved-notification';
interface AppLayoutProps {
children: ReactNode;
@@ -46,10 +45,8 @@ export const AppLayout = ({ children }: AppLayoutProps) => {
const NotificationsContainer = () => {
const { isReadOnly, pubKey, disconnect } = useVegaWallet();
return (
<div data-testid="banners">
<RewardsMovedNotification />
<ProtocolUpgradeProposalNotification
mode={ProtocolUpgradeCountdownMode.IN_ESTIMATED_TIME_REMAINING}
/>
@@ -111,4 +111,3 @@ export const ContractsProvider = ({ children }: { children: JSX.Element }) => {
</ContractsContext.Provider>
);
};
ContractsProvider.displayName = 'ContractsProvider';
@@ -288,7 +288,7 @@ describe('Consensus validators table', () => {
expect(
grid.querySelector('[role="gridcell"][col-id="totalPenalties"]')
).toHaveTextContent('10.07%');
).toHaveTextContent('13.16%');
expect(
grid.querySelector('[role="gridcell"][col-id="normalisedVotingPower"]')
@@ -185,19 +185,15 @@ export const ConsensusValidatorsTable = ({
const { rawValidatorScore: previousEpochValidatorScore } =
getLastEpochScoreAndPerformance(previousEpochData, id);
const overstakingPenalty = calculateOverstakedPenalty(
const overstakingPenalty = calculateOverallPenalty(
id,
allNodesInPreviousEpoch
);
const totalPenalty = calculateOverallPenalty(
const totalPenalty = calculateOverstakedPenalty(
id,
allNodesInPreviousEpoch
);
const lastEpochDataForNode = allNodesInPreviousEpoch.find(
(node) => node.id === id
);
return {
id,
[ValidatorFields.RANKING_INDEX]: stakedTotalRanking,
@@ -243,12 +239,6 @@ export const ConsensusValidatorsTable = ({
: undefined,
[ValidatorFields.MULTISIG_ERROR]:
multisigStatus?.showMultisigStatusError,
[ValidatorFields.MULTISIG_PENALTY]: formatNumberPercentage(
new BigNumber(1)
.minus(lastEpochDataForNode?.rewardScore?.multisigScore ?? 1)
.times(100),
2
),
};
}
);
@@ -388,6 +378,7 @@ export const ConsensusValidatorsTable = ({
headerTooltip: t('StakeDescription').toString(),
cellRenderer: TotalStakeRenderer,
width: 120,
sort: 'desc',
},
{
field: ValidatorFields.PENDING_STAKE,
@@ -409,7 +400,6 @@ export const ConsensusValidatorsTable = ({
headerTooltip: t('NormalisedVotingPowerDescription').toString(),
cellRenderer: VotingPowerRenderer,
width: 120,
sort: 'desc',
},
{
field: ValidatorFields.TOTAL_PENALTIES,
@@ -40,7 +40,6 @@ export enum ValidatorFields {
PENDING_USER_STAKE = 'pendingUserStake',
USER_STAKE_SHARE = 'userStakeShare',
MULTISIG_ERROR = 'multisigError',
MULTISIG_PENALTY = 'multisigPenalty',
}
export const addUserDataToValidator = (
@@ -328,7 +327,7 @@ interface TotalPenaltiesRendererProps {
overstakedAmount: string;
overstakingPenalty: string;
totalPenalties: string;
multisigPenalty: string;
multisigError?: boolean;
};
}
@@ -347,9 +346,11 @@ export const TotalPenaltiesRenderer = ({
<div data-testid="overstaked-penalty-tooltip">
{t('overstakedPenalty')}: {data.overstakingPenalty}
</div>
<div data-testid="multisig-error-tooltip">
{t('multisigPenalty')}: {data.multisigPenalty}
</div>
{data.multisigError && (
<div data-testid="multisig-error-tooltip">
{t('multisigPenalty')}: 100%
</div>
)}
</>
}
>
@@ -37,6 +37,7 @@ import {
import type { ReactNode } from 'react';
import type { StakingNodeFieldsFragment } from '../__generated__/Staking';
import type { PreviousEpochQuery } from '../__generated__/PreviousEpoch';
import { getMultisigStatusInfo } from '../../../lib/get-multisig-status-info';
const statuses = {
[Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_ERSATZ]: 'status-ersatz',
@@ -104,10 +105,9 @@ export const ValidatorTable = ({
};
}, [node, previousEpochData?.epoch.validatorsConnection?.edges]);
const previousNodeData =
previousEpochData?.epoch.validatorsConnection?.edges?.find(
(e) => e?.node.id === node.id
);
const multisigStatus = previousEpochData
? getMultisigStatusInfo(previousEpochData)
: undefined;
return (
<>
@@ -293,15 +293,21 @@ export const ValidatorTable = ({
data-testid="multisig-penalty"
className="flex gap-2 items-baseline"
>
{multisigStatus?.zeroScoreNodes.find(
(n) => n.id === node.id
) ? (
<Tooltip
description={t('multisigPenaltyThisNodeIndicator')}
>
<span className="inline-block w-2 h-2 rounded-full bg-vega-red-500"></span>
</Tooltip>
) : null}
<Tooltip description={t('multisigPenaltyDescription')}>
<span>
{formatNumberPercentage(
new BigNumber(1)
.minus(
previousNodeData?.node.rewardScore?.multisigScore ??
1
)
.times(100),
BigNumber(
multisigStatus?.showMultisigStatusError ? 100 : 0
),
2
)}
</span>
@@ -1,126 +1,63 @@
import type { InMemoryCacheConfig } from '@apollo/client';
import {
AppFailure,
AppLoader,
NetworkLoader,
NodeFailure,
NodeGuard,
useEnvironment,
useNodeSwitcherStore,
} from '@vegaprotocol/environment';
import { useEffect, type ReactNode, useState } from 'react';
import { type ReactNode } from 'react';
import { Web3Provider } from './web3-provider';
import { useT } from '../../lib/use-t';
import { DataLoader } from './data-loader';
import { WalletProvider } from '@vegaprotocol/wallet-react';
import { useVegaWalletConfig } from '../../lib/hooks/use-vega-wallet-config';
import { Trans } from 'react-i18next';
import { Button, Loader, Splash, VLogo } from '@vegaprotocol/ui-toolkit';
const Failure = ({ reason }: { reason?: ReactNode }) => {
const t = useT();
const setNodeSwitcher = useNodeSwitcherStore((store) => store.setDialogOpen);
return (
<Splash>
<div className="border border-vega-red m-10 mx-auto w-4/5 max-w-3xl rounded-lg overflow-hidden animate-shake">
<div className="bg-vega-red text-white px-2 py-2 flex gap-1 items-center font-alpha calt uppercase">
<VLogo className="h-4" />
<span className="text-lg">{t('Failed to initialize the app')}</span>
</div>
<div className="p-4 text-left text-sm">
<p className="mb-4">{reason}</p>
<div className="text-center">
<Button className="border-2" onClick={() => setNodeSwitcher(true)}>
{t('Change node')}
</Button>
</div>
</div>
</div>
</Splash>
);
};
const Loading = () => {
const [showSlowNotification, setShowSlowNotification] = useState(false);
const t = useT();
const setNodeSwitcher = useNodeSwitcherStore((store) => store.setDialogOpen);
useEffect(() => {
const to = setTimeout(() => {
if (!showSlowNotification) setShowSlowNotification(true);
}, 5000);
return () => {
clearTimeout(to);
};
}, [showSlowNotification]);
return (
<Splash>
<div className="border border-transparent m-10 mx-auto w-4/5 max-w-3xl rounded-lg overflow-hidden">
<div className="mt-11 p-4 text-left text-sm">
<Loader />
{showSlowNotification && (
<>
<p className="mt-4 text-center">
{t(
"It looks like you're connection is slow, try switching to another node."
)}
</p>
<div className="mt-4 text-center">
<Button
className="border-2"
onClick={() => setNodeSwitcher(true)}
>
{t('Change node')}
</Button>
</div>
</>
)}
</div>
</div>
</Splash>
);
};
export const Bootstrapper = ({ children }: { children: ReactNode }) => {
const t = useT();
const { error, VEGA_URL } = useEnvironment((state) => ({
error: state.error,
VEGA_URL: state.VEGA_URL,
}));
const { error, VEGA_URL } = useEnvironment();
const config = useVegaWalletConfig();
if (!config) {
return <AppLoader />;
}
const ERR_DATA_LOADER = (
<Trans
i18nKey="It appears that the connection to the node <0>{{VEGA_URL}}</0> does not return necessary data, try switching to another node."
components={[
<span key="vega" className="text-muted">
{VEGA_URL}
</span>,
]}
values={{
VEGA_URL,
}}
/>
);
return (
<NetworkLoader
cache={cacheConfig}
skeleton={<Loading />}
failure={<Failure reason={error} />}
skeleton={<AppLoader />}
failure={
<AppFailure title={t('Could not initialize app')} error={error} />
}
>
<DataLoader
skeleton={<Loading />}
failure={<Failure reason={ERR_DATA_LOADER} />}
<NodeGuard
skeleton={<AppLoader />}
failure={
<NodeFailure
title={t('Node: {{VEGA_URL}} is unsuitable', { VEGA_URL })}
/>
}
>
<Web3Provider
skeleton={<Loading />}
failure={<Failure reason={t('Could not configure web3 provider')} />}
<DataLoader
skeleton={<AppLoader />}
failure={
<AppFailure
title={t('Could not load market data or asset data')}
error={error}
/>
}
>
<WalletProvider config={config}>{children}</WalletProvider>
</Web3Provider>
</DataLoader>
<Web3Provider
skeleton={<AppLoader />}
failure={
<AppFailure title={t('Could not configure web3 provider')} />
}
>
<WalletProvider config={config}>{children}</WalletProvider>
</Web3Provider>
</DataLoader>
</NodeGuard>
</NetworkLoader>
);
};
@@ -30,6 +30,8 @@ export const ChartContainer = ({ marketId }: { marketId: string }) => {
setStudies,
setStudySizes,
setOverlays,
state,
setState,
} = useChartSettings();
const pennantChart = (
@@ -66,6 +68,10 @@ export const ChartContainer = ({ marketId }: { marketId: string }) => {
onIntervalChange={(newInterval) => {
setInterval(fromTradingViewResolution(newInterval));
}}
onAutoSaveNeeded={(data) => {
setState(data);
}}
state={state}
/>
);
}
@@ -6,12 +6,7 @@ export const SUPPORTED_INTERVALS = [
Interval.INTERVAL_I1M,
Interval.INTERVAL_I5M,
Interval.INTERVAL_I15M,
Interval.INTERVAL_I30M,
Interval.INTERVAL_I1H,
Interval.INTERVAL_I4H,
Interval.INTERVAL_I6H,
Interval.INTERVAL_I8H,
Interval.INTERVAL_I12H,
Interval.INTERVAL_I1D,
Interval.INTERVAL_I7D,
] as const;
@@ -9,6 +9,7 @@ type StudySizes = { [S in Study]?: number };
export type Chartlib = 'pennant' | 'tradingview';
interface StoredSettings {
state: object | undefined; // Don't see a better type provided from TradingView type definitions
chartlib: Chartlib;
// For interval we use the enum from @vegaprotocol/types, this is to make mapping between different
// chart types easier and more consistent
@@ -29,6 +30,7 @@ const STUDY_ORDER: Study[] = [
];
export const DEFAULT_CHART_SETTINGS = {
state: undefined,
chartlib: 'pennant' as const,
interval: Interval.INTERVAL_I15M,
type: ChartType.CANDLE,
@@ -45,6 +47,7 @@ export const useChartSettingsStore = create<
setStudies: (studies?: Study[]) => void;
setStudySizes: (sizes: number[]) => void;
setChartlib: (lib: Chartlib) => void;
setState: (state: object) => void;
}
>()(
persist(
@@ -92,6 +95,9 @@ export const useChartSettingsStore = create<
state.chartlib = lib;
});
},
setState: (state) => {
set({ state });
},
})),
{
name: 'vega_candles_chart_store',
@@ -145,5 +151,7 @@ export const useChartSettings = () => {
setOverlays: settings.setOverlays,
setStudySizes: settings.setStudySizes,
setChartlib: settings.setChartlib,
state: settings.state,
setState: settings.setState,
};
};
+1 -1
View File
@@ -1,3 +1,3 @@
CONSOLE_IMAGE_NAME=vegaprotocol/trading:latest
VEGA_VERSION=v0.75.0-preview.2
VEGA_VERSION=v0.74.6
LOCAL_SERVER=false
+2
View File
@@ -50,6 +50,8 @@ def truncate_middle(market_id, start=6, end=4):
def change_keys(page: Page, vega: VegaServiceNull, key_name):
page.get_by_test_id("manage-vega-wallet").click()
page.get_by_test_id("key-" + vega.wallet.public_key(key_name)).click()
page.click(
f'data-testid=key-{vega.wallet.public_key(key_name)} >> .inline-flex')
page.reload()
+1
View File
@@ -339,3 +339,4 @@ def retry_on_http_error(request):
print(f"Retrying due to HTTPError (attempt {i+1}/{retry_count})")
else:
raise
+4 -4
View File
@@ -877,13 +877,13 @@ testing = ["filelock"]
[[package]]
name = "python-dateutil"
version = "2.9.0.post0"
version = "2.8.2"
description = "Extensions to the standard Python datetime module"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
files = [
{file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"},
{file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"},
{file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"},
{file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"},
]
[package.dependencies]
@@ -1166,7 +1166,7 @@ profile = ["pytest-profiling", "snakeviz"]
type = "git"
url = "https://github.com/vegaprotocol/vega-market-sim.git/"
reference = "HEAD"
resolved_reference = "53eed8942acb670783105cb1115bab76710a46dc"
resolved_reference = "33fec45ce8044ef7f53b625584ce590d174f9057"
[[package]]
name = "websocket-client"
@@ -18,7 +18,7 @@ expire = "expire"
@pytest.fixture(scope="module")
def vega(request):
with init_vega(request) as vega_instance:
request.addfinalizer(lambda: cleanup_container(vega_instance))
request.addfinalizer(lambda: cleanup_container(vega_instance)) # Register the cleanup function
yield vega_instance
@@ -261,7 +261,7 @@ class TestStopOcoValidation:
@pytest.fixture(scope="class")
def vega(request):
with init_vega(request) as vega_instance:
request.addfinalizer(lambda: cleanup_container(vega_instance))
request.addfinalizer(lambda: cleanup_container(vega_instance)) # Register the cleanup function
yield vega_instance
@pytest.fixture(scope="class")
@@ -1,7 +1,6 @@
import pytest
from typing import Tuple, Generator
from fees_test_ids import *
from playwright.sync_api import expect, Page
from playwright.sync_api import Page, expect
from vega_sim.null_service import VegaServiceNull
from actions.vega import submit_order
from wallet_config import MM_WALLET
@@ -17,70 +16,77 @@ from fixtures.market import setup_continuous_market
@pytest.fixture(scope="module")
def setup_environment(
request, browser
) -> Generator[Tuple[VegaServiceNull, str, Page], None, None]:
def vega(request):
with init_vega(request) as vega_instance:
request.addfinalizer(lambda: cleanup_container(vega_instance))
market = setup_continuous_market(vega_instance, custom_quantum=100000)
vega_instance.update_volume_discount_program(
proposal_key=MM_WALLET.name,
benefit_tiers=[
{
"minimum_running_notional_taker_volume": 100,
"volume_discount_factor": 0.1,
},
{
"minimum_running_notional_taker_volume": 200,
"volume_discount_factor": 0.2,
},
],
window_length=7,
request.addfinalizer(
lambda: cleanup_container(vega_instance)
)
next_epoch(vega_instance)
vega_instance.update_referral_program(
proposal_key=MM_WALLET.name,
benefit_tiers=[
{
"minimum_running_notional_taker_volume": 100,
"minimum_epochs": 1,
"referral_reward_factor": 0.1,
"referral_discount_factor": 0.1,
},
{
"minimum_running_notional_taker_volume": 200,
"minimum_epochs": 2,
"referral_reward_factor": 0.2,
"referral_discount_factor": 0.2,
},
],
staking_tiers=[
{"minimum_staked_tokens": 100, "referral_reward_multiplier": 1.1},
{"minimum_staked_tokens": 200, "referral_reward_multiplier": 1.2},
],
window_length=1,
)
vega_instance.create_referral_set(key_name=MM_WALLET.name)
next_epoch(vega_instance)
referral_set_id = list(vega_instance.list_referral_sets().keys())[0]
vega_instance.apply_referral_code(key_name="Key 1", id=referral_set_id)
next_epoch(vega_instance)
for _ in range(2):
submit_order(vega_instance, "Key 1", market, "SIDE_BUY", 2, 110)
forward_time(vega_instance, True if _ < 2 - 1 else False)
with init_page(vega_instance, browser, request) as page_instance:
risk_accepted_setup(page_instance)
auth_setup(vega_instance, page_instance)
yield vega_instance, market, page_instance
yield vega_instance
def test_fees_page_discount_program_my_trading_fees(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
@pytest.fixture(scope="module")
def page(vega, browser, request):
with init_page(vega, browser, request) as page:
risk_accepted_setup(page)
auth_setup(vega, page)
yield page
@pytest.fixture(scope="module", autouse=True)
def setup_combined_market(vega: VegaServiceNull):
market = setup_continuous_market(vega, custom_quantum=100000)
vega.update_volume_discount_program(
proposal_key=MM_WALLET.name,
benefit_tiers=[
{
"minimum_running_notional_taker_volume": 100,
"volume_discount_factor": 0.1,
},
{
"minimum_running_notional_taker_volume": 200,
"volume_discount_factor": 0.2,
},
],
window_length=7,
)
next_epoch(vega=vega)
vega.update_referral_program(
proposal_key=MM_WALLET.name,
benefit_tiers=[
{
"minimum_running_notional_taker_volume": 100,
"minimum_epochs": 1,
"referral_reward_factor": 0.1,
"referral_discount_factor": 0.1,
},
{
"minimum_running_notional_taker_volume": 200,
"minimum_epochs": 2,
"referral_reward_factor": 0.2,
"referral_discount_factor": 0.2,
},
],
staking_tiers=[
{"minimum_staked_tokens": 100, "referral_reward_multiplier": 1.1},
{"minimum_staked_tokens": 200, "referral_reward_multiplier": 1.2},
],
window_length=1,
)
vega.create_referral_set(key_name=MM_WALLET.name)
next_epoch(vega=vega)
referral_set_id = list(vega.list_referral_sets().keys())[0]
vega.apply_referral_code(key_name="Key 1", id=referral_set_id)
next_epoch(vega=vega)
for _ in range(2):
submit_order(vega, "Key 1", market, "SIDE_BUY", 2, 110)
forward_time(vega, True if _ < 2 - 1 else False)
return market
@pytest.mark.xdist_group(name="test_fees_combo_tier_2")
def test_fees_page_discount_program_my_trading_fees(page: Page):
page.goto("/#/fees")
expect(page.get_by_test_id(ADJUSTED_FEES)).to_have_text("6.432%-6.432%")
expect(page.get_by_test_id(TOTAL_FEE_BEFORE_DISCOUNT)).to_have_text(
@@ -91,10 +97,10 @@ def test_fees_page_discount_program_my_trading_fees(
expect(page.get_by_test_id(LIQUIDITY_FEES)).to_have_text("Liquidity0%-0%")
@pytest.mark.xdist_group(name="test_fees_combo_tier_2")
def test_fees_page_discount_program_total_discount(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
page: Page,
):
page.goto("/#/fees")
expect(page.get_by_test_id(TOTAL_DISCOUNT)).to_have_text("36%")
expect(page.get_by_test_id(VOLUME_DISCOUNT_ROW)).to_have_text("Volume discount20%")
@@ -107,10 +113,8 @@ def test_fees_page_discount_program_total_discount(
)
def test_fees_page_discount_program_fees_by_market(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
@pytest.mark.xdist_group(name="test_fees_combo_tier_2")
def test_fees_page_discount_program_fees_by_market(page: Page):
page.goto("/#/fees")
pinned = page.locator(PINNED_ROW_LOCATOR)
row = page.locator(ROW_LOCATOR)
@@ -122,11 +126,12 @@ def test_fees_page_discount_program_fees_by_market(
expect(row.locator(COL_TOTAL_FEE)).to_have_text("10.05%")
@pytest.mark.xdist_group(name="test_fees_combo_tier_2")
def test_deal_ticket_discount_program(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
page.goto(f"/#/markets/{market}")
page: Page,
setup_combined_market,
):
page.goto(f"/#/markets/{setup_combined_market}")
page.get_by_test_id(ORDER_SIZE).fill("1")
page.get_by_test_id(ORDER_PRICE).fill("1")
expect(page.get_by_test_id(DISCOUNT_PILL)).to_have_text("-36%")
@@ -145,9 +150,12 @@ def test_deal_ticket_discount_program(
expect(tooltip.get_by_test_id(TOTAL_FEE_VALUE)).to_have_text("0.06432 tDAI")
def test_fills_taker_discount_program(setup_environment):
vega, market, page = setup_environment
page.goto(f"/#/markets/{market}")
@pytest.mark.xdist_group(name="test_fees_combo_tier_2")
def test_fills_taker_discount_program(
page: Page,
setup_combined_market,
):
page.goto(f"/#/markets/{setup_combined_market}")
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
expect(row.locator(COL_SIZE)).to_have_text("+2")
@@ -158,11 +166,13 @@ def test_fills_taker_discount_program(setup_environment):
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text("7.48926 tDAI")
@pytest.mark.xdist_group(name="test_fees_combo_tier_2")
def test_fills_maker_discount_program(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
page.goto(f"/#/markets/{market}")
vega: VegaServiceNull,
page: Page,
setup_combined_market,
):
page.goto(f"/#/markets/{setup_combined_market}")
change_keys(page, vega, MM_WALLET.name)
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
@@ -174,11 +184,11 @@ def test_fills_maker_discount_program(
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text("7.452 tDAI")
@pytest.mark.xdist_group(name="test_fees_combo_tier_2")
def test_fills_maker_fee_tooltip_discount_program(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
page.goto(f"/#/markets/{market}")
vega: VegaServiceNull, page: Page, setup_combined_market
):
page.goto(f"/#/markets/{setup_combined_market}")
change_keys(page, vega, MM_WALLET.name)
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
@@ -190,11 +200,12 @@ def test_fills_maker_fee_tooltip_discount_program(
)
@pytest.mark.xdist_group(name="test_fees_combo_tier_2")
def test_fills_taker_fee_tooltip_discount_program(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
page.goto(f"/#/markets/{market}")
page: Page,
setup_combined_market,
):
page.goto(f"/#/markets/{setup_combined_market}")
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
# tbd - tooltip is not visible without this wait
@@ -1,5 +1,4 @@
import pytest
from typing import Tuple, Generator
from fees_test_ids import *
from playwright.sync_api import Page, expect
from vega_sim.null_service import VegaServiceNull
@@ -15,58 +14,63 @@ from conftest import (
from actions.utils import next_epoch, change_keys, forward_time
from fixtures.market import setup_continuous_market
@pytest.fixture(scope="module")
def vega(request):
with init_vega(request) as vega_instance:
request.addfinalizer(
lambda: cleanup_container(vega_instance)
)
yield vega_instance
@pytest.fixture(scope="module")
def setup_environment(
request, browser
) -> Generator[Tuple[VegaServiceNull, str, Page], None, None]:
with init_vega(request) as vega_instance:
request.addfinalizer(lambda: cleanup_container(vega_instance))
# Setup the market with the referral discount program
market = setup_continuous_market(vega_instance, custom_quantum=100000)
vega_instance.update_referral_program(
proposal_key=MM_WALLET.name,
benefit_tiers=[
{
"minimum_running_notional_taker_volume": 100,
"minimum_epochs": 1,
"referral_reward_factor": 0.1,
"referral_discount_factor": 0.1,
},
{
"minimum_running_notional_taker_volume": 200,
"minimum_epochs": 2,
"referral_reward_factor": 0.2,
"referral_discount_factor": 0.2,
},
],
staking_tiers=[
{"minimum_staked_tokens": 100, "referral_reward_multiplier": 1.1},
{"minimum_staked_tokens": 200, "referral_reward_multiplier": 1.2},
],
window_length=1,
)
vega_instance.create_referral_set(key_name=MM_WALLET.name)
next_epoch(vega_instance)
referral_set_id = list(vega_instance.list_referral_sets().keys())[0]
vega_instance.apply_referral_code(key_name="Key 1", id=referral_set_id)
next_epoch(vega_instance)
for _ in range(2):
submit_order(vega_instance, "Key 1", market, "SIDE_BUY", 1, 110)
forward_time(vega_instance, True if _ < 2 - 1 else False)
with init_page(vega_instance, browser, request) as page_instance:
risk_accepted_setup(page_instance)
auth_setup(vega_instance, page_instance)
yield vega_instance, market, page_instance
def page(vega, browser, request):
with init_page(vega, browser, request) as page:
risk_accepted_setup(page)
auth_setup(vega, page)
yield page
def test_fees_page_discount_program_my_trading_fees(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
@pytest.fixture(scope="module", autouse=True)
def setup_market_with_referral_discount_program(vega: VegaServiceNull):
market = setup_continuous_market(vega, custom_quantum=100000)
vega.update_referral_program(
proposal_key=MM_WALLET.name,
benefit_tiers=[
{
"minimum_running_notional_taker_volume": 100,
"minimum_epochs": 1,
"referral_reward_factor": 0.1,
"referral_discount_factor": 0.1,
},
{
"minimum_running_notional_taker_volume": 200,
"minimum_epochs": 2,
"referral_reward_factor": 0.2,
"referral_discount_factor": 0.2,
},
],
staking_tiers=[
{"minimum_staked_tokens": 100, "referral_reward_multiplier": 1.1},
{"minimum_staked_tokens": 200, "referral_reward_multiplier": 1.2},
],
window_length=1,
)
vega.create_referral_set(key_name=MM_WALLET.name)
next_epoch(vega=vega)
referral_set_id = list(vega.list_referral_sets().keys())[0]
vega.apply_referral_code(key_name="Key 1", id=referral_set_id)
next_epoch(vega=vega)
for _ in range(2):
submit_order(vega, "Key 1", market, "SIDE_BUY", 1, 110)
forward_time(vega, True if _ < 2 - 1 else False)
return market
@pytest.mark.xdist_group(name="test_fees_referral_tier_1")
def test_fees_page_discount_program_my_trading_fees(page: Page):
page.goto("/#/fees")
expect(page.get_by_test_id(ADJUSTED_FEES)).to_have_text("9.045%-9.045%")
expect(page.get_by_test_id(TOTAL_FEE_BEFORE_DISCOUNT)).to_have_text(
@@ -77,10 +81,8 @@ def test_fees_page_discount_program_my_trading_fees(
expect(page.get_by_test_id(LIQUIDITY_FEES)).to_have_text("Liquidity0%-0%")
def test_fees_page_discount_program_total_discount(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
@pytest.mark.xdist_group(name="test_fees_referral_tier_1")
def test_fees_page_discount_program_total_discount(page: Page):
page.goto("/#/fees")
expect(page.get_by_test_id(TOTAL_DISCOUNT)).to_have_text("10%")
expect(page.get_by_test_id(VOLUME_DISCOUNT_ROW)).to_have_text("Volume discount0%")
@@ -93,19 +95,15 @@ def test_fees_page_discount_program_total_discount(
)
def test_fees_page_referral_discount_program_referral_benefits(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
@pytest.mark.xdist_group(name="test_fees_referral_tier_1")
def test_fees_page_referral_discount_program_referral_benefits(page: Page):
page.goto("/#/fees")
expect(page.get_by_test_id(RUNNING_NOTIONAL_TAKER_VOLUME)).to_have_text("103")
expect(page.get_by_test_id(EPOCHS_IN_REFERRAL_SET)).to_have_text("1")
def test_fees_page_discount_program_discount(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
@pytest.mark.xdist_group(name="test_fees_referral_tier_1")
def test_fees_page_discount_program_discount(page: Page):
page.goto("/#/fees")
expect(page.get_by_test_id(TIER_VALUE_0)).to_have_text("1")
expect(page.get_by_test_id(TIER_VALUE_1)).to_have_text("2")
@@ -121,10 +119,8 @@ def test_fees_page_discount_program_discount(
expect(page.get_by_test_id("your-referral-tier-0").nth(1)).to_have_text("Your tier")
def test_fees_page_discount_program_fees_by_market(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
@pytest.mark.xdist_group(name="test_fees_referral_tier_1")
def test_fees_page_discount_program_fees_by_market(page: Page):
page.goto("/#/fees")
pinned = page.locator(PINNED_ROW_LOCATOR)
row = page.locator(ROW_LOCATOR)
@@ -136,11 +132,11 @@ def test_fees_page_discount_program_fees_by_market(
expect(row.locator(COL_TOTAL_FEE)).to_have_text("10.05%")
@pytest.mark.xdist_group(name="test_fees_referral_tier_1")
def test_deal_ticket_discount_program(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
page.goto(f"/#/markets/{market}")
page: Page, setup_market_with_referral_discount_program
):
page.goto(f"/#/markets/{setup_market_with_referral_discount_program}")
page.get_by_test_id(ORDER_SIZE).fill("1")
page.get_by_test_id(ORDER_PRICE).fill("1")
expect(page.get_by_test_id(DISCOUNT_PILL)).to_have_text("-10%")
@@ -159,11 +155,12 @@ def test_deal_ticket_discount_program(
expect(tooltip.get_by_test_id(TOTAL_FEE_VALUE)).to_have_text("0.09045 tDAI")
@pytest.mark.xdist_group(name="test_fees_referral_tier_1")
def test_fills_taker_discount_program(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
page.goto(f"/#/markets/{market}")
page: Page,
setup_market_with_referral_discount_program,
):
page.goto(f"/#/markets/{setup_market_with_referral_discount_program}")
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
expect(row.locator(COL_SIZE)).to_have_text("+1")
@@ -174,11 +171,13 @@ def test_fills_taker_discount_program(
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text("1.04017 tDAI")
@pytest.mark.xdist_group(name="test_fees_referral_tier_1")
def test_fills_maker_discount_program(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
page.goto(f"/#/markets/{market}")
vega: VegaServiceNull,
page: Page,
setup_market_with_referral_discount_program,
):
page.goto(f"/#/markets/{setup_market_with_referral_discount_program}")
change_keys(page, vega, MM_WALLET.name)
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
@@ -190,11 +189,11 @@ def test_fills_maker_discount_program(
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text("1.035 tDAI")
@pytest.mark.xdist_group(name="test_fees_referral_tier_1")
def test_fills_maker_fee_tooltip_discount_program(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
page.goto(f"/#/markets/{market}")
vega: VegaServiceNull, page: Page, setup_market_with_referral_discount_program
):
page.goto(f"/#/markets/{setup_market_with_referral_discount_program}")
change_keys(page, vega, MM_WALLET.name)
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
@@ -206,11 +205,12 @@ def test_fills_maker_fee_tooltip_discount_program(
)
@pytest.mark.xdist_group(name="test_fees_referral_tier_1")
def test_fills_taker_fee_tooltip_discount_program(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
page.goto(f"/#/markets/{market}")
page: Page,
setup_market_with_referral_discount_program,
):
page.goto(f"/#/markets/{setup_market_with_referral_discount_program}")
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
# tbd - tooltip is not visible without this wait
@@ -1,6 +1,5 @@
import pytest
from fees_test_ids import *
from typing import Tuple, Generator
from playwright.sync_api import Page, expect
from vega_sim.null_service import VegaServiceNull
from actions.vega import submit_order
@@ -17,56 +16,62 @@ from fixtures.market import setup_continuous_market
@pytest.fixture(scope="module")
def setup_environment(
request, browser
) -> Generator[Tuple[VegaServiceNull, str, Page], None, None]:
def vega(request):
with init_vega(request) as vega_instance:
request.addfinalizer(lambda: cleanup_container(vega_instance))
# Setup market with referral discount program
market = setup_continuous_market(vega_instance, custom_quantum=100000)
vega_instance.update_referral_program(
proposal_key=MM_WALLET.name,
benefit_tiers=[
{
"minimum_running_notional_taker_volume": 100,
"minimum_epochs": 1,
"referral_reward_factor": 0.1,
"referral_discount_factor": 0.1,
},
{
"minimum_running_notional_taker_volume": 200,
"minimum_epochs": 2,
"referral_reward_factor": 0.2,
"referral_discount_factor": 0.2,
},
],
staking_tiers=[
{"minimum_staked_tokens": 100, "referral_reward_multiplier": 1.1},
{"minimum_staked_tokens": 200, "referral_reward_multiplier": 1.2},
],
window_length=1,
request.addfinalizer(
lambda: cleanup_container(vega_instance)
)
vega_instance.create_referral_set(key_name=MM_WALLET.name)
next_epoch(vega_instance)
referral_set_id = list(vega_instance.list_referral_sets().keys())[0]
vega_instance.apply_referral_code(key_name="Key 1", id=referral_set_id)
next_epoch(vega_instance)
for _ in range(2):
submit_order(vega_instance, "Key 1", market, "SIDE_BUY", 2, 110)
forward_time(vega_instance, True if _ < 2 - 1 else False)
with init_page(vega_instance, browser, request) as page_instance:
risk_accepted_setup(page_instance)
auth_setup(vega_instance, page_instance)
yield vega_instance, market, page_instance
yield vega_instance
def test_fees_page_discount_program_my_trading_fees(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
@pytest.fixture(scope="module")
def page(vega, browser, request):
with init_page(vega, browser, request) as page:
risk_accepted_setup(page)
auth_setup(vega, page)
yield page
@pytest.fixture(scope="module", autouse=True)
def setup_market_with_referral_discount_program(vega: VegaServiceNull):
market = setup_continuous_market(vega, custom_quantum=100000)
vega.update_referral_program(
proposal_key=MM_WALLET.name,
benefit_tiers=[
{
"minimum_running_notional_taker_volume": 100,
"minimum_epochs": 1,
"referral_reward_factor": 0.1,
"referral_discount_factor": 0.1,
},
{
"minimum_running_notional_taker_volume": 200,
"minimum_epochs": 2,
"referral_reward_factor": 0.2,
"referral_discount_factor": 0.2,
},
],
staking_tiers=[
{"minimum_staked_tokens": 100, "referral_reward_multiplier": 1.1},
{"minimum_staked_tokens": 200, "referral_reward_multiplier": 1.2},
],
window_length=1,
)
vega.create_referral_set(key_name=MM_WALLET.name)
next_epoch(vega=vega)
referral_set_id = list(vega.list_referral_sets().keys())[0]
vega.apply_referral_code(key_name="Key 1", id=referral_set_id)
next_epoch(vega=vega)
for _ in range(2):
submit_order(vega, "Key 1", market, "SIDE_BUY", 2, 110)
forward_time(vega, True if _ < 2 - 1 else False)
return market
@pytest.mark.xdist_group(name="test_fees_referral_tier_2")
def test_fees_page_discount_program_my_trading_fees(page: Page):
page.goto("/#/fees")
expect(page.get_by_test_id(ADJUSTED_FEES)).to_have_text("8.04%-8.04%")
expect(page.get_by_test_id(TOTAL_FEE_BEFORE_DISCOUNT)).to_have_text(
@@ -77,10 +82,8 @@ def test_fees_page_discount_program_my_trading_fees(
expect(page.get_by_test_id(LIQUIDITY_FEES)).to_have_text("Liquidity0%-0%")
def test_fees_page_discount_program_total_discount(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
@pytest.mark.xdist_group(name="test_fees_referral_tier_2")
def test_fees_page_discount_program_total_discount(page: Page):
page.goto("/#/fees")
expect(page.get_by_test_id(TOTAL_DISCOUNT)).to_have_text("20%")
expect(page.get_by_test_id(VOLUME_DISCOUNT_ROW)).to_have_text("Volume discount0%")
@@ -93,19 +96,15 @@ def test_fees_page_discount_program_total_discount(
)
def test_fees_page_referral_discount_program_referral_benefits(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
@pytest.mark.xdist_group(name="test_fees_referral_tier_2")
def test_fees_page_referral_discount_program_referral_benefits(page: Page):
page.goto("/#/fees")
expect(page.get_by_test_id(RUNNING_NOTIONAL_TAKER_VOLUME)).to_have_text("207")
expect(page.get_by_test_id(REQUIRED_FOR_NEXT_TIER)).not_to_be_visible()
def test_fees_page_discount_program_discount(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
@pytest.mark.xdist_group(name="test_fees_referral_tier_2")
def test_fees_page_discount_program_discount(page: Page):
page.goto("/#/fees")
expect(page.get_by_test_id(TIER_VALUE_0)).to_have_text("1")
expect(page.get_by_test_id(TIER_VALUE_1)).to_have_text("2")
@@ -121,10 +120,8 @@ def test_fees_page_discount_program_discount(
expect(page.get_by_test_id("your-referral-tier-1").nth(1)).to_have_text("Your tier")
def test_fees_page_discount_program_fees_by_market(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
@pytest.mark.xdist_group(name="test_fees_referral_tier_2")
def test_fees_page_discount_program_fees_by_market(page: Page):
page.goto("/#/fees")
pinned = page.locator(PINNED_ROW_LOCATOR)
row = page.locator(ROW_LOCATOR)
@@ -136,11 +133,11 @@ def test_fees_page_discount_program_fees_by_market(
expect(row.locator(COL_TOTAL_FEE)).to_have_text("10.05%")
@pytest.mark.xdist_group(name="test_fees_referral_tier_2")
def test_deal_ticket_discount_program(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
page.goto(f"/#/markets/{market}")
page: Page, setup_market_with_referral_discount_program
):
page.goto(f"/#/markets/{setup_market_with_referral_discount_program}")
page.get_by_test_id(ORDER_SIZE).fill("1")
page.get_by_test_id(ORDER_PRICE).fill("1")
expect(page.get_by_test_id(DISCOUNT_PILL)).to_have_text("-20%")
@@ -159,11 +156,12 @@ def test_deal_ticket_discount_program(
expect(tooltip.get_by_test_id(TOTAL_FEE_VALUE)).to_have_text("0.0804 tDAI")
@pytest.mark.xdist_group(name="test_fees_referral_tier_2")
def test_fills_taker_discount_program(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
page.goto(f"/#/markets/{market}")
page: Page,
setup_market_with_referral_discount_program,
):
page.goto(f"/#/markets/{setup_market_with_referral_discount_program}")
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
expect(row.locator(COL_SIZE)).to_have_text("+2")
@@ -174,11 +172,13 @@ def test_fills_taker_discount_program(
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text("4.1607 tDAI")
@pytest.mark.xdist_group(name="test_fees_referral_tier_2")
def test_fills_maker_discount_program(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
page.goto(f"/#/markets/{market}")
vega: VegaServiceNull,
page: Page,
setup_market_with_referral_discount_program,
):
page.goto(f"/#/markets/{setup_market_with_referral_discount_program}")
change_keys(page, vega, MM_WALLET.name)
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
@@ -190,11 +190,11 @@ def test_fills_maker_discount_program(
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text("4.14 tDAI")
@pytest.mark.xdist_group(name="test_fees_referral_tier_2")
def test_fills_maker_fee_tooltip_discount_program(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
page.goto(f"/#/markets/{market}")
vega: VegaServiceNull, page: Page, setup_market_with_referral_discount_program
):
page.goto(f"/#/markets/{setup_market_with_referral_discount_program}")
change_keys(page, vega, MM_WALLET.name)
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
@@ -206,11 +206,12 @@ def test_fills_maker_fee_tooltip_discount_program(
)
@pytest.mark.xdist_group(name="test_fees_referral_tier_2")
def test_fills_taker_fee_tooltip_discount_program(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
page.goto(f"/#/markets/{market}")
page: Page,
setup_market_with_referral_discount_program,
):
page.goto(f"/#/markets/{setup_market_with_referral_discount_program}")
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
# tbd - tooltip is not visible without this wait
@@ -1,6 +1,5 @@
import pytest
from fees_test_ids import *
from typing import Tuple, Generator
from playwright.sync_api import Page, expect
from vega_sim.null_service import VegaServiceNull
from actions.vega import submit_order
@@ -17,45 +16,49 @@ from fixtures.market import setup_continuous_market
@pytest.fixture(scope="module")
def setup_environment(
request, browser
) -> Generator[Tuple[VegaServiceNull, str, Page], None, None]:
def vega(request):
with init_vega(request) as vega_instance:
request.addfinalizer(lambda: cleanup_container(vega_instance))
# Setup the market with volume discount program
market = setup_continuous_market(vega_instance, custom_quantum=100000)
vega_instance.update_volume_discount_program(
proposal_key=MM_WALLET.name,
benefit_tiers=[
{
"minimum_running_notional_taker_volume": 100,
"volume_discount_factor": 0.1,
},
{
"minimum_running_notional_taker_volume": 200,
"volume_discount_factor": 0.2,
},
],
window_length=7,
request.addfinalizer(
lambda: cleanup_container(vega_instance)
)
next_epoch(vega=vega_instance)
for _ in range(2):
submit_order(vega_instance, "Key 1", market, "SIDE_BUY", 1, 110)
forward_time(vega_instance, True if _ < 2 - 1 else False)
# Initialize and setup page
with init_page(vega_instance, browser, request) as page:
risk_accepted_setup(page)
auth_setup(vega_instance, page)
yield vega_instance, market, page
yield vega_instance
def test_fees_page_discount_program_my_trading_fees(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
@pytest.fixture(scope="module")
def page(vega, browser, request):
with init_page(vega, browser, request) as page:
risk_accepted_setup(page)
auth_setup(vega, page)
yield page
@pytest.fixture(scope="module", autouse=True)
def setup_market_with_volume_discount_program(vega: VegaServiceNull):
market = setup_continuous_market(vega, custom_quantum=100000)
vega.update_volume_discount_program(
proposal_key=MM_WALLET.name,
benefit_tiers=[
{
"minimum_running_notional_taker_volume": 100,
"volume_discount_factor": 0.1,
},
{
"minimum_running_notional_taker_volume": 200,
"volume_discount_factor": 0.2,
},
],
window_length=7,
)
next_epoch(vega=vega)
for _ in range(2):
submit_order(vega, "Key 1", market, "SIDE_BUY", 1, 110)
forward_time(vega, True if _ < 2 - 1 else False)
return market
@pytest.mark.xdist_group(name="test_fees_volume_tier_1")
def test_fees_page_discount_program_my_trading_fees(page: Page):
page.goto("/#/fees")
expect(page.get_by_test_id(ADJUSTED_FEES)).to_have_text("9.045%-9.045%")
expect(page.get_by_test_id(TOTAL_FEE_BEFORE_DISCOUNT)).to_have_text(
@@ -66,10 +69,10 @@ def test_fees_page_discount_program_my_trading_fees(
expect(page.get_by_test_id(LIQUIDITY_FEES)).to_have_text("Liquidity0%-0%")
@pytest.mark.xdist_group(name="test_fees_volume_tier_1")
def test_fees_page_discount_program_total_discount(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
page: Page,
):
page.goto("/#/fees")
expect(page.get_by_test_id(TOTAL_DISCOUNT)).to_have_text("10%")
expect(page.get_by_test_id(VOLUME_DISCOUNT_ROW)).to_have_text("Volume discount10%")
@@ -82,20 +85,20 @@ def test_fees_page_discount_program_total_discount(
)
@pytest.mark.xdist_group(name="test_fees_volume_tier_1")
def test_fees_page_volume_discount_program_my_current_volume(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
page: Page,
):
page.goto("/#/fees")
expect(page.get_by_test_id(PAST_EPOCHS_VOLUME)).to_have_text("103")
expect(page.get_by_test_id(REQUIRED_FOR_NEXT_TIER)).to_have_text("97")
@pytest.mark.xdist_group(name="test_fees_volume_tier_1")
def test_fees_page_discount_program_discount(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
page: Page,
):
page.goto("/#/fees")
expect(page.get_by_test_id(TIER_VALUE_0)).to_have_text("1")
expect(page.get_by_test_id(TIER_VALUE_1)).to_have_text("2")
@@ -108,10 +111,8 @@ def test_fees_page_discount_program_discount(
expect(page.get_by_test_id("your-volume-tier-0").nth(1)).to_have_text("Your tier")
def test_fees_page_discount_program_fees_by_market(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
@pytest.mark.xdist_group(name="test_fees_volume_tier_1")
def test_fees_page_discount_program_fees_by_market(page: Page):
page.goto("/#/fees")
pinned = page.locator(PINNED_ROW_LOCATOR)
row = page.locator(ROW_LOCATOR)
@@ -123,11 +124,11 @@ def test_fees_page_discount_program_fees_by_market(
expect(row.locator(COL_TOTAL_FEE)).to_have_text("10.05%")
@pytest.mark.xdist_group(name="test_fees_volume_tier_1")
def test_deal_ticket_discount_program_testing(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
page.goto(f"/#/markets/{market}")
page: Page, setup_market_with_volume_discount_program
):
page.goto(f"/#/markets/{setup_market_with_volume_discount_program}")
page.get_by_test_id(ORDER_SIZE).fill("1")
page.get_by_test_id(ORDER_PRICE).fill("1")
expect(page.get_by_test_id(DISCOUNT_PILL)).to_have_text("-10%")
@@ -148,10 +149,9 @@ def test_deal_ticket_discount_program_testing(
@pytest.mark.xdist_group(name="test_fees_volume_tier_1")
def test_fills_taker_discount_program(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
page.goto(f"/#/markets/{market}")
page: Page, setup_market_with_volume_discount_program
):
page.goto(f"/#/markets/{setup_market_with_volume_discount_program}")
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
expect(row.locator(COL_SIZE)).to_have_text("+1")
@@ -164,10 +164,9 @@ def test_fills_taker_discount_program(
@pytest.mark.xdist_group(name="test_fees_volume_tier_1")
def test_fills_maker_discount_program(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
page.goto(f"/#/markets/{market}")
page: Page, setup_market_with_volume_discount_program, vega: VegaServiceNull
):
page.goto(f"/#/markets/{setup_market_with_volume_discount_program}")
change_keys(page, vega, MM_WALLET.name)
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
@@ -179,11 +178,11 @@ def test_fills_maker_discount_program(
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text("1.035 tDAI")
@pytest.mark.xdist_group(name="test_fees_volume_tier_1")
def test_fills_maker_fee_tooltip_discount_program(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
page.goto(f"/#/markets/{market}")
vega: VegaServiceNull, page: Page, setup_market_with_volume_discount_program
):
page.goto(f"/#/markets/{setup_market_with_volume_discount_program}")
change_keys(page, vega, MM_WALLET.name)
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
@@ -195,11 +194,12 @@ def test_fills_maker_fee_tooltip_discount_program(
)
@pytest.mark.xdist_group(name="test_fees_volume_tier_1")
def test_fills_taker_fee_tooltip_discount_program(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
page.goto(f"/#/markets/{market}")
page: Page,
setup_market_with_volume_discount_program,
):
page.goto(f"/#/markets/{setup_market_with_volume_discount_program}")
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
# tbd - tooltip is not visible without this wait
@@ -1,6 +1,5 @@
import pytest
from fees_test_ids import *
from typing import Tuple, Generator
from playwright.sync_api import Page, expect
from vega_sim.null_service import VegaServiceNull
from actions.vega import submit_order
@@ -15,47 +14,51 @@ from conftest import (
from actions.utils import next_epoch, change_keys, forward_time
from fixtures.market import setup_continuous_market
@pytest.fixture(scope="module")
def vega(request):
with init_vega(request) as vega_instance:
request.addfinalizer(
lambda: cleanup_container(vega_instance)
)
yield vega_instance
@pytest.fixture(scope="module")
def setup_environment(
request, browser
) -> Generator[Tuple[VegaServiceNull, str, Page], None, None]:
with init_vega(request) as vega_instance:
request.addfinalizer(lambda: cleanup_container(vega_instance))
# Setup the market with volume discount program
market = setup_continuous_market(vega_instance, custom_quantum=100000)
vega_instance.update_volume_discount_program(
proposal_key=MM_WALLET.name,
benefit_tiers=[
{
"minimum_running_notional_taker_volume": 100,
"volume_discount_factor": 0.1,
},
{
"minimum_running_notional_taker_volume": 200,
"volume_discount_factor": 0.2,
},
],
window_length=7,
)
next_epoch(vega=vega_instance)
for _ in range(3):
submit_order(vega_instance, "Key 1", market, "SIDE_BUY", 1, 110)
forward_time(vega_instance, True if _ < 3 - 1 else False)
# Initialize page and apply setups
with init_page(vega_instance, browser, request) as page_instance:
risk_accepted_setup(page_instance)
auth_setup(vega_instance, page_instance)
yield vega_instance, market, page_instance
def page(vega, browser, request):
with init_page(vega, browser, request) as page:
risk_accepted_setup(page)
auth_setup(vega, page)
yield page
def test_fees_page_discount_program_my_trading_fees(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
@pytest.fixture(scope="module", autouse=True)
def setup_market_with_volume_discount_program(vega: VegaServiceNull):
market = setup_continuous_market(vega, custom_quantum=100000)
vega.update_volume_discount_program(
proposal_key=MM_WALLET.name,
benefit_tiers=[
{
"minimum_running_notional_taker_volume": 100,
"volume_discount_factor": 0.1,
},
{
"minimum_running_notional_taker_volume": 200,
"volume_discount_factor": 0.2,
},
],
window_length=7,
)
next_epoch(vega=vega)
for _ in range(3):
submit_order(vega, "Key 1", market, "SIDE_BUY", 1, 110)
forward_time(vega, True if _ < 3 - 1 else False)
return market
@pytest.mark.xdist_group(name="test_fees_volume_tier_2")
def test_fees_page_discount_program_my_trading_fees(page: Page):
page.goto("/#/fees")
expect(page.get_by_test_id(ADJUSTED_FEES)).to_have_text("8.04%-8.04%")
expect(page.get_by_test_id(TOTAL_FEE_BEFORE_DISCOUNT)).to_have_text(
@@ -66,10 +69,8 @@ def test_fees_page_discount_program_my_trading_fees(
expect(page.get_by_test_id(LIQUIDITY_FEES)).to_have_text("Liquidity0%-0%")
def test_fees_page_discount_program_total_discount(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
@pytest.mark.xdist_group(name="test_fees_volume_tier_2")
def test_fees_page_discount_program_total_discount(page: Page):
page.goto("/#/fees")
expect(page.get_by_test_id(TOTAL_DISCOUNT)).to_have_text("20%")
expect(page.get_by_test_id(VOLUME_DISCOUNT_ROW)).to_have_text("Volume discount20%")
@@ -82,19 +83,15 @@ def test_fees_page_discount_program_total_discount(
)
def test_fees_page_volume_discount_program_my_current_volume(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
@pytest.mark.xdist_group(name="test_fees_volume_tier_2")
def test_fees_page_volume_discount_program_my_current_volume(page: Page):
page.goto("/#/fees")
expect(page.get_by_test_id(PAST_EPOCHS_VOLUME)).to_have_text("206")
expect(page.get_by_test_id(REQUIRED_FOR_NEXT_TIER)).not_to_be_visible()
def test_fees_page_discount_program_discount(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
@pytest.mark.xdist_group(name="test_fees_volume_tier_2")
def test_fees_page_discount_program_discount(page: Page):
page.goto("/#/fees")
expect(page.get_by_test_id(TIER_VALUE_0)).to_have_text("1")
expect(page.get_by_test_id(TIER_VALUE_1)).to_have_text("2")
@@ -107,8 +104,8 @@ def test_fees_page_discount_program_discount(
expect(page.get_by_test_id("your-volume-tier-1").nth(1)).to_have_text("Your tier")
def test_fees_page_discount_program_fees_by_market(setup_environment):
vega, market, page = setup_environment
@pytest.mark.xdist_group(name="test_fees_volume_tier_2")
def test_fees_page_discount_program_fees_by_market(page: Page):
page.goto("/#/fees")
pinned = page.locator(PINNED_ROW_LOCATOR)
row = page.locator(ROW_LOCATOR)
@@ -120,11 +117,12 @@ def test_fees_page_discount_program_fees_by_market(setup_environment):
expect(row.locator(COL_TOTAL_FEE)).to_have_text("10.05%")
@pytest.mark.xdist_group(name="test_fees_volume_tier_2")
def test_deal_ticket_discount_program(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
page.goto(f"/#/markets/{market}")
page: Page,
setup_market_with_volume_discount_program,
):
page.goto(f"/#/markets/{setup_market_with_volume_discount_program}")
page.get_by_test_id(ORDER_SIZE).fill("1")
page.get_by_test_id(ORDER_PRICE).fill("1")
expect(page.get_by_test_id(DISCOUNT_PILL)).to_have_text("-20%")
@@ -143,11 +141,12 @@ def test_deal_ticket_discount_program(
expect(tooltip.get_by_test_id(TOTAL_FEE_VALUE)).to_have_text("0.0804 tDAI")
@pytest.mark.xdist_group(name="test_fees_volume_tier_2")
def test_fills_taker_discount_program(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
page.goto(f"/#/markets/{market}")
page: Page,
setup_market_with_volume_discount_program,
):
page.goto(f"/#/markets/{setup_market_with_volume_discount_program}")
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
expect(row.locator(COL_SIZE)).to_have_text("+1")
@@ -160,11 +159,13 @@ def test_fills_taker_discount_program(
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text("2.08035 tDAI")
@pytest.mark.xdist_group(name="test_fees_volume_tier_2")
def test_fills_maker_discount_program(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
page.goto(f"/#/markets/{market}")
vega: VegaServiceNull,
page: Page,
setup_market_with_volume_discount_program,
):
page.goto(f"/#/markets/{setup_market_with_volume_discount_program}")
change_keys(page, vega, MM_WALLET.name)
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
@@ -176,11 +177,11 @@ def test_fills_maker_discount_program(
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text("2.07 tDAI")
@pytest.mark.xdist_group(name="test_fees_volume_tier_2")
def test_fills_maker_fee_tooltip_discount_program(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
page.goto(f"/#/markets/{market}")
vega, page: Page, setup_market_with_volume_discount_program
):
page.goto(f"/#/markets/{setup_market_with_volume_discount_program}")
change_keys(page, vega, MM_WALLET.name)
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
@@ -192,11 +193,12 @@ def test_fills_maker_fee_tooltip_discount_program(
)
@pytest.mark.xdist_group(name="test_fees_volume_tier_2")
def test_fills_taker_fee_tooltip_discount_program(
setup_environment: Tuple[VegaServiceNull, str, Page],
) -> None:
vega, market, page = setup_environment
page.goto(f"/#/markets/{market}")
page: Page,
setup_market_with_volume_discount_program,
):
page.goto(f"/#/markets/{setup_market_with_volume_discount_program}")
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
# tbd - tooltip is not visible without this wait
@@ -37,16 +37,19 @@ def validate_info_section(page: Page, fields: [[str, str]]):
for rowNumber, field in enumerate(fields):
name, value = field
expect(
page.get_by_test_id("key-value-table-row").nth(rowNumber).locator("dt")
page.get_by_test_id(
"key-value-table-row").nth(rowNumber).locator("dt")
).to_contain_text(name)
expect(
page.get_by_test_id("key-value-table-row").nth(rowNumber).locator("dd")
page.get_by_test_id(
"key-value-table-row").nth(rowNumber).locator("dd")
).to_contain_text(value)
def test_market_info_current_fees(page: Page):
# 6002-MDET-101
page.get_by_test_id(market_title_test_id).get_by_text("Current fees").click()
page.get_by_test_id(market_title_test_id).get_by_text(
"Current fees").click()
fields = [
["Maker Fee", "10%"],
["Infrastructure Fee", "0.05%"],
@@ -58,7 +61,8 @@ def test_market_info_current_fees(page: Page):
def test_market_info_market_price(page: Page):
# 6002-MDET-102
page.get_by_test_id(market_title_test_id).get_by_text("Market price").click()
page.get_by_test_id(market_title_test_id).get_by_text(
"Market price").click()
fields = [
["Mark Price", "107.50"],
["Best Bid Price", "101.50"],
@@ -67,25 +71,25 @@ def test_market_info_market_price(page: Page):
]
validate_info_section(page, fields)
#TODO: remove skip once volume is fixed
""" def test_market_info_market_volume(page: Page):
def test_market_info_market_volume(page: Page):
# 6002-MDET-103
page.get_by_test_id(market_title_test_id).get_by_text("Market volume").click()
page.get_by_test_id(market_title_test_id).get_by_text(
"Market volume").click()
fields = [
["24 Hour Volume", "0 (0 )"],
["24 Hour Volume", "-"],
["Open Interest", "1"],
["Best Bid Volume", "99"],
["Best Offer Volume", "99"],
["Best Static Bid Volume", "1"],
["Best Static Offer Volume", "1"],
]
validate_info_section(page, fields) """
validate_info_section(page, fields)
def test_market_info_liquidation_strategy(page: Page):
page.get_by_test_id(market_title_test_id).get_by_text(
"Liquidation strategy"
).click()
"Liquidation strategy").click()
fields = [
["Disposal Fraction", "1"],
["Disposal Time Step", "1"],
@@ -97,14 +101,16 @@ def test_market_info_liquidation_strategy(page: Page):
def test_market_info_liquidation(page: Page):
# 6002-MDET-104
page.get_by_test_id(market_title_test_id).get_by_text("Liquidations").click()
page.get_by_test_id(market_title_test_id).get_by_text(
"Liquidations").click()
fields = [["Insurance Pool Balance", "0.00 tDAI"]]
validate_info_section(page, fields)
def test_market_info_key_details(page: Page, vega: VegaServiceNull):
# 6002-MDET-201
page.get_by_test_id(market_title_test_id).get_by_text("Key details").click()
page.get_by_test_id(market_title_test_id).get_by_text(
"Key details").click()
market_id = vega.find_market_id("BTC:DAI_2023")
short_market_id = market_id[:6] + "" + market_id[-4:]
fields = [
@@ -150,7 +156,8 @@ def test_market_info_oracle(page: Page):
def test_market_info_settlement_asset(page: Page, vega: VegaServiceNull):
# 6002-MDET-206
page.get_by_test_id(market_title_test_id).get_by_text("Settlement asset").click()
page.get_by_test_id(market_title_test_id).get_by_text(
"Settlement asset").click()
tdai_id = vega.find_asset_id("tDAI")
tdai_id_short = tdai_id[:6] + "" + tdai_id[-4:]
fields = [
@@ -204,7 +211,8 @@ def test_market_info_margin_scaling_factors(page: Page):
def test_market_info_risk_factors(page: Page):
# 6002-MDET-210
page.get_by_test_id(market_title_test_id).get_by_text("Risk factors").click()
page.get_by_test_id(market_title_test_id).get_by_text(
"Risk factors").click()
fields = [
["Long", "0.05153"],
["Short", "0.05422"],
@@ -224,7 +232,8 @@ def test_market_info_price_monitoring_bounds(page: Page):
expect(page.locator("p.col-span-1").nth(0)).to_contain_text(
"99.9999% probability price bounds"
)
expect(page.locator("p.col-span-1").nth(1)).to_contain_text("Within 86,400 seconds")
expect(page.locator("p.col-span-1").nth(1)
).to_contain_text("Within 86,400 seconds")
fields = [
["Highest Price", "138.66685 BTC"],
["Lowest Price", "83.11038 BTC"],
@@ -245,7 +254,7 @@ def test_market_info_liquidity_monitoring_parameters(page: Page):
# Liquidity resolves to 3 results
def test_market_info_liquidity(page: Page):
def test_market_info_liquidit(page: Page):
# 6002-MDET-213
page.get_by_test_id(market_title_test_id).get_by_text(
"Liquidity", exact=True
@@ -274,14 +283,17 @@ def test_market_info_proposal(page: Page, vega: VegaServiceNull):
# 6002-MDET-301
page.get_by_test_id(market_title_test_id).get_by_text("Proposal").click()
first_link = (
page.get_by_test_id("accordion-content").get_by_test_id("external-link").first
page.get_by_test_id(
"accordion-content").get_by_test_id("external-link").first
)
second_link = (
page.get_by_test_id("accordion-content").get_by_test_id("external-link").nth(1)
page.get_by_test_id(
"accordion-content").get_by_test_id("external-link").nth(1)
)
expect(first_link).to_have_text("View governance proposal")
expect(first_link).to_have_attribute(
"href", re.compile(rf'(\/proposals\/{vega.find_market_id("BTC:DAI_2023")})')
"href", re.compile(
rf'(\/proposals\/{vega.find_market_id("BTC:DAI_2023")})')
)
expect(second_link).to_have_text("Propose a change to market")
@@ -292,10 +304,12 @@ def test_market_info_proposal(page: Page, vega: VegaServiceNull):
def test_market_info_succession_line(page: Page, vega: VegaServiceNull):
page.get_by_test_id(market_title_test_id).get_by_text("Succession line").click()
page.get_by_test_id(market_title_test_id).get_by_text(
"Succession line").click()
market_id = vega.find_market_id("BTC:DAI_2023")
succession_line = page.get_by_test_id("succession-line-item")
expect(succession_line.get_by_test_id("external-link")).to_have_text("BTC:DAI_2023")
expect(succession_line.get_by_test_id(
"external-link")).to_have_text("BTC:DAI_2023")
expect(succession_line.get_by_test_id("external-link")).to_have_attribute(
"href", re.compile(rf"(\/proposals\/{market_id})")
)
+192 -184
View File
@@ -10,218 +10,228 @@ order_tab = "tab-orders"
@pytest.fixture(scope="module")
def setup_environment(request, browser):
# Initialize Vega with cleanup
def vega(request):
with init_vega(request) as vega_instance:
request.addfinalizer(lambda: cleanup_container(vega_instance))
request.addfinalizer(lambda: cleanup_container(vega_instance)) # Register the cleanup function
yield vega_instance
# Setup multiple markets
markets = {
"market_1": setup_continuous_market(vega_instance, custom_market_name="market-1"),
"market_2": setup_continuous_market(vega_instance, custom_market_name="market-2"),
"market_3": setup_continuous_market(vega_instance, custom_market_name="market-3"),
"market_4": setup_continuous_market(vega_instance, custom_market_name="market-4"),
"market_5": setup_simple_market(vega_instance, custom_market_name="market-5"),
}
# Execute a series of orders across different markets
# Example for market_1 orders, adjust as necessary for your test scenario
vega_instance.submit_order(
trading_key="Key 1",
market_id=markets["market_1"],
time_in_force="TIME_IN_FORCE_IOC",
order_type="TYPE_LIMIT",
side="SIDE_SELL",
volume=100,
price=130,
)
vega_instance.forward("2s")
vega_instance.wait_fn(1)
vega_instance.wait_for_total_catchup()
@pytest.fixture(scope="module", autouse=True)
def markets(vega: VegaServiceNull):
market_1 = setup_continuous_market(
vega,
custom_market_name="market-1",
)
market_2 = setup_continuous_market(
vega,
custom_market_name="market-2",
)
market_3 = setup_continuous_market(
vega,
custom_market_name="market-3",
)
market_4 = setup_continuous_market(
vega,
custom_market_name="market-4",
)
market_5 = setup_simple_market(
vega,
custom_market_name="market-5",
)
vega_instance.submit_order(
trading_key="Key 1",
market_id=markets["market_1"],
time_in_force="TIME_IN_FORCE_GTC",
order_type="TYPE_LIMIT",
side="SIDE_SELL",
volume=100,
price=88,
)
vega.submit_order(
trading_key="Key 1",
market_id=market_1,
time_in_force="TIME_IN_FORCE_IOC",
order_type="TYPE_LIMIT",
side="SIDE_SELL",
volume=100,
price=130,
)
vega_instance.forward("2s")
vega_instance.wait_fn(1)
vega_instance.wait_for_total_catchup()
vega.forward("2s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
vega_instance.submit_order(
trading_key="Key 1",
market_id=markets["market_1"],
time_in_force="TIME_IN_FORCE_IOC",
order_type="TYPE_LIMIT",
side="SIDE_SELL",
volume=100,
price=88,
)
vega.submit_order(
trading_key="Key 1",
market_id=market_1,
time_in_force="TIME_IN_FORCE_GTC",
order_type="TYPE_LIMIT",
side="SIDE_SELL",
volume=100,
price=88,
)
vega_instance.forward("2s")
vega_instance.wait_fn(1)
vega_instance.wait_for_total_catchup()
vega.forward("2s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
vega_instance.submit_order(
trading_key="Key 1",
market_id=markets["market_1"],
time_in_force="TIME_IN_FORCE_GTC",
order_type="TYPE_LIMIT",
side="SIDE_SELL",
volume=1e10,
price=130,
wait=False,
)
vega.submit_order(
trading_key="Key 1",
market_id=market_1,
time_in_force="TIME_IN_FORCE_IOC",
order_type="TYPE_LIMIT",
side="SIDE_SELL",
volume=100,
price=88,
)
vega_instance.forward("2s")
vega_instance.wait_fn(1)
vega_instance.wait_for_total_catchup()
vega.forward("2s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
vega_instance.submit_order(
trading_key="Key 1",
market_id=markets["market_2"],
time_in_force="TIME_IN_FORCE_IOC",
order_type="TYPE_LIMIT",
side="SIDE_BUY",
volume=100,
price=104,
)
vega_instance.forward("2s")
vega_instance.wait_fn(1)
vega_instance.wait_for_total_catchup()
vega.submit_order(
trading_key="Key 1",
market_id=market_1,
time_in_force="TIME_IN_FORCE_GTC",
order_type="TYPE_LIMIT",
side="SIDE_SELL",
volume=1e10,
price=130,
wait=False,
)
vega_instance.submit_order(
trading_key="Key 1",
market_id=markets["market_3"],
time_in_force="TIME_IN_FORCE_GTT",
order_type="TYPE_LIMIT",
side="SIDE_SELL",
volume=10,
price=120,
expires_at=vega_instance.get_blockchain_time() + 5 * 1e9,
)
vega.forward("2s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
vega_instance.forward("2s")
vega_instance.wait_fn(1)
vega_instance.wait_for_total_catchup()
vega.submit_order(
trading_key="Key 1",
market_id=market_2,
time_in_force="TIME_IN_FORCE_IOC",
order_type="TYPE_LIMIT",
side="SIDE_BUY",
volume=100,
price=104,
)
vega.forward("2s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
vega_instance.submit_order(
market_id=markets["market_4"],
trading_key="Key 1",
side="SIDE_BUY",
order_type="TYPE_LIMIT",
pegged_order=PeggedOrder(reference="PEGGED_REFERENCE_MID", offset=5),
time_in_force="TIME_IN_FORCE_GTC",
volume=20,
)
vega.submit_order(
trading_key="Key 1",
market_id=market_3,
time_in_force="TIME_IN_FORCE_GTT",
order_type="TYPE_LIMIT",
side="SIDE_SELL",
volume=10,
price=120,
expires_at=vega.get_blockchain_time() + 5 * 1e9,
)
vega_instance.forward("2s")
vega_instance.wait_fn(1)
vega_instance.wait_for_total_catchup()
vega.forward("2s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
vega_instance.submit_order(
market_id=markets["market_4"],
trading_key="Key 1",
side="SIDE_BUY",
order_type="TYPE_LIMIT",
pegged_order=PeggedOrder(reference="PEGGED_REFERENCE_BEST_BID", offset=10),
time_in_force="TIME_IN_FORCE_GTC",
volume=40,
)
vega.submit_order(
market_id=market_4,
trading_key="Key 1",
side="SIDE_BUY",
order_type="TYPE_LIMIT",
pegged_order=PeggedOrder(reference="PEGGED_REFERENCE_MID", offset=5),
time_in_force="TIME_IN_FORCE_GTC",
volume=20,
)
vega_instance.forward("2s")
vega_instance.wait_fn(1)
vega_instance.wait_for_total_catchup()
vega.forward("2s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
vega_instance.submit_order(
market_id=markets["market_4"],
trading_key="Key 1",
side="SIDE_SELL",
order_type="TYPE_LIMIT",
pegged_order=PeggedOrder(reference="PEGGED_REFERENCE_BEST_ASK", offset=15),
time_in_force="TIME_IN_FORCE_GTC",
volume=60,
)
vega.submit_order(
market_id=market_4,
trading_key="Key 1",
side="SIDE_BUY",
order_type="TYPE_LIMIT",
pegged_order=PeggedOrder(reference="PEGGED_REFERENCE_BEST_BID", offset=10),
time_in_force="TIME_IN_FORCE_GTC",
volume=40,
)
vega_instance.forward("2s")
vega_instance.wait_fn(1)
vega_instance.wait_for_total_catchup()
vega.forward("2s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
vega_instance.submit_order(
market_id=markets["market_5"],
trading_key="Key 1",
side="SIDE_SELL",
order_type="TYPE_LIMIT",
pegged_order=PeggedOrder(reference="PEGGED_REFERENCE_BEST_ASK", offset=15),
wait=False,
time_in_force="TIME_IN_FORCE_GTC",
volume=60,
)
vega.submit_order(
market_id=market_4,
trading_key="Key 1",
side="SIDE_SELL",
order_type="TYPE_LIMIT",
pegged_order=PeggedOrder(reference="PEGGED_REFERENCE_BEST_ASK", offset=15),
time_in_force="TIME_IN_FORCE_GTC",
volume=60,
)
vega_instance.forward("2s")
vega_instance.wait_fn(1)
vega_instance.wait_for_total_catchup()
vega.forward("2s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
vega_instance.submit_order(
trading_key="Key 1",
market_id=markets["market_2"],
time_in_force="TIME_IN_FORCE_GTC",
order_type="TYPE_LIMIT",
side="SIDE_SELL",
volume=10,
price=150,
)
vega_instance.wait_fn(1)
vega_instance.wait_for_total_catchup()
vega.submit_order(
market_id=market_5,
trading_key="Key 1",
side="SIDE_SELL",
order_type="TYPE_LIMIT",
pegged_order=PeggedOrder(reference="PEGGED_REFERENCE_BEST_ASK", offset=15),
wait=False,
time_in_force="TIME_IN_FORCE_GTC",
volume=60,
)
vega_instance.submit_order(
trading_key="Key 1",
market_id=markets["market_2"],
time_in_force="TIME_IN_FORCE_GTC",
order_type="TYPE_LIMIT",
side="SIDE_SELL",
volume=10,
price=160,
)
vega.forward("2s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
vega_instance.wait_fn(1)
vega_instance.wait_for_total_catchup()
vega.submit_order(
trading_key="Key 1",
market_id=market_2,
time_in_force="TIME_IN_FORCE_GTC",
order_type="TYPE_LIMIT",
side="SIDE_SELL",
volume=10,
price=150,
)
vega.wait_fn(1)
vega.wait_for_total_catchup()
vega_instance.submit_order(
trading_key="Key 1",
market_id=markets["market_3"],
time_in_force="TIME_IN_FORCE_GTC",
order_type="TYPE_LIMIT",
side="SIDE_BUY",
volume=10,
price=60,
)
vega.submit_order(
trading_key="Key 1",
market_id=market_2,
time_in_force="TIME_IN_FORCE_GTC",
order_type="TYPE_LIMIT",
side="SIDE_SELL",
volume=10,
price=160,
)
vega_instance.wait_fn(1)
vega_instance.wait_for_total_catchup()
# Initialize page and setup
yield vega_instance, markets
vega.wait_fn(1)
vega.wait_for_total_catchup()
vega.submit_order(
trading_key="Key 1",
market_id=market_3,
time_in_force="TIME_IN_FORCE_GTC",
order_type="TYPE_LIMIT",
side="SIDE_BUY",
volume=10,
price=60,
)
vega.wait_fn(1)
vega.wait_for_total_catchup()
@pytest.fixture(scope="module")
def page(setup_environment, browser, request):
vega_instance, markets = setup_environment
with init_page(vega_instance, browser, request) as page:
def page(vega, browser, request):
with init_page(vega, browser, request) as page:
risk_accepted_setup(page)
auth_setup(vega_instance, page)
auth_setup(vega, page)
page.goto("/")
page.get_by_test_id("All").click()
yield page
# close toast that is still opened after test
@pytest.fixture(autouse=True)
def after_each(page: Page):
yield
@@ -371,8 +381,7 @@ def test_order_status_pegged_mid(page: Page):
)
def test_order_amend_order(setup_environment, page:Page):
vega, markets = setup_environment
def test_order_amend_order(vega: VegaServiceNull, page: Page):
# 7002-SORD-053
# 7003-MORD-012
# 7003-MORD-014
@@ -393,13 +402,13 @@ def test_order_amend_order(setup_environment, page:Page):
)
def test_order_cancel_single_order(setup_environment, page:Page):
vega, markets = setup_environment
def test_order_cancel_single_order(vega: VegaServiceNull, page: Page):
# 7003-MORD-009
# 7003-MORD-010
# 7003-MORD-011
# 7002-SORD-043
page.get_by_test_id("cancel").first.click()
wait_for_toast_confirmation(page, timeout=5000)
vega.wait_fn(1)
vega.wait_for_total_catchup()
@@ -411,8 +420,7 @@ def test_order_cancel_single_order(setup_environment, page:Page):
)
def test_order_cancel_all_orders(setup_environment, page:Page):
vega, markets = setup_environment
def test_order_cancel_all_orders(vega: VegaServiceNull, page: Page):
# 7003-MORD-009
# 7003-MORD-010
# 7003-MORD-011
@@ -57,7 +57,7 @@ class TestPerpetuals:
page.goto(f"/#/markets/{perps_market}")
page.get_by_test_id("Funding payments").click()
row = page.locator(row_selector)
expect(row.locator(col_amount)).to_have_text("4.45 tDAI")
expect(row.locator(col_amount)).to_have_text("9.00 tDAI")
@pytest.mark.usefixtures("risk_accepted", "auth")
def test_funding_payment_loss(self, perps_market, page: Page, vega):
@@ -65,7 +65,7 @@ class TestPerpetuals:
change_keys(page, vega, "market_maker")
page.get_by_test_id("Funding payments").click()
row = page.locator(row_selector)
expect(row.locator(col_amount)).to_have_text("-13.35 tDAI")
expect(row.locator(col_amount)).to_have_text("-27.00 tDAI")
@pytest.mark.usefixtures("risk_accepted", "auth")
def test_funding_header(self, perps_market, page: Page):
@@ -1,15 +1,8 @@
import pytest
import vega_sim.proto.vega as vega_protos
from typing import Tuple, Generator
from rewards_test_ids import *
from playwright.sync_api import Page, expect
from conftest import (
init_vega,
init_page,
auth_setup,
risk_accepted_setup,
cleanup_container,
)
from conftest import init_vega, init_page, auth_setup, risk_accepted_setup, cleanup_container
from fixtures.market import setup_continuous_market
from actions.utils import next_epoch, change_keys
from wallet_config import MM_WALLET
@@ -17,20 +10,22 @@ from vega_sim.null_service import VegaServiceNull
@pytest.fixture(scope="module")
def setup_environment(request, browser) -> Generator[Tuple[Page, str, str], None, None]:
def vega(request):
with init_vega(request) as vega_instance:
request.addfinalizer(lambda: cleanup_container(vega_instance))
yield vega_instance
tDAI_market, tDAI_asset_id = setup_market_with_reward_program(vega_instance)
with init_page(vega_instance, browser, request) as page:
risk_accepted_setup(page)
auth_setup(vega_instance, page)
page.goto(REWARDS_URL)
change_keys(page, vega_instance, PARTY_B)
yield page, tDAI_market, tDAI_asset_id
@pytest.fixture(scope="module")
def page(vega, browser, request):
with init_page(vega, browser, request) as page:
risk_accepted_setup(page)
auth_setup(vega, page)
page.goto(REWARDS_URL)
change_keys(page, vega, PARTY_B)
yield page
@pytest.fixture(scope="module", autouse=True)
def setup_market_with_reward_program(vega: VegaServiceNull):
tDAI_market = setup_continuous_market(vega)
PARTY_A, PARTY_B, PARTY_C, PARTY_D = keys(vega)
@@ -88,39 +83,39 @@ def setup_market_with_reward_program(vega: VegaServiceNull):
return tDAI_market, tDAI_asset_id
@pytest.mark.xdist_group(name="test_rewards_hoarder_tier_0")
def test_network_reward_pot(
setup_environment: Tuple[Page, str, str],
) -> None:
page, tDAI_market, tDAI_asset_id = setup_environment
page: Page,
):
expect(page.get_by_test_id(TOTAL_REWARDS)).to_have_text("50.00 tDAI")
@pytest.mark.xdist_group(name="test_rewards_hoarder_tier_0")
def test_reward_multiplier(
setup_environment: Tuple[Page, str, str],
) -> None:
page, tDAI_market, tDAI_asset_id = setup_environment
page: Page,
):
expect(page.get_by_test_id(COMBINED_MULTIPLIERS)).to_have_text("1x")
expect(page.get_by_test_id(STREAK_REWARD_MULTIPLIER_VALUE)).to_have_text("1x")
expect(page.get_by_test_id(HOARDER_REWARD_MULTIPLIER_VALUE)).to_have_text("1x")
@pytest.mark.xdist_group(name="test_rewards_hoarder_tier_0")
def test_hoarder_bonus(
setup_environment: Tuple[Page, str, str],
) -> None:
page, tDAI_market, tDAI_asset_id = setup_environment
page: Page,
):
expect(page.get_by_test_id(HOARDER_BONUS_TOTAL_HOARDED)).to_contain_text(
"5,000,000"
)
@pytest.mark.xdist_group(name="test_rewards_hoarder_tier_0")
def test_reward_history(
setup_environment: Tuple[Page, str, str],
) -> None:
page, tDAI_market, tDAI_asset_id = setup_environment
page: Page,
):
page.locator('[name="fromEpoch"]').fill("1")
expect((page.get_by_role(ROW).locator(PRICE_TAKING_COL_ID)).nth(1)).to_have_text(
"100.00100.00%"
)
expect((page.get_by_role(ROW).locator(TOTAL_COL_ID)).nth(1)).to_have_text("100.00")
page.get_by_test_id(EARNED_BY_ME_BUTTON).click()
expect((page.get_by_role(ROW).locator(TOTAL_COL_ID)).nth(1)).to_have_text("50.00")
expect((page.get_by_role(ROW).locator(TOTAL_COL_ID)).nth(1)).to_have_text("50.00")
@@ -1,15 +1,8 @@
import pytest
from rewards_test_ids import *
from typing import Tuple, Generator
import vega_sim.proto.vega as vega_protos
from playwright.sync_api import Page, expect
from conftest import (
init_vega,
init_page,
auth_setup,
risk_accepted_setup,
cleanup_container,
)
from conftest import init_vega, init_page, auth_setup, risk_accepted_setup, cleanup_container
from fixtures.market import setup_continuous_market
from actions.utils import next_epoch, change_keys
from wallet_config import MM_WALLET
@@ -17,21 +10,23 @@ from vega_sim.null_service import VegaServiceNull
@pytest.fixture(scope="module")
def setup_environment(request, browser) -> Generator[Tuple[Page, str, str], None, None]:
def vega(request):
with init_vega(request) as vega_instance:
request.addfinalizer(lambda: cleanup_container(vega_instance))
tDAI_market, tDAI_asset_id = setup_market_with_reward_program(vega_instance)
with init_page(vega_instance, browser, request) as page:
risk_accepted_setup(page)
auth_setup(vega_instance, page)
page.goto(REWARDS_URL)
change_keys(page, vega_instance, PARTY_B)
yield page, tDAI_market, tDAI_asset_id
request.addfinalizer(lambda: cleanup_container(vega_instance))
yield vega_instance
@pytest.fixture(scope="module")
def page(vega, browser, request):
with init_page(vega, browser, request) as page:
risk_accepted_setup(page)
auth_setup(vega, page)
page.goto(REWARDS_URL)
change_keys(page, vega, PARTY_B)
yield page
@pytest.fixture(scope="module", autouse=True)
def setup_market_with_reward_program(vega: VegaServiceNull):
tDAI_market = setup_continuous_market(vega)
PARTY_A, PARTY_B, PARTY_C, PARTY_D = keys(vega)
@@ -140,35 +135,31 @@ def setup_market_with_reward_program(vega: VegaServiceNull):
return tDAI_market, tDAI_asset_id
@pytest.mark.xdist_group(name="test_rewards_hoarder_tier_1")
def test_network_reward_pot(
setup_environment: Tuple[Page, str, str],
) -> None:
page, tDAI_market, tDAI_asset_id = setup_environment
page: Page,
):
expect(page.get_by_test_id(TOTAL_REWARDS)).to_have_text("166.66666 tDAI")
@pytest.mark.xdist_group(name="test_rewards_hoarder_tier_1")
def test_reward_multiplier(
setup_environment: Tuple[Page, str, str],
) -> None:
page, tDAI_market, tDAI_asset_id = setup_environment
page: Page,
):
expect(page.get_by_test_id(COMBINED_MULTIPLIERS)).to_have_text("2x")
expect(page.get_by_test_id(STREAK_REWARD_MULTIPLIER_VALUE)).to_have_text("1x")
expect(page.get_by_test_id(HOARDER_REWARD_MULTIPLIER_VALUE)).to_have_text("2x")
def test_hoarder_bonus(
setup_environment: Tuple[Page, str, str],
) -> None:
page, tDAI_market, tDAI_asset_id = setup_environment
@pytest.mark.xdist_group(name="test_rewards_hoarder_tier_1")
def test_hoarder_bonus(page: Page):
expect(page.get_by_test_id(HOARDER_BONUS_TOTAL_HOARDED)).to_contain_text(
"16,666,666"
)
def test_reward_history(
setup_environment: Tuple[Page, str, str],
) -> None:
page, tDAI_market, tDAI_asset_id = setup_environment
@pytest.mark.xdist_group(name="test_rewards_hoarder_tier_1")
def test_reward_history(page: Page):
page.locator('[name="fromEpoch"]').fill("1")
expect((page.get_by_role(ROW).locator(PRICE_TAKING_COL_ID)).nth(1)).to_have_text(
"299.99999100.00%"
@@ -179,4 +170,4 @@ def test_reward_history(
page.get_by_test_id(EARNED_BY_ME_BUTTON).click()
expect((page.get_by_role(ROW).locator(TOTAL_COL_ID)).nth(1)).to_have_text(
"166.66666"
)
)
@@ -1,6 +1,5 @@
import pytest
from rewards_test_ids import *
from typing import Tuple, Generator
import vega_sim.proto.vega as vega_protos
from playwright.sync_api import Page, expect
from conftest import (
@@ -17,23 +16,23 @@ from vega_sim.null_service import VegaServiceNull
@pytest.fixture(scope="module")
def setup_environment(request, browser) -> Generator[Tuple[Page, str, str], None, None]:
def vega(request):
with init_vega(request) as vega_instance:
request.addfinalizer(lambda: cleanup_container(vega_instance))
tDAI_market, tDAI_asset_id = setup_market_with_reward_program(vega_instance)
with init_page(vega_instance, browser, request) as page:
risk_accepted_setup(page)
auth_setup(vega_instance, page)
page.goto(REWARDS_URL)
change_keys(page, vega_instance, PARTY_B)
yield page, tDAI_market, tDAI_asset_id
yield vega_instance
@pytest.fixture(scope="module")
def page(vega, browser, request):
with init_page(vega, browser, request) as page:
risk_accepted_setup(page)
auth_setup(vega, page)
page.goto(REWARDS_URL)
change_keys(page, vega, PARTY_B)
yield page
@pytest.fixture(scope="module", autouse=True)
def setup_market_with_reward_program(vega: VegaServiceNull):
tDAI_market = setup_continuous_market(vega)
PARTY_A, PARTY_B, PARTY_C, PARTY_D = keys(vega)
@@ -91,23 +90,25 @@ def setup_market_with_reward_program(vega: VegaServiceNull):
return tDAI_market, tDAI_asset_id
@pytest.mark.xdist_group(name="test_rewards_activity_tier_0")
def test_network_reward_pot(
setup_environment: Tuple[Page, str, str],
) -> None:
page, tDAI_market, tDAI_asset_id = setup_environment
page: Page,
):
expect(page.get_by_test_id(TOTAL_REWARDS)).to_have_text("50.00 tDAI")
page.pause()
@pytest.mark.xdist_group(name="test_rewards_activity_tier_0")
def test_reward_multiplier(
setup_environment: Tuple[Page, str, str],
) -> None:
page, tDAI_market, tDAI_asset_id = setup_environment
page: Page,
):
page.pause()
expect(page.get_by_test_id(COMBINED_MULTIPLIERS)).to_have_text("1x")
expect(page.get_by_test_id(STREAK_REWARD_MULTIPLIER_VALUE)).to_have_text("1x")
expect(page.get_by_test_id(HOARDER_REWARD_MULTIPLIER_VALUE)).to_have_text("1x")
"""
""" @pytest.mark.xdist_group(name="test_rewards_activity_tier_0")
def test_activity_streak(
page: Page,
):
@@ -116,6 +117,7 @@ def test_activity_streak(
)
@pytest.mark.xdist_group(name="test_rewards_activity_tier_0")
def test_reward_history(
page: Page,
):
@@ -1,15 +1,8 @@
import pytest
from rewards_test_ids import *
from typing import Tuple, Generator
import vega_sim.proto.vega as vega_protos
from playwright.sync_api import Page, expect
from conftest import (
init_vega,
init_page,
auth_setup,
risk_accepted_setup,
cleanup_container,
)
from conftest import init_vega, init_page, auth_setup, risk_accepted_setup, cleanup_container
from fixtures.market import setup_continuous_market
from actions.utils import next_epoch, change_keys
from wallet_config import MM_WALLET
@@ -17,21 +10,22 @@ from vega_sim.null_service import VegaServiceNull
@pytest.fixture(scope="module")
def setup_environment(request, browser) -> Generator[Tuple[Page, str, str], None, None]:
def vega(request):
with init_vega(request) as vega_instance:
request.addfinalizer(lambda: cleanup_container(vega_instance))
tDAI_market, tDAI_asset_id = setup_market_with_reward_program(vega_instance)
with init_page(vega_instance, browser, request) as page:
risk_accepted_setup(page)
auth_setup(vega_instance, page)
page.goto(REWARDS_URL)
change_keys(page, vega_instance, PARTY_B)
yield page, tDAI_market, tDAI_asset_id
yield vega_instance
@pytest.fixture(scope="module")
def page(vega, browser, request):
with init_page(vega, browser, request) as page:
risk_accepted_setup(page)
auth_setup(vega, page)
page.goto(REWARDS_URL)
change_keys(page, vega, PARTY_B)
yield page
@pytest.fixture(scope="module", autouse=True)
def setup_market_with_reward_program(vega: VegaServiceNull):
tDAI_market = setup_continuous_market(vega)
PARTY_A, PARTY_B, PARTY_C, PARTY_D = keys(vega)
@@ -134,35 +128,34 @@ def setup_market_with_reward_program(vega: VegaServiceNull):
return tDAI_market, tDAI_asset_id
def test_network_reward_pot(
setup_environment: Tuple[Page, str, str],
) -> None:
page, tDAI_market, tDAI_asset_id = setup_environment
@pytest.mark.xdist_group(name="test_rewards_activity_tier_1")
def test_network_reward_pot(page: Page):
expect(page.get_by_test_id(TOTAL_REWARDS)).to_have_text("116.66666 tDAI")
@pytest.mark.xdist_group(name="test_rewards_activity_tier_1")
def test_reward_multiplier(
setup_environment: Tuple[Page, str, str],
) -> None:
page, tDAI_market, tDAI_asset_id = setup_environment
page: Page,
):
expect(page.get_by_test_id(COMBINED_MULTIPLIERS)).to_have_text("2x")
expect(page.get_by_test_id(STREAK_REWARD_MULTIPLIER_VALUE)).to_have_text("2x")
expect(page.get_by_test_id(HOARDER_REWARD_MULTIPLIER_VALUE)).to_have_text("1x")
@pytest.mark.xdist_group(name="test_rewards_activity_tier_1")
def test_activity_streak(
setup_environment: Tuple[Page, str, str],
) -> None:
page, tDAI_market, tDAI_asset_id = setup_environment
page: Page,
):
expect(page.get_by_test_id(EPOCH_STREAK)).to_have_text(
"Active trader: 7 epochs so far (Tier 1 as of last epoch)"
)
@pytest.mark.xdist_group(name="test_rewards_activity_tier_1")
def test_reward_history(
setup_environment: Tuple[Page, str, str],
) -> None:
page, tDAI_market, tDAI_asset_id = setup_environment
page: Page,
):
page.locator('[name="fromEpoch"]').fill("1")
expect((page.get_by_role(ROW).locator(PRICE_TAKING_COL_ID)).nth(1)).to_have_text(
"300.00100.00%"
@@ -174,10 +167,10 @@ def test_reward_history(
)
@pytest.mark.xdist_group(name="test_rewards_activity_tier_1")
def test_redeem(
setup_environment: Tuple[Page, str, str],
) -> None:
page, tDAI_market, tDAI_asset_id = setup_environment
page: Page,
):
page.get_by_test_id("redeem-rewards-button").click()
available_to_withdraw = page.get_by_test_id(
"available-to-withdraw-value"
@@ -191,4 +184,4 @@ def test_redeem(
)
page.get_by_test_id("use-max-button").first.click()
expect(page.get_by_test_id(TRANSFER_AMOUNT)).to_have_text(available_to_withdraw)
expect(page.get_by_test_id(TRANSFER_AMOUNT)).to_have_text(available_to_withdraw)
@@ -1,6 +1,5 @@
import pytest
from rewards_test_ids import *
from typing import Tuple, Generator
import vega_sim.proto.vega as vega_protos
from playwright.sync_api import Page, expect
from conftest import init_vega, init_page, auth_setup, risk_accepted_setup, cleanup_container
@@ -10,20 +9,24 @@ from wallet_config import MM_WALLET
from vega_sim.null_service import VegaServiceNull
@pytest.fixture(scope="module")
def setup_environment(request, browser) -> Generator[Tuple[Page, str, str], None, None]:
def vega(request):
with init_vega(request) as vega_instance:
request.addfinalizer(lambda: cleanup_container(vega_instance))
tDAI_market, tDAI_asset_id = setup_market_with_reward_program(vega_instance)
with init_page(vega_instance, browser, request) as page:
risk_accepted_setup(page)
auth_setup(vega_instance, page)
page.goto(REWARDS_URL)
change_keys(page, vega_instance, PARTY_B)
yield page, tDAI_market, tDAI_asset_id
yield vega_instance
@pytest.fixture(scope="module")
def page(vega, browser, request):
with init_page(vega, browser, request) as page:
risk_accepted_setup(page)
auth_setup(vega, page)
page.goto(REWARDS_URL)
change_keys(page, vega, PARTY_B)
yield page
@pytest.fixture(scope="module", autouse=True)
def setup_market_with_reward_program(vega: VegaServiceNull):
tDAI_market = setup_continuous_market(vega)
PARTY_A, PARTY_B, PARTY_C, PARTY_D = keys(vega)
@@ -54,16 +57,6 @@ def setup_market_with_reward_program(vega: VegaServiceNull):
)
next_epoch(vega=vega)
vega.recurring_transfer(
from_key_name=PARTY_A.name,
from_account_type=vega_protos.vega.ACCOUNT_TYPE_GENERAL,
to_account_type=vega_protos.vega.ACCOUNT_TYPE_GLOBAL_REWARD,
asset=tDAI_asset_id,
amount=100,
factor=1.0,
)
vega.wait_fn(1)
vega.wait_for_total_catchup()
vega.recurring_transfer(
from_key_name=PARTY_A.name,
from_account_type=vega_protos.vega.ACCOUNT_TYPE_GENERAL,
@@ -147,18 +140,16 @@ def setup_market_with_reward_program(vega: VegaServiceNull):
return tDAI_market, tDAI_asset_id
def test_network_reward_pot( setup_environment: Tuple[Page, str, str],
) -> None:
page, tDAI_market, tDAI_asset_id = setup_environment
@pytest.mark.xdist_group(name="test_rewards_combo_tier_1")
def test_network_reward_pot( page: Page
):
expect(page.get_by_test_id(TOTAL_REWARDS)).to_have_text("183.33333 tDAI")
@pytest.mark.xdist_group(name="test_rewards_combo_tier_1")
def test_reward_multiplier(
setup_environment: Tuple[Page, str, str],
) -> None:
page, tDAI_market, tDAI_asset_id = setup_environment
page: Page,
):
expect(page.get_by_test_id(COMBINED_MULTIPLIERS)).to_have_text("4x")
expect(page.get_by_test_id(STREAK_REWARD_MULTIPLIER_VALUE)).to_have_text(
"2x"
@@ -168,11 +159,10 @@ def test_reward_multiplier(
)
@pytest.mark.xdist_group(name="test_rewards_combo_tier_1")
def test_reward_history(
setup_environment: Tuple[Page, str, str],
) -> None:
page, tDAI_market, tDAI_asset_id = setup_environment
page: Page,
):
page.locator('[name="fromEpoch"]').fill("1")
expect((page.get_by_role(ROW).locator(PRICE_TAKING_COL_ID)).nth(1)).to_have_text(
"299.99999100.00%"
@@ -181,22 +171,4 @@ def test_reward_history(
page.get_by_test_id(EARNED_BY_ME_BUTTON).click()
expect((page.get_by_role(ROW).locator(TOTAL_COL_ID)).nth(1)).to_have_text(
"183.33333"
)
def test_staking_reward(
page: Page,
):
expect(page.get_by_test_id("active-rewards-card")).to_have_count(2)
staking_reward_card = page.get_by_test_id("active-rewards-card").nth(1)
expect(staking_reward_card).to_be_visible()
expect(staking_reward_card.get_by_test_id("entity-scope")).to_have_text("Individual")
expect(staking_reward_card.get_by_test_id("locked-for")).to_have_text("0 epochs")
expect(staking_reward_card.get_by_test_id("reward-value")).to_have_text("100.00")
expect(staking_reward_card.get_by_test_id("distribution-strategy")).to_have_text("Pro rata")
expect(staking_reward_card.get_by_test_id("dispatch-metric-info")).to_have_text(
"Staking rewards"
)
expect(staking_reward_card.get_by_test_id("assessed-over")).to_have_text("1 epoch")
expect(staking_reward_card.get_by_test_id("scope")).to_have_text("Individual")
expect(staking_reward_card.get_by_test_id("staking-requirement")).to_have_text("1.00")
expect(staking_reward_card.get_by_test_id("average-position")).to_have_text("0.00")
)
@@ -97,13 +97,10 @@ def test_banners(vega: VegaServiceNull, page: Page):
settlement_price=100,
market_id=parent_market_id,
)
vega.wait_fn(1)
vega.wait_for_total_catchup()
successor_name = "successor market name"
propose_successor(vega, parent_market_id, tdai_id, successor_name)
vega.wait_fn(1)
vega.wait_for_total_catchup()
page.reload()
# Check that the banners notifying about the successor proposal and market has been settled are shown
banner = page.get_by_test_id(market_banner)
expect(banner).to_be_attached()
+3 -3
View File
@@ -299,10 +299,10 @@ def test_leaderboard(competitions_page: Page, setup_teams_and_games):
def test_game_card(competitions_page: Page):
expect(competitions_page.get_by_test_id("active-rewards-card")).to_have_count(1)
expect(competitions_page.get_by_test_id("active-rewards-card")).to_have_count(2)
game_1 = competitions_page.get_by_test_id("active-rewards-card").first
expect(game_1).to_be_visible()
expect(game_1.get_by_test_id("entity-scope")).to_have_text("Team")
expect(game_1.get_by_test_id("entity-scope")).to_have_text("Individual")
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")
@@ -311,7 +311,7 @@ def test_game_card(competitions_page: Page):
"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("scope")).to_have_text("In team")
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")
+2 -6
View File
@@ -25,12 +25,8 @@ fragment GameFields on Game {
}
}
query Games($epochFrom: Int, $teamId: ID) {
games(
epochFrom: $epochFrom
teamId: $teamId
entityScope: ENTITY_SCOPE_TEAMS
) {
query Games($epochFrom: Int) {
games(epochFrom: $epochFrom, entityScope: ENTITY_SCOPE_TEAMS) {
edges {
node {
...GameFields
+2 -4
View File
@@ -9,7 +9,6 @@ export type GameFieldsFragment = { __typename?: 'Game', id: string, epoch: numbe
export type GamesQueryVariables = Types.Exact<{
epochFrom?: Types.InputMaybe<Types.Scalars['Int']>;
teamId?: Types.InputMaybe<Types.Scalars['ID']>;
}>;
@@ -45,8 +44,8 @@ export const GameFieldsFragmentDoc = gql`
}
${TeamEntityFragmentDoc}`;
export const GamesDocument = gql`
query Games($epochFrom: Int, $teamId: ID) {
games(epochFrom: $epochFrom, teamId: $teamId, entityScope: ENTITY_SCOPE_TEAMS) {
query Games($epochFrom: Int) {
games(epochFrom: $epochFrom, entityScope: ENTITY_SCOPE_TEAMS) {
edges {
node {
...GameFields
@@ -69,7 +68,6 @@ export const GamesDocument = gql`
* const { data, loading, error } = useGamesQuery({
* variables: {
* epochFrom: // value for 'epochFrom'
* teamId: // value for 'teamId'
* },
* });
*/
-1
View File
@@ -51,7 +51,6 @@ export const useGames = (teamId?: string, epochFrom?: number): GamesData => {
const { data, loading, error } = useGamesQuery({
variables: {
epochFrom: from,
teamId: teamId,
},
skip: !from,
fetchPolicy: 'cache-and-network',
+2 -2
View File
@@ -194,11 +194,11 @@ describe('isScopedToTeams', () => {
undefined,
makeDispatchStrategy(
EntityScope.ENTITY_SCOPE_INDIVIDUALS,
IndividualScope.INDIVIDUAL_SCOPE_IN_TEAM // individual in teams but not a team game
IndividualScope.INDIVIDUAL_SCOPE_IN_TEAM // individual in teams
),
'RecurringTransfer'
),
false,
true,
],
[
makeReward(
+11 -1
View File
@@ -14,6 +14,7 @@ import {
TransferStatus,
type DispatchStrategy,
EntityScope,
IndividualScope,
MarketState,
AccountType,
} from '@vegaprotocol/types';
@@ -74,11 +75,20 @@ export const isActiveReward = (node: RewardTransfer, currentEpoch: number) => {
/**
* Checks if given reward (transfer) is scoped to teams.
*
* A reward is scoped to teams if it's entity scope is set to teams or
* if the scope is set to individuals but the individuals are in a team.
*/
export const isScopedToTeams = (node: EnrichedRewardTransfer) =>
// scoped to teams
node.transfer.kind.dispatchStrategy?.entityScope ===
EntityScope.ENTITY_SCOPE_TEAMS;
EntityScope.ENTITY_SCOPE_TEAMS ||
// or to individuals
(node.transfer.kind.dispatchStrategy?.entityScope ===
EntityScope.ENTITY_SCOPE_INDIVIDUALS &&
// but they have to be in a team
node.transfer.kind.dispatchStrategy?.individualScope ===
IndividualScope.INDIVIDUAL_SCOPE_IN_TEAM);
/** Retrieves rewards (transfers) */
export const useRewards = ({
+2
View File
@@ -24,6 +24,7 @@ import {
ProtocolUpgradeInProgressNotification,
ProtocolUpgradeProposalNotification,
} from '@vegaprotocol/proposals';
import { ViewingBanner } from '../components/viewing-banner';
import { Telemetry } from '../components/telemetry';
import { SSRLoader } from './ssr-loader';
import { PartyActiveOrdersHandler } from './party-active-orders-handler';
@@ -76,6 +77,7 @@ function AppBody({ Component }: AppProps) {
mode={ProtocolUpgradeCountdownMode.IN_ESTIMATED_TIME_REMAINING}
/>
<ProtocolUpgradeInProgressNotification />
<ViewingBanner />
</div>
<div data-testid={`pathname-${location.pathname}`}>
<Component />
-7
View File
@@ -62,10 +62,3 @@ export const DENY_LIST: Record<string, string[]> = {
'fdf0ec118d98393a7702cf72e46fc87ad680b152f64b2aac59e093ac2d688fbb',
],
};
// We need a record of USDT on mainnet as it needs special handling for
// deposits and approvals due to the contract not conforming exactly
// to ERC20
export const USDT_ID = {
MAINNET: 'bf1e88d19db4b3ca0d1d5bdb73718a01686b18cf731ca26adedf3c8b83802bba',
} as const;
-5
View File
@@ -6,12 +6,7 @@ export const PENNANT_INTERVAL_MAP = {
[Interval.INTERVAL_I1M]: PennantInterval.I1M,
[Interval.INTERVAL_I5M]: PennantInterval.I5M,
[Interval.INTERVAL_I15M]: PennantInterval.I15M,
[Interval.INTERVAL_I30M]: PennantInterval.I30M,
[Interval.INTERVAL_I1H]: PennantInterval.I1H,
[Interval.INTERVAL_I4H]: PennantInterval.I4H,
[Interval.INTERVAL_I6H]: PennantInterval.I6H,
[Interval.INTERVAL_I8H]: PennantInterval.I8H,
[Interval.INTERVAL_I12H]: PennantInterval.I12H,
[Interval.INTERVAL_I1D]: PennantInterval.I1D,
[Interval.INTERVAL_I7D]: PennantInterval.I7D,
} as const;
-45
View File
@@ -34,28 +34,18 @@ const INTERVAL_TO_PENNANT_MAP = {
[PennantInterval.I1M]: Schema.Interval.INTERVAL_I1M,
[PennantInterval.I5M]: Schema.Interval.INTERVAL_I5M,
[PennantInterval.I15M]: Schema.Interval.INTERVAL_I15M,
[PennantInterval.I30M]: Schema.Interval.INTERVAL_I30M,
[PennantInterval.I1H]: Schema.Interval.INTERVAL_I1H,
[PennantInterval.I4H]: Schema.Interval.INTERVAL_I4H,
[PennantInterval.I6H]: Schema.Interval.INTERVAL_I6H,
[PennantInterval.I8H]: Schema.Interval.INTERVAL_I8H,
[PennantInterval.I12H]: Schema.Interval.INTERVAL_I12H,
[PennantInterval.I1D]: Schema.Interval.INTERVAL_I1D,
[PennantInterval.I7D]: Schema.Interval.INTERVAL_I7D,
};
const defaultConfig = {
decimalPlaces: 5,
supportedIntervals: [
PennantInterval.I7D,
PennantInterval.I1D,
PennantInterval.I12H,
PennantInterval.I8H,
PennantInterval.I6H,
PennantInterval.I4H,
PennantInterval.I1H,
PennantInterval.I15M,
PennantInterval.I30M,
PennantInterval.I5M,
PennantInterval.I1M,
],
@@ -147,15 +137,10 @@ export class VegaDataSource implements DataSource {
decimalPlaces: this._decimalPlaces,
positionDecimalPlaces: this._positionDecimalPlaces,
supportedIntervals: [
PennantInterval.I7D,
PennantInterval.I1D,
PennantInterval.I12H,
PennantInterval.I8H,
PennantInterval.I6H,
PennantInterval.I4H,
PennantInterval.I1H,
PennantInterval.I15M,
PennantInterval.I30M,
PennantInterval.I5M,
PennantInterval.I1M,
],
@@ -270,10 +255,6 @@ const getDuration = (
multiplier: number
): Duration => {
switch (interval) {
case 'I7D':
return {
days: 7 * multiplier,
};
case 'I1D':
return {
days: 1 * multiplier,
@@ -290,30 +271,14 @@ const getDuration = (
return {
minutes: 5 * multiplier,
};
case 'I4H':
return {
hours: 4 * multiplier,
};
case 'I6H':
return {
hours: 6 * multiplier,
};
case 'I8H':
return {
hours: 8 * multiplier,
};
case 'I12H':
return {
hours: 12 * multiplier,
};
case 'I15M':
return {
minutes: 15 * multiplier,
};
case 'I30M':
return {
minutes: 30 * multiplier,
};
}
};
@@ -323,24 +288,14 @@ const getDifference = (
dateRight: Date
): number => {
switch (interval) {
case 'I7D':
return differenceInDays(dateRight, dateLeft) / 7;
case 'I1D':
return differenceInDays(dateRight, dateLeft);
case 'I12H':
return differenceInHours(dateRight, dateLeft) / 12;
case 'I8H':
return differenceInHours(dateRight, dateLeft) / 8;
case 'I6H':
return differenceInHours(dateRight, dateLeft) / 6;
case 'I4H':
return differenceInHours(dateRight, dateLeft) / 4;
case 'I1H':
return differenceInHours(dateRight, dateLeft);
case 'I15M':
return differenceInMinutes(dateRight, dateLeft) / 15;
case 'I30M':
return differenceInMinutes(dateRight, dateLeft) / 30;
case 'I5M':
return differenceInMinutes(dateRight, dateLeft) / 5;
case 'I1M':
@@ -12,7 +12,7 @@ declare global {
}
}
const chainId = 'vega-stagnet1-202307191148';
const chainId = 'test-id';
export function addMockChainId() {
Cypress.Commands.add('mockChainId', () => {
@@ -37,12 +37,10 @@ export function addVegaWalletConnect() {
Cypress.Commands.add('connectVegaWallet', (isMobile) => {
mockConnectWallet();
cy.highlight(`Connecting Vega Wallet`);
cy.get('[data-testid="splash-loader"]', { timeout: 20000 }).should(
'not.exist'
);
const connectVegaWalletButton = `[data-testid=connect-vega-wallet${
isMobile ? '-mobile' : ''
}]:visible`;
cy.get(connectVegaWalletButton).then((btn) => {
if (btn.length === 0) {
cy.log('could not find the button, perhaps already connected');
+2 -3
View File
@@ -13,8 +13,7 @@ declare global {
const hasMethod = (req: CyHttpMessages.IncomingHttpRequest, method: string) => {
const { body } = req;
const b = JSON.parse(body);
return 'method' in b && b.method === method;
return 'method' in body && body.method === method;
};
export function addMockWalletCommand() {
@@ -73,7 +72,7 @@ export const aliasWalletConnectQuery = (
body: {
jsonrpc: '2.0',
result: {
chainID: 'vega-fairground-202305051805',
chainID: 'test-id',
},
id: '1',
},
@@ -73,7 +73,7 @@ export const DealTicketContainer = ({
market={market}
marketPrice={marketPrice}
marketData={marketData}
submit={(transaction) => create(transaction)}
submit={(orderSubmission) => create({ orderSubmission })}
/>
)}
</>
@@ -1,172 +0,0 @@
import { Controller, type Control } from 'react-hook-form';
import type { Market } from '@vegaprotocol/markets';
import type { OrderFormValues } from '../../hooks/use-form-values';
import { toDecimal, useValidateAmount } from '@vegaprotocol/utils';
import {
TradingFormGroup,
TradingInputError,
Tooltip,
FormGroup,
Input,
InputError,
Pill,
} from '@vegaprotocol/ui-toolkit';
import { useT } from '../../use-t';
export interface DealTicketPriceTakeProfitStopLossProps {
control: Control<OrderFormValues>;
market: Market;
takeProfitError?: string;
stopLossError?: string;
quoteName?: string;
}
export const DealTicketPriceTakeProfitStopLoss = ({
control,
market,
takeProfitError,
stopLossError,
quoteName,
}: DealTicketPriceTakeProfitStopLossProps) => {
const t = useT();
const validateAmount = useValidateAmount();
const priceStep = toDecimal(market?.decimalPlaces);
const renderTakeProfitError = () => {
if (takeProfitError) {
return (
<TradingInputError testId="deal-ticket-take-profit-error-message">
{takeProfitError}
</TradingInputError>
);
}
return null;
};
const renderStopLossError = () => {
if (stopLossError) {
return (
<TradingInputError testId="deal-stop-loss-error-message">
{stopLossError}
</TradingInputError>
);
}
return null;
};
return (
<div className="mb-2">
<div className="flex flex-col gap-2">
<div className="flex-1">
<TradingFormGroup
label={
<Tooltip
description={<div>{t('The price for take profit.')}</div>}
>
<span className="text-xs">{t('Take profit')}</span>
</Tooltip>
}
labelFor="input-order-take-profit"
className="!mb-1"
>
<Controller
name="takeProfit"
control={control}
rules={{
min: {
value: priceStep,
message: t(
'Take profit price cannot be lower than {{priceStep}}',
{
priceStep,
}
),
},
validate: validateAmount(priceStep, 'takeProfit'),
}}
render={({ field, fieldState }) => (
<div className="mb-2">
<FormGroup
labelFor="input-price-take-profit"
label={''}
compact
>
<Input
id="input-price-take-profit"
appendElement={<Pill size="xs">{quoteName}</Pill>}
className="w-full"
type="number"
step={priceStep}
data-testid="order-price-take-profit"
onWheel={(e) => e.currentTarget.blur()}
{...field}
/>
</FormGroup>
{fieldState.error && (
<InputError testId="deal-ticket-error-message-price-take-profit">
{fieldState.error.message}
</InputError>
)}
</div>
)}
/>
</TradingFormGroup>
</div>
<div className="flex-1">
<TradingFormGroup
label={
<Tooltip description={<div>{t('The price for stop loss.')}</div>}>
<span className="text-xs">{t('Stop loss')}</span>
</Tooltip>
}
labelFor="input-order-stop-loss"
className="!mb-1"
>
<Controller
name="stopLoss"
control={control}
rules={{
min: {
value: priceStep,
message: t('Price cannot be lower than {{priceStep}}', {
priceStep,
}),
},
validate: validateAmount(priceStep, 'stopLoss'),
}}
render={({ field, fieldState }) => (
<div className="mb-2">
<FormGroup
labelFor="input-price-stop-loss"
label={''}
compact
>
<Input
id="input-price-stop-loss"
appendElement={<Pill size="xs">{quoteName}</Pill>}
className="w-full"
type="number"
step={priceStep}
data-testid="order-price-stop-loss"
onWheel={(e) => e.currentTarget.blur()}
{...field}
/>
</FormGroup>
{fieldState.error && (
<InputError testId="deal-ticket-error-message-price-stop-loss">
{fieldState.error.message}
</InputError>
)}
</div>
)}
/>
</TradingFormGroup>
</div>
</div>
{renderTakeProfitError()}
{renderStopLossError()}
</div>
);
};
@@ -1003,7 +1003,7 @@ export const StopOrder = ({ market, marketPrice, submit }: StopOrderProps) => {
name="oco"
label={
<Tooltip
description={<span>{t('One cancels the other')}</span>}
description={<span>{t('One cancels another')}</span>}
>
<>{t('OCO')}</>
</Tooltip>
@@ -8,12 +8,9 @@ import { ExpirySelector } from './expiry-selector';
import { SideSelector } from './side-selector';
import { TimeInForceSelector } from './time-in-force-selector';
import { TypeSelector } from './type-selector';
import { type OrderSubmission } from '@vegaprotocol/wallet';
import { useVegaWallet } from '@vegaprotocol/wallet-react';
import { type Transaction } from '@vegaprotocol/wallet';
import {
mapFormValuesToOrderSubmission,
mapFormValuesToTakeProfitAndStopLoss,
} from '../../utils/map-form-values-to-submission';
import { mapFormValuesToOrderSubmission } from '../../utils/map-form-values-to-submission';
import {
TradingInput as Input,
TradingCheckbox as Checkbox,
@@ -80,8 +77,6 @@ import { isNonPersistentOrder } from '../../utils/time-in-force-persistence';
import { KeyValue } from './key-value';
import { DocsLinks } from '@vegaprotocol/environment';
import { useT } from '../../use-t';
import { DealTicketPriceTakeProfitStopLoss } from './deal-ticket-price-tp-sl';
import uniqueId from 'lodash/uniqueId';
export const REDUCE_ONLY_TOOLTIP =
'"Reduce only" will ensure that this order will not increase the size of an open position. When the order is matched, it will only trade enough volume to bring your open volume towards 0 but never change the direction of your position. If applied to a limit order that is not instantly filled, the order will be stopped.';
@@ -91,7 +86,7 @@ export interface DealTicketProps {
marketData: StaticMarketData;
marketPrice?: string | null;
onMarketClick?: (marketId: string, metaKey?: boolean) => void;
submit: (order: Transaction) => void;
submit: (order: OrderSubmission) => void;
onDeposit: (assetId: string) => void;
}
@@ -189,7 +184,6 @@ export const DealTicket = ({
const rawSize = watch('size');
const rawPrice = watch('price');
const iceberg = watch('iceberg');
const tpSl = watch('tpSl');
const peakSize = watch('peakSize');
const expiresAt = watch('expiresAt');
const postOnly = watch('postOnly');
@@ -388,28 +382,17 @@ export const DealTicket = ({
if (lastSubmitTime.current && now - lastSubmitTime.current < 1000) {
return;
}
if (formValues.tpSl) {
const reference = `${pubKey}-${now}-${uniqueId()}`;
const batchMarketInstructions = mapFormValuesToTakeProfitAndStopLoss(
formValues,
market,
reference
);
submit({
batchMarketInstructions,
});
} else {
const orderSubmission = mapFormValuesToOrderSubmission(
submit(
mapFormValuesToOrderSubmission(
formValues,
market.id,
market.decimalPlaces,
market.positionDecimalPlaces
);
submit({ orderSubmission });
}
)
);
lastSubmitTime.current = now;
},
[market, pubKey, submit]
[submit, market.decimalPlaces, market.positionDecimalPlaces, market.id]
);
useController({
name: 'type',
@@ -691,63 +674,40 @@ export const DealTicket = ({
)}
/>
</div>
{
{isLimitType && (
<>
<div className="flex justify-between gap-2 pb-2">
{isLimitType && (
<Controller
name="iceberg"
control={control}
render={({ field }) => (
<Tooltip
description={
<p>
{t(
'ICEBERG_TOOLTIP',
'Trade only a fraction of the order size at once. After the peak size of the order has traded, the size is reset. This is repeated until the order is cancelled, expires, or its full volume trades away. For example, an iceberg order with a size of 1000 and a peak size of 100 will effectively be split into 10 orders with a size of 100 each. Note that the full volume of the order is not hidden and is still reflected in the order book.'
)}{' '}
<ExternalLink href={DocsLinks?.ICEBERG_ORDERS}>
{t('Find out more')}
</ExternalLink>{' '}
</p>
}
>
<div>
<Checkbox
name="iceberg"
checked={field.value}
onCheckedChange={field.onChange}
disabled={disableIcebergCheckbox}
label={t('Iceberg')}
/>
</div>
</Tooltip>
)}
/>
)}
<Controller
name="tpSl"
name="iceberg"
control={control}
render={({ field }) => (
<Tooltip
description={
<p>{t('TP_SL_TOOLTIP', 'Take profit / Stop loss')}</p>
<p>
{t(
'ICEBERG_TOOLTIP',
'Trade only a fraction of the order size at once. After the peak size of the order has traded, the size is reset. This is repeated until the order is cancelled, expires, or its full volume trades away. For example, an iceberg order with a size of 1000 and a peak size of 100 will effectively be split into 10 orders with a size of 100 each. Note that the full volume of the order is not hidden and is still reflected in the order book.'
)}{' '}
<ExternalLink href={DocsLinks?.ICEBERG_ORDERS}>
{t('Find out more')}
</ExternalLink>{' '}
</p>
}
>
<div>
<Checkbox
name="tpSl"
name="iceberg"
checked={field.value}
onCheckedChange={field.onChange}
disabled={false}
label={t('TP / SL')}
disabled={disableIcebergCheckbox}
label={t('Iceberg')}
/>
</div>
</Tooltip>
)}
/>
</div>
{isLimitType && iceberg && (
{iceberg && (
<DealTicketSizeIceberg
market={market}
peakSizeError={errors.peakSize?.message}
@@ -757,18 +717,8 @@ export const DealTicket = ({
peakSize={peakSize}
/>
)}
{tpSl && (
<DealTicketPriceTakeProfitStopLoss
market={market}
takeProfitError={errors.takeProfit?.message}
stopLossError={errors.stopLoss?.message}
control={control}
quoteName={quoteName}
/>
)}
</>
}
)}
<SummaryMessage
error={summaryError}
asset={asset}
@@ -53,9 +53,6 @@ export type OrderFormValues = {
iceberg?: boolean;
peakSize?: string;
minimumVisibleSize?: string;
tpSl?: boolean;
takeProfit?: string;
stopLoss?: string;
};
type UpdateOrder = (marketId: string, values: Partial<OrderFormValues>) => void;
@@ -10,16 +10,13 @@ import type {
import * as Schema from '@vegaprotocol/types';
import { removeDecimal, toNanoSeconds } from '@vegaprotocol/utils';
import { isPersistentOrder } from './time-in-force-persistence';
import { type MarketFieldsFragment } from '@vegaprotocol/markets';
export const mapFormValuesToOrderSubmission = (
order: OrderFormValues,
marketId: string,
decimalPlaces: number,
positionDecimalPlaces: number,
reference?: string
positionDecimalPlaces: number
): OrderSubmission => ({
reference,
marketId: marketId,
type: order.type,
side: order.side,
@@ -84,8 +81,7 @@ export const mapFormValuesToStopOrdersSubmission = (
data: StopOrderFormValues,
marketId: string,
decimalPlaces: number,
positionDecimalPlaces: number,
reference?: string
positionDecimalPlaces: number
): StopOrdersSubmission => {
const submission: StopOrdersSubmission = {};
const stopOrderSetup: StopOrderSetup = {
@@ -100,8 +96,7 @@ export const mapFormValuesToStopOrdersSubmission = (
},
marketId,
decimalPlaces,
positionDecimalPlaces,
reference
positionDecimalPlaces
),
};
setTrigger(
@@ -125,8 +120,7 @@ export const mapFormValuesToStopOrdersSubmission = (
},
marketId,
decimalPlaces,
positionDecimalPlaces,
reference
positionDecimalPlaces
),
};
setTrigger(
@@ -165,125 +159,3 @@ export const mapFormValuesToStopOrdersSubmission = (
return submission;
};
export const mapFormValuesToTakeProfitAndStopLoss = (
formValues: OrderFormValues,
market: MarketFieldsFragment,
reference: string
) => {
const orderSubmission = mapFormValuesToOrderSubmission(
formValues,
market.id,
market.decimalPlaces,
market.positionDecimalPlaces,
reference
);
const oppositeSide =
formValues.side === Schema.Side.SIDE_BUY
? Schema.Side.SIDE_SELL
: Schema.Side.SIDE_BUY;
// For direction it needs to be implied
// If position is LONG (BUY)
// TP is SHORT and trigger is RISES ABOVE
// If position is SHORT
// TP is LONG and trigger is FALLS BELOW
const takeProfitTriggerDirection =
formValues.side === Schema.Side.SIDE_BUY
? Schema.StopOrderTriggerDirection.TRIGGER_DIRECTION_RISES_ABOVE
: Schema.StopOrderTriggerDirection.TRIGGER_DIRECTION_FALLS_BELOW;
// For direction it needs to be implied
// If position is LONG (BUY)
// SL is SHORT and trigger is FALLS BELOW
// If position is SHORT
// SL is LONG and trigger is RISES ABOVE
const stopLossTriggerDirection =
formValues.side === Schema.Side.SIDE_BUY
? Schema.StopOrderTriggerDirection.TRIGGER_DIRECTION_FALLS_BELOW
: Schema.StopOrderTriggerDirection.TRIGGER_DIRECTION_RISES_ABOVE;
const stopOrdersSubmission = [];
// if there are both take profit and stop loss then the stop order needs to be OCO
if (formValues.takeProfit && formValues.stopLoss) {
const ocoStopOrderSubmission = mapFormValuesToStopOrdersSubmission(
{
...formValues,
triggerPrice: formValues.stopLoss,
ocoTriggerPrice: formValues.takeProfit,
price: formValues.stopLoss,
triggerDirection: stopLossTriggerDirection,
triggerType: 'price',
side: oppositeSide,
expire: false,
type: Schema.OrderType.TYPE_MARKET,
oco: true,
ocoPrice: formValues.takeProfit,
ocoTriggerType: 'price',
ocoType: Schema.OrderType.TYPE_MARKET,
ocoSize: formValues.size,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_FOK,
ocoTimeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_FOK,
},
market.id,
market.decimalPlaces,
market.positionDecimalPlaces,
reference
);
stopOrdersSubmission.push(ocoStopOrderSubmission);
} else if (formValues.takeProfit) {
const takeProfitStopOrderSubmission = mapFormValuesToStopOrdersSubmission(
{
...formValues,
price: formValues.takeProfit,
triggerDirection: takeProfitTriggerDirection,
triggerType: 'price',
triggerPrice: formValues.takeProfit,
side: oppositeSide,
expire: false,
ocoTriggerType: 'price',
type: Schema.OrderType.TYPE_MARKET,
oco: false,
ocoType: Schema.OrderType.TYPE_MARKET,
ocoSize: formValues.size,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_FOK,
ocoTimeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_FOK,
},
market.id,
market.decimalPlaces,
market.positionDecimalPlaces,
reference
);
stopOrdersSubmission.push(takeProfitStopOrderSubmission);
} else if (formValues.stopLoss) {
const stopLossStopOrderSubmission = mapFormValuesToStopOrdersSubmission(
{
...formValues,
triggerPrice: formValues.stopLoss,
price: formValues.stopLoss,
triggerDirection: stopLossTriggerDirection,
triggerType: 'price',
side: oppositeSide,
expire: false,
type: Schema.OrderType.TYPE_MARKET,
oco: false,
ocoTriggerType: 'price',
ocoType: Schema.OrderType.TYPE_MARKET,
ocoSize: formValues.size,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_FOK,
ocoTimeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_FOK,
},
market.id,
market.decimalPlaces,
market.positionDecimalPlaces,
reference
);
stopOrdersSubmission.push(stopLossStopOrderSubmission);
}
const batchMarketInstructions = {
submissions: [orderSubmission],
stopOrdersSubmission,
};
return batchMarketInstructions;
};
@@ -1,15 +1,8 @@
import type {
OrderSubmissionBody,
StopOrdersSubmission,
} from '@vegaprotocol/wallet';
import {
mapFormValuesToOrderSubmission,
mapFormValuesToTakeProfitAndStopLoss,
} from './map-form-values-to-submission';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import { mapFormValuesToOrderSubmission } from './map-form-values-to-submission';
import * as Schema from '@vegaprotocol/types';
import { OrderTimeInForce, OrderType } from '@vegaprotocol/types';
import type { OrderFormValues } from '../hooks';
import { type MarketFieldsFragment } from '@vegaprotocol/markets';
describe('mapFormValuesToOrderSubmission', () => {
it('sets and formats price only for limit orders', () => {
@@ -193,232 +186,3 @@ describe('mapFormValuesToOrderSubmission', () => {
}
);
});
const mockMarket: MarketFieldsFragment = {
__typename: 'Market',
id: 'marketId',
decimalPlaces: 1,
positionDecimalPlaces: 4,
state: Schema.MarketState.STATE_ACTIVE,
tradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
} as MarketFieldsFragment;
const orderFormValues: OrderFormValues = {
type: OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_BUY,
timeInForce: OrderTimeInForce.TIME_IN_FORCE_GTC,
size: '1',
price: '66300',
postOnly: false,
reduceOnly: false,
tpSl: true,
takeProfit: '70000',
stopLoss: '60000',
};
describe('mapFormValuesToTakeProfitAndStopLoss', () => {
it('creates batch market instructions for a normal order created with TP and SL', () => {
const result = mapFormValuesToTakeProfitAndStopLoss(
orderFormValues,
mockMarket,
'reference'
);
const expected: {
submissions: Schema.OrderSubmission[];
stopOrdersSubmission: StopOrdersSubmission[];
} = {
stopOrdersSubmission: [
{
fallsBelow: {
orderSubmission: {
expiresAt: undefined,
marketId: 'marketId',
postOnly: false,
price: undefined,
reduceOnly: true,
reference: 'reference',
side: Schema.Side.SIDE_SELL,
size: '10000',
timeInForce: OrderTimeInForce.TIME_IN_FORCE_FOK,
type: OrderType.TYPE_MARKET,
},
price: '600000',
},
risesAbove: {
orderSubmission: {
expiresAt: undefined,
marketId: 'marketId',
postOnly: false,
price: undefined,
reduceOnly: true,
reference: 'reference',
side: Schema.Side.SIDE_SELL,
size: '10000',
timeInForce: OrderTimeInForce.TIME_IN_FORCE_FOK,
type: OrderType.TYPE_MARKET,
},
price: '700000',
},
},
],
submissions: [
{
expiresAt: undefined,
marketId: 'marketId',
postOnly: false,
price: '663000',
reduceOnly: false,
reference: 'reference',
side: Schema.Side.SIDE_BUY,
size: '10000',
timeInForce: OrderTimeInForce.TIME_IN_FORCE_GTC,
type: OrderType.TYPE_LIMIT,
},
],
};
expect(result).toEqual(expected);
});
it('creates batch market instructions for a normal order created without TP and SL', () => {
// Create order form values without TP and SL
const orderFormValuesWithoutTPSL = { ...orderFormValues };
delete orderFormValuesWithoutTPSL.takeProfit;
delete orderFormValuesWithoutTPSL.stopLoss;
const result = mapFormValuesToTakeProfitAndStopLoss(
orderFormValuesWithoutTPSL,
mockMarket,
'reference'
);
// Expected result when TP and SL are not provided
const expected: {
submissions: Schema.OrderSubmission[];
stopOrdersSubmission: StopOrdersSubmission[];
} = {
stopOrdersSubmission: [],
submissions: [
{
expiresAt: undefined,
marketId: 'marketId',
postOnly: false,
price: '663000',
reduceOnly: false,
reference: 'reference',
side: Schema.Side.SIDE_BUY,
size: '10000',
timeInForce: OrderTimeInForce.TIME_IN_FORCE_GTC,
type: OrderType.TYPE_LIMIT,
},
],
};
expect(result).toEqual(expected);
});
it('creates batch market instructions for a normal order created with TP only', () => {
// Create order form values with TP only
const orderFormValuesWithTP = { ...orderFormValues };
orderFormValuesWithTP.stopLoss = undefined;
const result = mapFormValuesToTakeProfitAndStopLoss(
orderFormValuesWithTP,
mockMarket,
'reference'
);
// Expected result when only TP is provided
const expected: {
submissions: Schema.OrderSubmission[];
stopOrdersSubmission: StopOrdersSubmission[];
} = {
stopOrdersSubmission: [
{
risesAbove: {
orderSubmission: {
expiresAt: undefined,
marketId: 'marketId',
postOnly: false,
price: undefined,
reduceOnly: true,
reference: 'reference',
side: Schema.Side.SIDE_SELL,
size: '10000',
timeInForce: OrderTimeInForce.TIME_IN_FORCE_FOK,
type: OrderType.TYPE_MARKET,
},
price: '700000',
},
},
],
submissions: [
{
expiresAt: undefined,
marketId: 'marketId',
postOnly: false,
price: '663000',
reduceOnly: false,
reference: 'reference',
side: Schema.Side.SIDE_BUY,
size: '10000',
timeInForce: OrderTimeInForce.TIME_IN_FORCE_GTC,
type: OrderType.TYPE_LIMIT,
},
],
};
expect(result).toEqual(expected);
});
it('creates batch market instructions for a normal order created with SL only', () => {
// Create order form values with SL only
const orderFormValuesWithSL = { ...orderFormValues };
orderFormValuesWithSL.takeProfit = undefined;
const result = mapFormValuesToTakeProfitAndStopLoss(
orderFormValuesWithSL,
mockMarket,
'reference'
);
// Expected result when only SL is provided
const expected: {
submissions: Schema.OrderSubmission[];
stopOrdersSubmission: StopOrdersSubmission[];
} = {
stopOrdersSubmission: [
{
fallsBelow: {
orderSubmission: {
expiresAt: undefined,
marketId: 'marketId',
postOnly: false,
price: undefined,
reduceOnly: true,
reference: 'reference',
side: Schema.Side.SIDE_SELL,
size: '10000',
timeInForce: OrderTimeInForce.TIME_IN_FORCE_FOK,
type: OrderType.TYPE_MARKET,
},
price: '600000',
},
},
],
submissions: [
{
expiresAt: undefined,
marketId: 'marketId',
postOnly: false,
price: '663000',
reduceOnly: false,
reference: 'reference',
side: Schema.Side.SIDE_BUY,
size: '10000',
timeInForce: OrderTimeInForce.TIME_IN_FORCE_GTC,
type: OrderType.TYPE_LIMIT,
},
],
};
expect(result).toEqual(expected);
});
});
+15 -37
View File
@@ -1,9 +1,5 @@
import { USDT_ID, type Asset } from '@vegaprotocol/assets';
import {
EtherscanLink,
Networks,
useEnvironment,
} from '@vegaprotocol/environment';
import type { Asset } from '@vegaprotocol/assets';
import { EtherscanLink } from '@vegaprotocol/environment';
import { Intent, Notification } from '@vegaprotocol/ui-toolkit';
import {
formatNumber,
@@ -19,7 +15,7 @@ import { useT } from './use-t';
interface ApproveNotificationProps {
isActive: boolean;
selectedAsset?: Asset;
onApprove: (amount?: string) => void;
onApprove: () => void;
approved: boolean;
balances: DepositBalances | null;
amount: string;
@@ -37,7 +33,6 @@ export const ApproveNotification = ({
approveTxId,
intent = Intent.Warning,
}: ApproveNotificationProps) => {
const { VEGA_ENV } = useEnvironment();
const t = useT();
const tx = useEthTransactionStore((state) => {
return state.transactions.find((t) => t?.id === approveTxId);
@@ -69,45 +64,28 @@ export const ApproveNotification = ({
text: t('Approve {{assetSymbol}}', {
assetSymbol: selectedAsset?.symbol,
}),
action: () => onApprove(),
action: onApprove,
dataTestId: 'approve-submit',
}}
/>
</div>
);
let message = t('Approve again to deposit more than {{allowance}}', {
allowance: formatNumber(balances.allowance.toString()),
});
const buttonProps = {
size: 'small' as const,
text: t('Approve {{assetSymbol}}', {
assetSymbol: selectedAsset?.symbol,
}),
action: () => onApprove(),
dataTestId: 'reapprove-submit',
};
if (VEGA_ENV === Networks.MAINNET && selectedAsset.id === USDT_ID[VEGA_ENV]) {
message = t(
'USDT approved amount cannot be changed, only revoked. Revoke and reapprove to deposit more than {{allowance}}.',
{
allowance: formatNumber(balances.allowance.toString()),
}
);
buttonProps.text = t('Revoke {{assetSymbol}} approval', {
assetSymbol: selectedAsset?.symbol,
});
buttonProps.action = () => onApprove('0');
}
const reApprovePrompt = (
<div className="mb-4">
<Notification
intent={intent}
testId="reapprove-default"
message={message}
buttonProps={buttonProps}
message={t('Approve again to deposit more than {{allowance}}', {
allowance: formatNumber(balances.allowance.toString()),
})}
buttonProps={{
size: 'small',
text: t('Approve {{assetSymbol}}', {
assetSymbol: selectedAsset?.symbol,
}),
action: onApprove,
dataTestId: 'reapprove-submit',
}}
/>
</div>
);
+3 -3
View File
@@ -58,7 +58,7 @@ export interface DepositFormProps {
onSelectAsset: (assetId: string) => void;
handleAmountChange: (amount: string) => void;
onDisconnect: () => void;
submitApprove: (amount?: string) => void;
submitApprove: () => void;
approveTxId: number | null;
submitFaucet: () => void;
faucetTxId: number | null;
@@ -423,8 +423,8 @@ export const DepositForm = ({
isActive={isActive}
approveTxId={approveTxId}
selectedAsset={selectedAsset}
onApprove={(amount) => {
submitApprove(amount);
onApprove={() => {
submitApprove();
setApproveNotificationIntent(Intent.Warning);
}}
balances={balances}
+2 -2
View File
@@ -35,11 +35,11 @@ export const useSubmitApproval = (
reset: () => {
setId(null);
},
perform: (amount?: string) => {
perform: () => {
if (!asset || !config) return;
const id = createEthTransaction(contract, 'approve', [
config?.collateral_bridge_contract.address,
amount ? amount : MaxUint256.toString(),
MaxUint256.toString(),
]);
setId(id);
},
@@ -0,0 +1,16 @@
import { Splash } from '@vegaprotocol/ui-toolkit';
export const AppFailure = ({
title,
error,
}: {
title: string;
error?: string | null;
}) => {
return (
<Splash>
<p className="mb-4 text-xl">{title}</p>
{error && <p className="mb-8 text-sm">{error}</p>}
</Splash>
);
};
@@ -0,0 +1 @@
export * from './app-failure';
+1
View File
@@ -1,3 +1,4 @@
export * from './app-failure';
export * from './app-loader';
export * from './network-loader';
export * from './network-switcher';
@@ -40,16 +40,6 @@ const mockStatsQuery = (
vegaTime: new Date().toISOString(),
chainId: 'test-chain-id',
},
networkParametersConnection: {
edges: [
{
node: {
key: 'a',
value: '1',
},
},
],
},
},
},
});
@@ -345,16 +335,6 @@ describe('RowData', () => {
vegaTime: new Date().toISOString(),
chainId: 'test-chain-id',
},
networkParametersConnection: {
edges: [
{
node: {
key: 'a',
value: '1',
},
},
],
},
},
},
};
@@ -1,9 +1,4 @@
import {
CopyWithTooltip,
TradingRadio,
VegaIcon,
VegaIconNames,
} from '@vegaprotocol/ui-toolkit';
import { TradingRadio } from '@vegaprotocol/ui-toolkit';
import { useEffect, useState } from 'react';
import { CUSTOM_NODE_KEY } from '../../types';
import {
@@ -132,17 +127,8 @@ export const RowData = ({
return (
<>
{id !== CUSTOM_NODE_KEY && (
<div className="break-all flex gap-2" data-testid="node">
<div className="break-all" data-testid="node">
<TradingRadio id={`node-url-${id}`} value={url} label={url} />
{url.length > 0 && url !== 'custom' && (
<span className="text-muted">
<CopyWithTooltip text={url}>
<button>
<VegaIcon name={VegaIconNames.COPY} />
</button>
</CopyWithTooltip>
</span>
)}
</div>
)}
<LayoutCell
@@ -39,19 +39,6 @@ export const getMockStatisticsResult = (
blockHeight: '11',
vegaTime: new Date().toISOString(),
},
networkParametersConnection: {
__typename: 'NetworkParametersConnection',
edges: [
{
__typename: 'NetworkParameterEdge',
node: {
__typename: 'NetworkParameter',
key: 'a',
value: '1',
},
},
],
},
});
export const getMockQueryResult = (env: Networks): NodeCheckQuery => ({
@@ -61,19 +48,6 @@ export const getMockQueryResult = (env: Networks): NodeCheckQuery => ({
blockHeight: '11',
vegaTime: new Date().toISOString(),
},
networkParametersConnection: {
__typename: 'NetworkParametersConnection',
edges: [
{
__typename: 'NetworkParameterEdge',
node: {
__typename: 'NetworkParameter',
key: 'a',
value: '1',
},
},
],
},
});
function getHandler<T>(
@@ -34,16 +34,6 @@ const createDefaultMockClient = () => {
blockHeight: '100',
vegaTime: new Date().toISOString(),
},
networkParametersConnection: {
edges: [
{
node: {
key: 'something',
value: 123,
},
},
],
},
},
}),
subscribe: () => ({
@@ -193,16 +183,6 @@ describe('useEnvironment', () => {
blockHeight: '100',
vegaTime: new Date(1).toISOString(),
},
networkParametersConnection: {
edges: [
{
node: {
key: 'something',
value: 123,
},
},
],
},
},
});
}, wait);
@@ -264,16 +244,6 @@ describe('useEnvironment', () => {
blockHeight: '100',
vegaTime: new Date().toISOString(),
},
networkParametersConnection: {
edges: [
{
node: {
key: 'something',
value: 123,
},
},
],
},
},
}),
subscribe: () => ({
+54 -72
View File
@@ -1,5 +1,5 @@
import { parse as tomlParse } from 'toml';
import { LocalStorage, isValidUrl } from '@vegaprotocol/utils';
import { isValidUrl, LocalStorage } from '@vegaprotocol/utils';
import { useEffect } from 'react';
import { create } from 'zustand';
import { createClient } from '@vegaprotocol/apollo-client';
@@ -22,7 +22,6 @@ import uniq from 'lodash/uniq';
import orderBy from 'lodash/orderBy';
import first from 'lodash/first';
import { canMeasureResponseTime, measureResponseTime } from '../utils/time';
import compact from 'lodash/compact';
type Client = ReturnType<typeof createClient>;
type ClientCollection = {
@@ -71,19 +70,10 @@ const fetchConfig = async (url?: string) => {
};
/**
* Find a suitable nodes by running a test query and test
* Find a suitable node by running a test query and test
* subscription, against a list of clients, first to resolve wins
*/
const findHealthyNodes = async (nodes: string[]) => {
const clients: ClientCollection = {};
nodes.forEach((url) => {
clients[url] = createClient({
url,
cacheConfig: undefined,
retry: false,
connectToDevTools: false,
});
});
const findNode = async (clients: ClientCollection): Promise<string | null> => {
const tests = Object.entries(clients).map((args) => testNode(...args));
try {
const nodes = await Promise.all(tests);
@@ -103,10 +93,11 @@ const findHealthyNodes = async (nodes: string[]) => {
['desc', 'desc', 'asc']
);
return ordered;
const best = first(ordered);
return best ? best.url : null;
} catch (err) {
// All tests rejected, no suitable node found
return [];
return null;
}
};
@@ -151,15 +142,6 @@ const testQuery = (
})
.then((result) => {
if (result && !result.error) {
const netParams = compact(
result.data.networkParametersConnection.edges?.map((n) => n?.node)
);
if (netParams.length === 0) {
// any node that doesn't return the network parameters is considered
// failed
resolve(false);
return;
}
const res = {
blockHeight: Number(result.data.statistics.blockHeight),
vegaTime: new Date(result.data.statistics.vegaTime),
@@ -618,34 +600,32 @@ export const useEnvironment = create<EnvStore>()((set, get) => ({
}
const state = get();
let storedUrl = LocalStorage.getItem(STORAGE_KEY);
if (!isValidUrl(storedUrl)) {
// remove invalid data from local storage
LocalStorage.removeItem(STORAGE_KEY);
storedUrl = null;
}
const storedUrl = LocalStorage.getItem(STORAGE_KEY);
let nodes: string[] | undefined;
try {
nodes = uniq(
compact([
// url from local storage
storedUrl,
// url from state (if set via env var)
state.VEGA_URL,
// urls from network configuration
...(await fetchConfig(state.VEGA_CONFIG_URL)),
])
nodes = await fetchConfig(state.VEGA_CONFIG_URL);
const enrichedNodes = uniq(
[...nodes, state.VEGA_URL, storedUrl].filter(Boolean) as string[]
);
set({ nodes });
set({ nodes: enrichedNodes });
} catch (err) {
console.warn(`Could not fetch node config from ${state.VEGA_CONFIG_URL}`);
}
// skip picking up the best node if VEGA_URL env variable is set
if (state.VEGA_URL && isValidUrl(state.VEGA_URL)) {
state.setUrl(state.VEGA_URL);
// Node url found in localStorage, if its valid attempt to connect
if (storedUrl) {
if (isValidUrl(storedUrl)) {
set({ VEGA_URL: storedUrl, status: 'success' });
return;
} else {
LocalStorage.removeItem(STORAGE_KEY);
}
}
// VEGA_URL env var is set and is a valid url no need to proceed
if (state.VEGA_URL) {
set({ status: 'success' });
return;
}
@@ -659,35 +639,37 @@ export const useEnvironment = create<EnvStore>()((set, get) => ({
return;
}
const healthyNodes = await findHealthyNodes(nodes);
// A requested node is a node to which the app was previously connected
// or the one set via env variable.
const requestedNodeUrl = storedUrl || state.VEGA_URL;
const bestNode = first(healthyNodes);
const requestedNode = healthyNodes.find(
(n) => requestedNodeUrl && n.url === requestedNodeUrl
);
if (!requestedNode) {
// remove unhealthy node url from local storage
LocalStorage.removeItem(STORAGE_KEY);
}
// A node's url (VEGA_URL) is either the requested node (previously
// connected or taken form env variable) or the currently best available
// node.
const url = requestedNode?.url || bestNode?.url;
if (url != null) {
state.setUrl(url);
return;
}
set({
status: 'failed',
error: 'No suitable node found',
// Create a map of node urls to client instances
const clients: ClientCollection = {};
nodes.forEach((url) => {
clients[url] = createClient({
url,
cacheConfig: undefined,
retry: false,
connectToDevTools: false,
});
});
console.warn('No suitable node was found');
// Find a suitable node to connect to by attempting a query and a
// subscription, first to fulfill both will be the resulting url.
const url = await findNode(clients);
if (url !== null) {
set({
status: 'success',
VEGA_URL: url,
});
LocalStorage.setItem(STORAGE_KEY, url);
}
// Every node failed either to make a query or retrieve data from
// a subscription
else {
set({
status: 'failed',
error: 'No node found',
});
console.warn('No suitable vega node was found');
}
},
}));
-1
View File
@@ -134,7 +134,6 @@ export const CONSOLE_TRANSFER = '#/portfolio/assets/transfer';
export const CONSOLE_TRANSFER_ASSET =
'#/portfolio/assets/transfer?assetId=:assetId';
export const CONSOLE_MARKET_PAGE = '#/markets/:marketId';
export const CONSOLE_REWARDS_PAGE = '#/rewards';
// Governance pages
export const TOKEN_NEW_MARKET_PROPOSAL = '/proposals/propose/new-market';
@@ -28,16 +28,6 @@ const createStatsMock = (
blockHeight: blockHeight.toString(),
vegaTime: '12345',
},
networkParametersConnection: {
edges: [
{
node: {
key: 'a',
value: '1',
},
},
],
},
},
},
};
@@ -1,19 +1,9 @@
query NodeCheck {
# statistics needed to get the most recent node in terms of block height
statistics {
chainId
blockHeight
vegaTime
}
# net params needed to filter out the nodes that are not suitable
networkParametersConnection {
edges {
node {
key
value
}
}
}
}
subscription NodeCheckTimeUpdate {
+1 -9
View File
@@ -6,7 +6,7 @@ const defaultOptions = {} as const;
export type NodeCheckQueryVariables = Types.Exact<{ [key: string]: never; }>;
export type NodeCheckQuery = { __typename?: 'Query', statistics: { __typename?: 'Statistics', chainId: string, blockHeight: string, vegaTime: any }, networkParametersConnection: { __typename?: 'NetworkParametersConnection', edges?: Array<{ __typename?: 'NetworkParameterEdge', node: { __typename?: 'NetworkParameter', key: string, value: string } } | null> | null } };
export type NodeCheckQuery = { __typename?: 'Query', statistics: { __typename?: 'Statistics', chainId: string, blockHeight: string, vegaTime: any } };
export type NodeCheckTimeUpdateSubscriptionVariables = Types.Exact<{ [key: string]: never; }>;
@@ -21,14 +21,6 @@ export const NodeCheckDocument = gql`
blockHeight
vegaTime
}
networkParametersConnection {
edges {
node {
key
value
}
}
}
}
`;
-13
View File
@@ -12,19 +12,6 @@ export const statisticsQuery = (
blockHeight: '11',
vegaTime: new Date().toISOString(),
},
networkParametersConnection: {
__typename: 'NetworkParametersConnection',
edges: [
{
__typename: 'NetworkParameterEdge',
node: {
__typename: 'NetworkParameter',
key: 'a',
value: '1',
},
},
],
},
};
return merge(defaultResult, override);
+1 -7
View File
@@ -66,7 +66,7 @@
"Notional": "Notional",
"NOTIONAL_SIZE_TOOLTIP_TEXT": "The notional size represents the position size in the settlement asset {{quoteName}} of the futures contract. This is calculated by multiplying the number of contracts by the prices of the contract. For example 10 contracts traded at a price of $50 has a notional size of $500.",
"OCO": "OCO",
"One cancels the other": "One cancels the other",
"One cancels another": "One cancels another",
"Only limit orders are permitted when market is in auction": "Only limit orders are permitted when market is in auction",
"Only your allocated margin will be used to fund this position, and if the maintenance margin is breached you will be closed out.": "Only your allocated margin will be used to fund this position, and if the maintenance margin is breached you will be closed out.",
"You have an existing position on this market.": "You have an existing position on this market.",
@@ -135,12 +135,6 @@
"Total margin available": "Total margin available",
"TOTAL_MARGIN_AVAILABLE": "Total margin available = general {{assetSymbol}} balance ({{generalAccountBalance}} {{assetSymbol}}) + margin balance ({{marginAccountBalance}} {{assetSymbol}}) + order margin balance ({{orderMarginAccountBalance}} {{assetSymbol}}) - maintenance level ({{marginMaintenance}} {{assetSymbol}}).",
"No trading": "No trading",
"TP / SL": "TP / SL",
"TP_SL_TOOLTIP": "Take profit / Stop loss",
"Take profit": "Take profit",
"Stop loss": "Stop loss",
"The price for take profit.": "The price for take profit.",
"The price for stop loss.": "The price for stop loss.",
"Trailing percent offset cannot be higher than 99.9": "Trailing percent offset cannot be higher than 99.9",
"Trailing percent offset cannot be lower than {{trailingPercentOffsetStep}}": "Trailing percent offset cannot be lower than {{trailingPercentOffsetStep}}",
"Trailing percentage offset": "Trailing percentage offset",
-2
View File
@@ -4,7 +4,6 @@
"Approval failed": "Approval failed",
"Approve {{assetSymbol}}": "Approve {{assetSymbol}}",
"Approve again to deposit more than {{allowance}}": "Approve again to deposit more than {{allowance}}",
"USDT approved amount cannot be changed, only revoked. Revoke and reapprove to deposit more than {{allowance}}.": "USDT approved amount cannot be changed, only revoked. Revoke and reapprove to deposit more than {{allowance}}.",
"Asset": "Asset",
"Balance available": "Balance available",
"Before you can make a deposit of your chosen asset, {{assetSymbol}}, you need to approve its use in your Ethereum wallet": "Before you can make a deposit of your chosen asset, {{assetSymbol}}, you need to approve its use in your Ethereum wallet",
@@ -24,7 +23,6 @@
"Please select": "Please select",
"Please select an asset": "Please select an asset",
"Remaining deposit allowance": "Remaining deposit allowance",
"Revoke {{assetSymbol}} approval": "Revoke {{assetSymbol}} approval",
"Select from wallet": "Select from wallet",
"The {{symbol}} faucet is not available at this time": "The {{symbol}} faucet is not available at this time",
"The deposit cap is set when you approve an asset for use with this app. To increase this cap, approve {{assetSymbol}} again and choose a higher cap. Check the documentation for your Ethereum wallet app for details.": "The deposit cap is set when you approve an asset for use with this app. To increase this cap, approve {{assetSymbol}} again and choose a higher cap. Check the documentation for your Ethereum wallet app for details.",
+1 -2
View File
@@ -971,6 +971,5 @@
"YourIdentityAnonymous": "Your identity is always anonymous on Vega",
"yourStake": "Your stake",
"yourVote": "Your vote",
"youVoted": "You voted",
"rewardsMovedNotification": "Trading and liquidity rewards have moved. Visit <0>Console</0> to view your rewards."
"youVoted": "You voted"
}
+5
View File
@@ -1,6 +1,8 @@
{
"{{liquidityPriceRange}} of mid price": "{{liquidityPriceRange}} of mid price",
"{{probability}} probability price bounds": "{{probability}} probability price bounds",
"24 hour change is unavailable at this time. The price change in the last 120 hours is:": "24 hour change is unavailable at this time. The price change in the last 120 hours is:",
"24 hour change is unavailable at this time. The volume change in the last 120 hours is {{candleVolumeValue}} for a total of {{candleVolumePrice}} {{quoteUnit}}": "24 hour change is unavailable at this time. The volume change in the last 120 hours is {{candleVolumeValue}} for a total of {{candleVolumePrice}} {{quoteUnit}}",
"A concept derived from traditional markets. It is a calculated value for the current market price on a market.": "A concept derived from traditional markets. It is a calculated value for the current market price on a market.",
"A number that will be calculated by an appropriate stochastic risk model, dependent on the type of risk model used and its parameters.": "A number that will be calculated by an appropriate stochastic risk model, dependent on the type of risk model used and its parameters.",
"A sliding penalty for how much an LP bond is slashed if an LP fails to reach the minimum SLA. This is a network parameter.": "A sliding penalty for how much an LP bond is slashed if an LP fails to reach the minimum SLA. This is a network parameter.",
@@ -49,6 +51,9 @@
"Market": "Market",
"Market data": "Market data",
"Market governance": "Market governance",
"Market has not been active for 24 hours. The price change between {{start}} and {{end}} is:": "Market has not been active for 24 hours. The price change between {{start}} and {{end}} is:",
"Market has not been active for 24 hours. The volume traded between {{start}} and {{end}} is:": "Market has not been active for 24 hours. The volume traded between {{start}} and {{end}} is:",
"Market has not been active for 24 hours. The volume traded between {{start}} and {{end}} is {{candleVolumeValue}} for a total of {{candleVolumePrice}} {{quoteUnit}}": "Market has not been active for 24 hours. The volume traded between {{start}} and {{end}} is {{candleVolumeValue}} for a total of {{candleVolumePrice}} {{quoteUnit}}",
"Market ID": "Market ID",
"Market price": "Market price",
"Market specification": "Market specification",
+4 -11
View File
@@ -143,17 +143,12 @@
"Hoarder reward multiplier": "Hoarder reward multiplier",
"How it works": "How it works",
"I want a code": "I want a code",
"INTERVAL_I12H": "12H",
"INTERVAL_I15M": "15m",
"INTERVAL_I1D": "D",
"INTERVAL_I1H": "1h",
"INTERVAL_I1D": "1D",
"INTERVAL_I1H": "1H",
"INTERVAL_I1M": "1m",
"INTERVAL_I30M": "30m",
"INTERVAL_I4H": "4H",
"INTERVAL_I5M": "5m",
"INTERVAL_I6H": "6h",
"INTERVAL_I8H": "8h",
"INTERVAL_I7D": "W",
"INTERVAL_I6H": "6H",
"Improve vega console": "Improve vega console",
"Inactive": "Inactive",
"Index Price": "Index Price",
@@ -485,7 +480,5 @@
"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."
"Currently no active teams on the network.": "Currently no active teams on the network."
}
@@ -7,7 +7,6 @@
"Get MetaMask": "Get MetaMask",
"Get the Vega Wallet": "Get the Vega Wallet",
"I agree": "I agree",
"Once you have added the extension, <0>refresh</0> your browser.": "Once you have added the extension, <0>refresh</0> your browser.",
"Successfully connected": "Successfully connected",
"Transaction was not successful": "Transaction was not successful",
"Wallet rejected transaction": "Wallet rejected transaction"
@@ -2,14 +2,16 @@ import { type ReactNode } from 'react';
import {
addDecimalsFormatNumber,
formatNumberPercentage,
getDateTimeFormat,
priceChange,
priceChangePercentage,
} from '@vegaprotocol/utils';
import { signedNumberCssClass } from '@vegaprotocol/datagrid';
import { VegaIcon, VegaIconNames } from '@vegaprotocol/ui-toolkit';
import { PriceChangeCell, signedNumberCssClass } from '@vegaprotocol/datagrid';
import { Tooltip, VegaIcon, VegaIconNames } from '@vegaprotocol/ui-toolkit';
import { useCandles } from '../../hooks/use-candles';
import BigNumber from 'bignumber.js';
import classNames from 'classnames';
import { useT } from '../../use-t';
interface Props {
marketId?: string;
@@ -22,6 +24,7 @@ export const Last24hPriceChange = ({
decimalPlaces,
fallback,
}: Props) => {
const t = useT();
const { oneDayCandles, fiveDaysCandles, error } = useCandles({
marketId,
});
@@ -32,6 +35,56 @@ export const Last24hPriceChange = ({
return nonIdeal;
}
if (fiveDaysCandles.length < 24) {
return (
<Tooltip
description={
<span className="justify-start">
{t(
'Market has not been active for 24 hours. The price change between {{start}} and {{end}} is:',
{
start: getDateTimeFormat().format(
new Date(fiveDaysCandles[0].periodStart)
),
end: getDateTimeFormat().format(
new Date(
fiveDaysCandles[fiveDaysCandles.length - 1].periodStart
)
),
}
)}
<PriceChangeCell
candles={fiveDaysCandles.map((c) => c.close) || []}
decimalPlaces={decimalPlaces}
/>
</span>
}
>
<span>{nonIdeal}</span>
</Tooltip>
);
}
if (oneDayCandles.length < 24) {
return (
<Tooltip
description={
<span className="justify-start">
{t(
'24 hour change is unavailable at this time. The price change in the last 120 hours is:'
)}{' '}
<PriceChangeCell
candles={fiveDaysCandles.map((c) => c.close) || []}
decimalPlaces={decimalPlaces}
/>
</span>
}
>
<span>{nonIdeal}</span>
</Tooltip>
);
}
const candles = oneDayCandles?.map((c) => c.close) || [];
const change = priceChange(candles);
const changePercentage = priceChangePercentage(candles);
@@ -2,6 +2,7 @@ import { calcCandleVolume, calcCandleVolumePrice } from '../../market-utils';
import {
addDecimalsFormatNumber,
formatNumber,
getDateTimeFormat,
isNumeric,
} from '@vegaprotocol/utils';
import { Tooltip } from '@vegaprotocol/ui-toolkit';
@@ -36,6 +37,83 @@ export const Last24hVolume = ({
return nonIdeal;
}
if (fiveDaysCandles.length < 24) {
const candleVolume = calcCandleVolume(fiveDaysCandles);
const candleVolumePrice = calcCandleVolumePrice(
fiveDaysCandles,
marketDecimals,
positionDecimalPlaces
);
const candleVolumeValue =
candleVolume && isNumeric(positionDecimalPlaces)
? addDecimalsFormatNumber(
candleVolume,
positionDecimalPlaces,
formatDecimals
)
: '-';
return (
<Tooltip
description={
<div>
<span className="flex flex-col">
{t(
'Market has not been active for 24 hours. The volume traded between {{start}} and {{end}} is {{candleVolumeValue}} for a total of {{candleVolumePrice}} {{quoteUnit}}',
{
start: getDateTimeFormat().format(
new Date(fiveDaysCandles[0].periodStart)
),
end: getDateTimeFormat().format(
new Date(
fiveDaysCandles[fiveDaysCandles.length - 1].periodStart
)
),
candleVolumeValue,
candleVolumePrice,
quoteUnit,
}
)}
</span>
</div>
}
>
<span>{nonIdeal}</span>
</Tooltip>
);
}
if (oneDayCandles.length < 24) {
const candleVolume = calcCandleVolume(fiveDaysCandles);
const candleVolumePrice = calcCandleVolumePrice(
fiveDaysCandles,
marketDecimals,
positionDecimalPlaces
);
const candleVolumeValue =
candleVolume && isNumeric(positionDecimalPlaces)
? addDecimalsFormatNumber(
candleVolume,
positionDecimalPlaces,
formatDecimals
)
: '-';
return (
<Tooltip
description={
<div>
<span className="flex flex-col">
{t(
'24 hour change is unavailable at this time. The volume change in the last 120 hours is {{candleVolumeValue}} for a total of ({{candleVolumePrice}} {{quoteUnit}})',
{ candleVolumeValue, candleVolumePrice, quoteUnit }
)}
</span>
</div>
}
>
<span>{nonIdeal}</span>
</Tooltip>
);
}
const candleVolume = oneDayCandles
? calcCandleVolume(oneDayCandles)
: initialValue;
+8 -1
View File
@@ -8,7 +8,7 @@ export const useCandles = ({ marketId }: { marketId?: string }) => {
const fiveDaysAgo = useFiveDaysAgo();
const yesterday = useYesterday();
const since = new Date(fiveDaysAgo).toISOString();
const { data: fiveDaysCandles, error } = useThrottledDataProvider({
const { data, error } = useThrottledDataProvider({
dataProvider: marketCandlesProvider,
variables: {
marketId: marketId || '',
@@ -18,6 +18,13 @@ export const useCandles = ({ marketId }: { marketId?: string }) => {
skip: !marketId,
});
const fiveDaysCandles = data?.filter((c) => {
if (c.open === '' || c.close === '' || c.high === '' || c.close === '') {
return false;
}
return true;
});
const oneDayCandles = fiveDaysCandles?.filter((candle) =>
isCandleLessThan24hOld(candle, yesterday)
);
-5
View File
@@ -15,14 +15,9 @@ export const TRADINGVIEW_INTERVAL_MAP = {
[Interval.INTERVAL_I1M]: '1',
[Interval.INTERVAL_I5M]: '5',
[Interval.INTERVAL_I15M]: '15',
[Interval.INTERVAL_I30M]: '30',
[Interval.INTERVAL_I1H]: '60',
[Interval.INTERVAL_I4H]: '240',
[Interval.INTERVAL_I6H]: '360',
[Interval.INTERVAL_I8H]: '480',
[Interval.INTERVAL_I12H]: '720',
[Interval.INTERVAL_I1D]: '1D',
[Interval.INTERVAL_I7D]: '1W',
} as const;
export type ResolutionRecord = typeof TRADINGVIEW_INTERVAL_MAP;
@@ -1,7 +1,7 @@
import { useScript } from '@vegaprotocol/react-helpers';
import { Splash } from '@vegaprotocol/ui-toolkit';
import { useT } from './use-t';
import { TradingView } from './trading-view';
import { TradingView, type OnAutoSaveNeededCallback } from './trading-view';
import { CHARTING_LIBRARY_FILE, type ResolutionString } from './constants';
export const TradingViewContainer = ({
@@ -10,12 +10,16 @@ export const TradingViewContainer = ({
marketId,
interval,
onIntervalChange,
onAutoSaveNeeded,
state,
}: {
libraryPath: string;
libraryHash: string;
marketId: string;
interval: ResolutionString;
onIntervalChange: (interval: string) => void;
onAutoSaveNeeded: OnAutoSaveNeededCallback;
state: object | undefined;
}) => {
const t = useT();
const scriptState = useScript(
@@ -45,6 +49,8 @@ export const TradingViewContainer = ({
marketId={marketId}
interval={interval}
onIntervalChange={onIntervalChange}
onAutoSaveNeeded={onAutoSaveNeeded}
state={state}
/>
);
};
+20 -1
View File
@@ -25,11 +25,15 @@ export const TradingView = ({
libraryPath,
interval,
onIntervalChange,
onAutoSaveNeeded,
state,
}: {
marketId: string;
libraryPath: string;
interval: ResolutionString;
onIntervalChange: (interval: string) => void;
onAutoSaveNeeded: OnAutoSaveNeededCallback;
state: object | undefined;
}) => {
const { isMobile } = useScreenDimensions();
const { theme } = useThemeSwitcher();
@@ -104,6 +108,7 @@ export const TradingView = ({
backgroundColor: overrides['paneProperties.background'],
},
auto_save_delay: 1,
saved_data: state,
};
widgetRef.current = new window.TradingView.widget(widgetOptions);
@@ -112,12 +117,25 @@ export const TradingView = ({
if (!widgetRef.current) return;
const activeChart = widgetRef.current.activeChart();
activeChart.createStudy('Volume');
if (!state) {
// If chart has loaded with no state, create a volume study
activeChart.createStudy('Volume');
}
// Subscribe to interval changes so it can be persisted in chart settings
activeChart.onIntervalChanged().subscribe(null, onIntervalChange);
});
widgetRef.current.subscribe('onAutoSaveNeeded', () => {
if (!widgetRef.current) return;
widgetRef.current.save((newState) => {
onAutoSaveNeeded(newState);
});
});
}, [
state,
datafeed,
interval,
prevTheme,
@@ -127,6 +145,7 @@ export const TradingView = ({
language,
libraryPath,
isMobile,
onAutoSaveNeeded,
onIntervalChange,
]);
@@ -32,14 +32,9 @@ const resolutionMap: Record<string, Interval> = {
'1': Interval.INTERVAL_I1M,
'5': Interval.INTERVAL_I5M,
'15': Interval.INTERVAL_I15M,
'30': Interval.INTERVAL_I30M,
'60': Interval.INTERVAL_I1H,
'240': Interval.INTERVAL_I4H,
'360': Interval.INTERVAL_I6H,
'480': Interval.INTERVAL_I8H,
'720': Interval.INTERVAL_I12H,
'1D': Interval.INTERVAL_I1D,
'1W': Interval.INTERVAL_I7D,
} as const;
const supportedResolutions = Object.keys(resolutionMap);
-12
View File
@@ -936,8 +936,6 @@ export enum DispatchMetric {
/** Dispatch strategy for a recurring transfer */
export type DispatchStrategy = {
__typename?: 'DispatchStrategy';
/** Optional multiplier on taker fees used to cap the rewards a party may receive in an epoch */
capRewardFeeMultiple?: Maybe<Scalars['String']>;
/** Defines the data that will be used to compare markets so as to distribute rewards appropriately */
dispatchMetric: DispatchMetric;
/** The asset to use for measuring contribution to the metric */
@@ -2393,8 +2391,6 @@ export type Market = {
state: MarketState;
/** Optional: Market ID of the successor to this market if one exists */
successorMarketID?: Maybe<Scalars['ID']>;
/** The market minimum tick size */
tickSize: Scalars['String'];
/** An instance of, or reference to, a tradable instrument. */
tradableInstrument: TradableInstrument;
/** @deprecated Simplify and consolidate trades query and remove nesting. Use trades query instead */
@@ -2820,8 +2816,6 @@ export type NewMarket = {
riskParameters: RiskModel;
/** Successor market configuration. If this proposed market is meant to succeed a given market, then this needs to be set. */
successorConfiguration?: Maybe<SuccessorConfiguration>;
/** The market minimum tick size */
tickSize: Scalars['String'];
};
/** Configuration for a new spot market on Vega */
@@ -2845,8 +2839,6 @@ export type NewSpotMarket = {
riskParameters?: Maybe<RiskModel>;
/** Specifies parameters related to liquidity target stake calculation */
targetStakeParameters: TargetStakeParameters;
/** The market minimum tick size */
tickSize: Scalars['String'];
};
export type NewTransfer = {
@@ -7082,8 +7074,6 @@ export type UpdateMarketConfiguration = {
quadraticSlippageFactor: Scalars['String'];
/** Updated futures market risk model parameters. */
riskParameters: UpdateMarketRiskParameters;
/** The market minimum tick size */
tickSize: Scalars['String'];
};
export type UpdateMarketLogNormalRiskModel = {
@@ -7181,8 +7171,6 @@ export type UpdateSpotMarketConfiguration = {
riskParameters: RiskModel;
/** Specifies parameters related to target stake calculation */
targetStakeParameters: TargetStakeParameters;
/** The market minimum tick size */
tickSize: Scalars['String'];
};
export type UpdateVolumeDiscountProgram = {
@@ -17,8 +17,8 @@ export const InputError = ({
...props
}: InputErrorProps) => {
const effectiveClassName = classNames(
'text-sm block items-center first-letter:capitalize',
'mt-2 min-w-0 break-words',
'text-sm flex items-center first-letter:uppercase',
'mt-2',
{
'border-danger': intent === 'danger',
'border-warning': intent === 'warning',
+1 -1
View File
@@ -1,4 +1,4 @@
export const isValidUrl = (url?: string | null) => {
export const isValidUrl = (url?: string) => {
if (!url) return false;
try {
new URL(url);
@@ -1,9 +1,4 @@
import {
type ReactNode,
type FunctionComponent,
forwardRef,
useState,
} from 'react';
import { type ReactNode, type FunctionComponent, forwardRef } from 'react';
import {
ConnectorErrors,
isBrowserWalletInstalled,
@@ -17,7 +12,6 @@ import { useConnect } from '../../hooks/use-connect';
import { Links } from '../../constants';
import { ConnectorIcon } from './connector-icon';
import { useUserAgent } from '@vegaprotocol/react-helpers';
import { Trans } from 'react-i18next';
const vegaExtensionsLinks = {
chrome: Links.chromeExtension,
@@ -35,67 +29,48 @@ export const ConnectionOptions = ({
onConnect: (id: ConnectorType) => void;
}) => {
const t = useT();
const { connectors } = useConnect();
const error = useWallet((store) => store.error);
const [isInstalling, setIsInstalling] = useState(false);
const { connectors } = useConnect();
return (
<div className="flex flex-col items-start gap-4">
<h2 className="text-xl">{t('Connect to Vega')}</h2>
{isInstalling ? (
<p className="text-warning">
<Trans
i18nKey="Once you have added the extension, <0>refresh</0> your browser."
components={[
<button
onClick={() => window.location.reload()}
className="underline underline-offset-4"
/>,
]}
/>
<ul
className="grid grid-cols-1 sm:grid-cols-2 gap-1 -mx-2"
data-testid="connectors-list"
>
{connectors.map((c) => {
const ConnectionOption = ConnectionOptionRecord[c.id];
const props = {
id: c.id,
name: c.name,
description: c.description,
showDescription: false,
onClick: () => onConnect(c.id),
};
if (ConnectionOption) {
return (
<li key={c.id}>
<ConnectionOption {...props} />
</li>
);
}
return (
<li key={c.id}>
<ConnectionOptionDefault {...props} />
</li>
);
})}
</ul>
{error && error.code !== ConnectorErrors.userRejected.code && (
<p
className="text-danger text-sm first-letter:uppercase"
data-testid="connection-error"
>
{error.message}
</p>
) : (
<>
<ul
className="grid grid-cols-1 sm:grid-cols-2 gap-1 -mx-2"
data-testid="connectors-list"
>
{connectors.map((c) => {
const ConnectionOption = ConnectionOptionRecord[c.id];
const props = {
id: c.id,
name: c.name,
description: c.description,
showDescription: false,
onClick: () => onConnect(c.id),
onInstall: () => setIsInstalling(true),
};
if (ConnectionOption) {
return (
<li key={c.id}>
<ConnectionOption {...props} />
</li>
);
}
return (
<li key={c.id}>
<ConnectionOptionDefault {...props} />
</li>
);
})}
</ul>
{error && error.code !== ConnectorErrors.userRejected.code && (
<p
className="text-danger text-sm first-letter:uppercase"
data-testid="connection-error"
>
{error.message}
{error.data ? `: ${error.data}` : ''}
</p>
)}
</>
)}
<a
href={Links.walletOverview}
@@ -115,7 +90,6 @@ interface ConnectionOptionProps {
description: string;
showDescription?: boolean;
onClick: () => void;
onInstall?: () => void;
}
const CONNECTION_OPTION_CLASSES =
@@ -168,7 +142,6 @@ export const ConnectionOptionInjected = ({
description,
showDescription = false,
onClick,
onInstall,
}: ConnectionOptionProps) => {
const t = useT();
const userAgent = useUserAgent();
@@ -185,11 +158,7 @@ export const ConnectionOptionInjected = ({
</span>
</ConnectionOptionButtonWithDescription>
) : (
<ConnectionOptionLinkWithDescription
id={id}
href={link}
onClick={onInstall}
>
<ConnectionOptionLinkWithDescription id={id} href={link}>
<span className="flex flex-col justify-start text-left">
<span className="capitalize leading-5">
{t('Get the Vega Wallet')}
@@ -214,7 +183,7 @@ export const ConnectionOptionInjected = ({
{name}
</ConnectionOptionButton>
) : (
<ConnectionOptionLink id={id} href={link} onClick={onInstall}>
<ConnectionOptionLink id={id} href={link}>
{t('Get the Vega Wallet')}
</ConnectionOptionLink>
)}
@@ -306,9 +275,8 @@ const ConnectionOptionLink = forwardRef<
children: ReactNode;
id: ConnectorType;
href: string;
onClick?: () => void;
}
>(({ children, id, href, onClick }, ref) => {
>(({ children, id, href }, ref) => {
return (
<a
href={href}
@@ -317,7 +285,6 @@ const ConnectionOptionLink = forwardRef<
className={CONNECTION_OPTION_CLASSES}
data-testid={`connector-${id}`}
ref={ref}
onClick={onClick}
>
<ConnectorIcon id={id} />
{children}
@@ -353,10 +320,8 @@ const ConnectionOptionLinkWithDescription = forwardRef<
children: ReactNode;
id: ConnectorType;
href: string;
onClick?: () => void;
}
>(({ children, id, href, onClick }, ref) => {
>(({ children, id, href }, ref) => {
return (
<a
ref={ref}
@@ -364,7 +329,6 @@ const ConnectionOptionLinkWithDescription = forwardRef<
href={href}
target="_blank"
rel="noreferrer"
onClick={onClick}
>
<span>
<ConnectorIcon id={id} />
@@ -1,20 +1,17 @@
import { useEffect } from 'react';
import { useEffect, useState } from 'react';
import { useWallet } from './use-wallet';
import { useConnect } from './use-connect';
export function useEagerConnect() {
const current = useWallet((store) => store.current);
const status = useWallet((store) => store.status);
const { connect } = useConnect();
const [connecting, setConnecting] = useState(true);
useEffect(() => {
const attemptConnect = async () => {
// No stored config, or config was malformed or no risk accepted
if (!current) {
return;
}
if (status !== 'disconnected') {
setConnecting(false);
return;
}
@@ -22,13 +19,15 @@ export function useEagerConnect() {
await connect(current);
} catch {
console.warn(`Failed to connect with connector: ${current}`);
} finally {
setConnecting(false);
}
};
if (typeof window !== 'undefined') {
attemptConnect();
}
}, [status, connect, current]);
}, [connect, current, connecting]);
return status;
return connecting;
}
@@ -65,12 +65,12 @@ export const useSimpleTransaction = (opts?: Options) => {
if (err.code === ConnectorErrors.userRejected.code) {
setStatus('idle');
} else {
setError(`${err.message}${err.data ? `: ${err.data}` : ''}`);
setError(err.message);
setStatus('idle');
opts?.onError?.(err.message);
}
} else {
const msg = t('Something went wrong');
const msg = t('Wallet rejected transaction');
setError(msg);
setStatus('idle');
opts?.onError?.(msg);
@@ -7,7 +7,6 @@ import {
listKeysError,
noWalletError,
sendTransactionError,
userRejectedError,
} from '../errors';
import {
type TransactionParams,
@@ -15,19 +14,6 @@ import {
type VegaWalletEvent,
} from '../types';
interface InjectedError {
message: string;
code: number;
data:
| {
message: string;
code: number;
}
| string;
}
const USER_REJECTED_CODE = -4;
export class InjectedConnector implements Connector {
readonly id = 'injected';
readonly name = 'Vega Wallet';
@@ -99,55 +85,15 @@ export class InjectedConnector implements Connector {
sentAt: res.sentAt,
};
} catch (err) {
if (this.isInjectedError(err)) {
if (err.code === USER_REJECTED_CODE) {
throw userRejectedError();
}
if (typeof err.data === 'string') {
throw sendTransactionError(err.data);
} else {
throw sendTransactionError(err.data.message);
}
}
throw sendTransactionError();
}
}
on(event: VegaWalletEvent, callback: () => void) {
// Check for on/off in case user is on older versions which don't support it
// We can remove this check once FF is at the latest version
if (
typeof window.vega !== 'undefined' &&
typeof window.vega.on === 'function'
) {
window.vega.on(event, callback);
}
window.vega.on(event, callback);
}
off(event: VegaWalletEvent, callback: () => void) {
// Check for on/off in case user is on older versions which don't support it
// We can remove this check once FF is at the latest version
if (
typeof window.vega !== 'undefined' &&
typeof window.vega.off === 'function'
) {
window.vega.off(event, callback);
}
}
private isInjectedError(obj: unknown): obj is InjectedError {
if (
obj !== undefined &&
obj !== null &&
typeof obj === 'object' &&
'code' in obj &&
'message' in obj &&
'data' in obj
) {
return true;
}
return false;
window.vega.off(event, callback);
}
}
@@ -17,8 +17,6 @@ import {
type JsonRpcConnectorConfig = { url: string; token?: string };
const USER_REJECTED_CODE = 3001;
export class JsonRpcConnector implements Connector {
readonly id = 'jsonRpc';
readonly name = 'Command Line Wallet';
@@ -29,7 +27,7 @@ export class JsonRpcConnector implements Connector {
requestId: number = 0;
store: StoreApi<Store> | undefined;
pollRef: NodeJS.Timer | undefined;
ee: InstanceType<typeof EventEmitter>;
ee: EventEmitter;
constructor(config: JsonRpcConnectorConfig) {
this.url = config.url;
@@ -65,7 +63,7 @@ export class JsonRpcConnector implements Connector {
const token = response.headers.get('Authorization');
if (!response.ok) {
if ('error' in data && data.error.code === USER_REJECTED_CODE) {
if ('error' in data && data.error.code === 3001) {
throw userRejectedError();
}
throw connectError('response not ok');
@@ -139,7 +137,7 @@ export class JsonRpcConnector implements Connector {
if (!response.ok) {
if ('error' in data) {
if (data.error.code === USER_REJECTED_CODE) {
if (data.error.code === 3001) {
throw userRejectedError();
}
+97 -102
View File
@@ -1,3 +1,4 @@
import EventEmitter from 'eventemitter3';
import {
ConnectorError,
chainIdError,
@@ -5,13 +6,13 @@ import {
listKeysError,
noWalletError,
sendTransactionError,
userRejectedError,
} from '../errors';
import { type Transaction } from '../transaction-types';
import {
JsonRpcMethod,
type Connector,
type TransactionParams,
type VegaWalletEvent,
} from '../types';
enum EthereumMethod {
@@ -42,6 +43,7 @@ declare global {
type WindowEthereumProvider = {
isMetaMask: boolean;
request<T = unknown>(args: RequestArguments): Promise<T>;
selectedAddress: string | null;
};
interface Window {
@@ -50,16 +52,6 @@ declare global {
}
}
interface SnapRPCError {
code: number;
message: string;
data?: {
originalError: { code: number };
};
}
const USER_REJECTED_CODE = -4;
export class SnapConnector implements Connector {
readonly id = 'snap';
readonly name = 'MetaMask Snap';
@@ -69,6 +61,8 @@ export class SnapConnector implements Connector {
node: string;
version: string;
snapId: string;
pollRef: NodeJS.Timer | undefined;
ee: EventEmitter;
// Note: apps may not know which node is selected on start up so its up
// to the app to make sure class intances are renewed if the node changes
@@ -76,21 +70,14 @@ export class SnapConnector implements Connector {
this.node = config.node;
this.version = config.version;
this.snapId = config.snapId;
this.ee = new EventEmitter();
}
bindStore() {}
async connectWallet(desiredChainId: string) {
try {
const res = await this.requestSnap();
if (res[this.snapId].blocked) {
throw connectError('snap is blocked');
}
if (!res[this.snapId].enabled) {
throw connectError('snap is not enabled');
}
await this.requestSnap();
const { chainId } = await this.getChainId();
@@ -100,6 +87,7 @@ export class SnapConnector implements Connector {
);
}
this.startPoll();
return { success: true };
} catch (err) {
if (err instanceof ConnectorError) {
@@ -110,66 +98,57 @@ export class SnapConnector implements Connector {
}
}
async disconnectWallet() {}
async disconnectWallet() {
this.stopPoll();
}
// deprecated, pass chain on connect
async getChainId() {
try {
const data = await this.invokeSnap<{ chainID: string }>(
const res = await this.invokeSnap<{ chainID: string }>(
JsonRpcMethod.GetChainId,
{
networkEndpoints: [this.node],
}
);
if ('error' in data) {
throw chainIdError(data.error.message);
}
return { chainId: data.chainID };
return { chainId: res.chainID };
} catch (err) {
if (err instanceof ConnectorError) {
throw err;
}
this.stopPoll();
throw chainIdError();
}
}
async listKeys() {
try {
const data = await this.invokeSnap<{
const res = await this.invokeSnap<{
keys: Array<{ publicKey: string; name: string }>;
}>(JsonRpcMethod.ListKeys);
if ('error' in data) {
throw listKeysError(data.error.message);
}
return data.keys;
return res.keys;
} catch (err) {
if (err instanceof ConnectorError) {
throw err;
}
this.stopPoll();
throw listKeysError();
}
}
async isConnected() {
try {
// Check if metamask is unlocked
if (!window.ethereum.selectedAddress) {
throw noWalletError();
}
// If this throws its likely the snap is disabled or has been uninstalled
await this.listKeys();
return { connected: true };
} catch (err) {
this.stopPoll();
return { connected: false };
}
}
async sendTransaction(params: TransactionParams) {
try {
// If the transaction is invalid this will throw with SnapRPCError
// but if its rejected it will resolve with 'error' in data
const data = await this.invokeSnap<{
const res = await this.invokeSnap<{
transactionHash: string;
transaction: { signature: { value: string } };
receivedAt: string;
@@ -181,99 +160,115 @@ export class SnapConnector implements Connector {
networkEndpoints: [this.node],
});
if ('error' in data) {
if (data.error.code === USER_REJECTED_CODE) {
throw userRejectedError();
}
throw sendTransactionError(`${data.error.message}: ${data.error.data}`);
}
return {
transactionHash: data.transactionHash,
signature: data.transaction.signature.value,
receivedAt: data.receivedAt,
sentAt: data.sentAt,
transactionHash: res.transactionHash,
signature: res.transaction.signature.value,
receivedAt: res.receivedAt,
sentAt: res.sentAt,
};
} catch (err) {
if (err instanceof ConnectorError) {
throw err;
}
if (this.isSnapRPCError(err)) {
throw sendTransactionError(err.message);
}
throw sendTransactionError();
}
}
on() {}
off() {}
on(event: VegaWalletEvent, callback: () => void) {
this.ee.on(event, callback);
}
off(event: VegaWalletEvent, callback?: () => void) {
this.ee.off(event, callback);
}
////////////////////////////////////
// Snap methods
////////////////////////////////////
private startPoll() {
// This only event we need to poll for right now is client.disconnect,
// if more events get added we will need more logic here
this.pollRef = setInterval(async () => {
const result = await this.isConnected();
if (result.connected) return;
this.ee.emit('client.disconnected');
}, 2000);
}
private stopPoll() {
if (this.pollRef) {
clearInterval(this.pollRef);
}
}
/**
* Requests permission for a website to communicate with the specified snaps
* and attempts to install them if they're not already installed.
* If the installation of any snap fails, returns the error that caused the failure.
* More informations here: https://docs.metamask.io/snaps/reference/rpc-api/#wallet_requestsnaps
*/
private async requestSnap(): Promise<{
[snapId: string]: {
blocked: boolean;
enabled: boolean;
id: string;
version: string;
};
}> {
return window.ethereum.request({
method: EthereumMethod.RequestSnaps,
params: {
[this.snapId]: {
version: this.version,
},
private async requestSnap() {
await this.request(EthereumMethod.RequestSnaps, {
[this.snapId]: {
version: this.version,
},
});
}
// TODO: check if this is needed, its used in use-snap-status
//
//
// /**
// * Gets the list of all installed snaps.
// * More information here: https://docs.metamask.io/snaps/reference/rpc-api/#wallet_getsnaps
// */
// async getSnap() {
// const snaps = await this.request(EthereumMethod.GetSnaps);
// return Object.values(snaps).find(
// (s) => s.id === this.snapId && s.version === this.version
// );
// }
/**
* Calls a method on the specified snap, always vega in this case
* should always be npm:@vegaprotocol/snap
*/
private async invokeSnap<TResult>(
method: JsonRpcMethod,
params: SnapInvocationParams = {}
): Promise<TResult | { error: SnapRPCError }> {
// MetaMask in Firefox doesn't like undefined properties or some properties
// on __proto__ so we need to strip them out with JSON.strinfify
params = JSON.parse(JSON.stringify(params));
return window.ethereum.request({
method: EthereumMethod.InvokeSnap,
params: {
snapId: this.snapId,
request: {
method,
params,
},
params?: SnapInvocationParams
): Promise<TResult> {
return await this.request(EthereumMethod.InvokeSnap, {
snapId: this.snapId,
request: {
method,
params,
},
});
}
private isSnapRPCError(obj: unknown): obj is SnapRPCError {
if (
obj !== undefined &&
obj !== null &&
typeof obj === 'object' &&
'code' in obj &&
'message' in obj
) {
return true;
/**
* Calls window.ethereum.request with method and params
*/
private async request<TResult>(
method: EthereumMethod,
params?: object
): Promise<TResult> {
if (window.ethereum?.request && window.ethereum?.isMetaMask) {
// MetaMask in Firefox doesn't like undefined properties or some properties
// on __proto__ so we need to strip them out with JSON.strinfify
try {
params = JSON.parse(JSON.stringify(params));
} catch (err) {
throw sendTransactionError();
}
return window.ethereum.request({
method,
params,
});
}
return false;
throw noWalletError();
}
}
+1 -1
View File
@@ -12,7 +12,7 @@ export class ConnectorError extends Error {
export const ConnectorErrors = {
userRejected: { message: 'user rejected', code: 0 },
noConnector: { message: 'not connected', code: 1 },
noConnector: { message: 'no connector', code: 1 },
connect: { message: 'failed to connect', code: 2 },
disconnect: { message: 'failed to disconnect', code: 3 },
chainId: { message: 'incorrect chain id', code: 4 },
-3
View File
@@ -403,9 +403,6 @@ export interface BatchMarketInstructionSubmissionBody {
// Note: If multiple orders are submitted the first order ID is determined by hashing the signature of the transaction
// (see determineId function). For each subsequent order's ID, a hash of the previous orders ID is used
submissions?: OrderSubmission[];
stopOrdersSubmission?: StopOrdersSubmission[];
stopOrdersCancellation?: StopOrdersCancellation[];
updateMarginMode?: UpdateMarginMode[];
};
}
+2 -1
View File
@@ -93,6 +93,7 @@ describe('disconnect', () => {
expect(result).toEqual({ status: 'disconnected' });
expect(config.store.getState()).toMatchObject({
status: 'disconnected',
error: noConnectorError(),
current: undefined,
keys: [],
pubKey: undefined,
@@ -129,7 +130,7 @@ describe('refresh keys', () => {
it('handles invalid connector', async () => {
await config.refreshKeys();
expect(config.store.getState()).toMatchObject({
error: undefined,
error: noConnectorError(),
});
});

Some files were not shown because too many files have changed in this diff Show More