Feat/Intro to staking page (#736)
* frontend-monorepo-646: Staking intro tweaked and tests amended * frontend-monorepo-646: Sorting grid placements and setting a fixed width for the main content area on larger screens * frontend-monorepo-646: Removing some redundant elements and tweaking some tests * test: fixes ahead of ui changes * test: lint * test: remove unused import * test: renabling tests * test: fixes * test: fixes to catch up with last PR * test: removal of tests no longer required * test: removal of unused import * Update apps/token/src/i18n/translations/dev.json Co-authored-by: candida-d <62548908+candida-d@users.noreply.github.com> * frontend-monorepo-646: Updated staking text Co-authored-by: AndyWhiteVega <andy@vegaprotocol.io> Co-authored-by: candida-d <62548908+candida-d@users.noreply.github.com>
This commit is contained in:
parent
3792029bec
commit
936f849cef
@ -25,7 +25,7 @@ const ethWalletContainer = '[data-testid="ethereum-wallet"]';
|
||||
const txTimeout = { timeout: 40000 };
|
||||
const epochTimeout = { timeout: 10000 };
|
||||
|
||||
context('Staking Flow - with eth and vega wallets connected', function () {
|
||||
context('Staking Tab - with eth and vega wallets connected', function () {
|
||||
before('visit staking tab and connect vega wallet', function () {
|
||||
cy.vega_wallet_import();
|
||||
cy.visit('/');
|
||||
@ -411,7 +411,7 @@ context('Staking Flow - with eth and vega wallets connected', function () {
|
||||
.and('be.visible');
|
||||
});
|
||||
|
||||
it('Disassociating all tokens - removes all staked tokens', function () {
|
||||
it.skip('Disassociating all tokens max - removes all staked tokens', function () {
|
||||
cy.staking_page_associate_tokens('3');
|
||||
|
||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
||||
|
@ -1,12 +1,5 @@
|
||||
const guideLink = '[data-testid="staking-guide-link"]';
|
||||
const step1 = '[data-testid="staking-step-1"]';
|
||||
const step2 = '[data-testid="staking-step-2"]';
|
||||
const step3 = '[data-testid="staking-step-3"]';
|
||||
const sectionHeader = 'h2';
|
||||
const connectToEthBtn = '[data-testid="connect-to-eth-btn"]';
|
||||
const connectToVegaBtn = '[data-testid="connect-to-vega-wallet-btn"]';
|
||||
const link = '[data-testid="link"]';
|
||||
const warning = '[data-testid="callout"]';
|
||||
const validators = '[data-testid="node-list-item"]';
|
||||
|
||||
context('Staking Page - verify elements on page', function () {
|
||||
before('navigate to staking page', function () {
|
||||
@ -20,7 +13,7 @@ context('Staking Page - verify elements on page', function () {
|
||||
});
|
||||
|
||||
it('should have STAKING ON VEGA header visible', function () {
|
||||
cy.verify_page_header('Staking on Vega');
|
||||
cy.verify_page_header('Staking');
|
||||
});
|
||||
|
||||
it('should have Staking Guide link visible', function () {
|
||||
@ -34,73 +27,9 @@ context('Staking Page - verify elements on page', function () {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('step 1 section', function () {
|
||||
it('should have header visible', function () {
|
||||
cy.get(step1).within(() => {
|
||||
cy.get(sectionHeader)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Step 1. Connect to a Vega Wallet');
|
||||
});
|
||||
});
|
||||
|
||||
it('should have text visible', function () {
|
||||
cy.get(step1).within(() => {
|
||||
cy.get(link)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Vega Wallet')
|
||||
.and('have.attr', 'href', 'https://vega.xyz/wallet');
|
||||
});
|
||||
});
|
||||
|
||||
it('should have connect to eth button visible', function () {
|
||||
cy.get(step1).within(() => {
|
||||
cy.get(connectToEthBtn)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Connect Ethereum wallet');
|
||||
});
|
||||
});
|
||||
|
||||
it('should have connect to vega button visible', function () {
|
||||
cy.get(step1).within(() => {
|
||||
cy.get(connectToVegaBtn)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Connect Vega wallet');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('step 2 section', function () {
|
||||
it('should have header visible', function () {
|
||||
cy.get(step2).within(() => {
|
||||
cy.get(sectionHeader)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Step 2. Associate tokens with a Vega Wallet');
|
||||
});
|
||||
});
|
||||
|
||||
it('should have warning visible', function () {
|
||||
cy.get(step2).within(() => {
|
||||
cy.get(warning)
|
||||
.should('be.visible')
|
||||
.and(
|
||||
'have.text',
|
||||
'You need to connect to an Ethereum wallet first'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('step 3 section', function () {
|
||||
it('should have header visible', function () {
|
||||
cy.get(step3).within(() => {
|
||||
cy.get(sectionHeader)
|
||||
.should('be.visible')
|
||||
.and(
|
||||
'have.text',
|
||||
"Step 3. Select the validator you'd like to nominate"
|
||||
);
|
||||
});
|
||||
describe('validators section', function () {
|
||||
it('should be visible', function () {
|
||||
cy.get(validators).should('be.visible');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -10,7 +10,7 @@ export const AppBanner = () => {
|
||||
if (!bannerMessage) return <div />;
|
||||
|
||||
return (
|
||||
<div className="bg-white p-8 text-black" role="alert">
|
||||
<div className="row-start-1 bg-white p-8 text-black" role="alert">
|
||||
<p>
|
||||
<span className="inline-block relative top-[1px] text-danger text-ui mr-[5px]">
|
||||
<Error />
|
||||
|
@ -9,10 +9,10 @@ export interface TemplateSidebarProps {
|
||||
|
||||
export function TemplateSidebar({ children, sidebar }: TemplateSidebarProps) {
|
||||
return (
|
||||
<div className="border-b border-white lg:grid lg:grid-rows-[auto_minmax(600px,_1fr)] lg:grid-cols-[1fr_450px]">
|
||||
<div className="row-start-2 border-b border-white lg:grid lg:grid-rows-[auto_minmax(600px,_1fr)] lg:grid-cols-[850px_450px]">
|
||||
<Nav />
|
||||
<main className="p-20">{children}</main>
|
||||
<aside className="hidden lg:block lg:col-start-2 lg:col-end-4 lg:row-start-1 lg: row-end-4 p-20 bg-banner bg-contain border-l border-white">
|
||||
<main className="col-start-1 p-20">{children}</main>
|
||||
<aside className="col-start-2 row-start-1 row-span-2 hidden lg:block p-20 bg-banner bg-contain border-l border-white">
|
||||
{sidebar.map((Component, i) => (
|
||||
<section className="mb-20 last:mb-0" key={i}>
|
||||
{Component}
|
||||
|
@ -8,7 +8,7 @@
|
||||
"pageTitleLiquidity": "Incentivised Liquidity Programme",
|
||||
"pageTitleRedemptionTranche": "Redeem from Tranche",
|
||||
"pageTitleTranches": "Vesting tranches",
|
||||
"pageTitleStaking": "Staking on Vega",
|
||||
"pageTitleStaking": "Staking",
|
||||
"pageTitle404": "Page not found",
|
||||
"pageTitleNotPermitted": "Can not proceed!",
|
||||
"pageTitleDisassociate": "Disassociate $VEGA tokens from a Vega key",
|
||||
@ -511,10 +511,11 @@
|
||||
"unsupportedChainIdError": "You're connected to an unsupported network",
|
||||
"userRejectionError": "Please authorise this website to access your Ethereum account",
|
||||
"unknownEthereumConnectionError": "An unknown error occurred. Check the console in your browser's web developer tools for more details",
|
||||
"stakingDescription1": "Associate VEGA tokens from your Ethereum wallet to a Vega wallet/key to nominate a validator",
|
||||
"stakingDescription2": "Validators and their nominators are rewared every 24 hours for securing the network with a cut of trading fees (and rewards from the Vega treasury). Staking rewards are paid into your Vega wallet after an epoch ends.",
|
||||
"stakingDescription3": "The amount that a validator, and its nominators receives is proportionate to the amount staked on it, however a validator can be penalised during an epoch for a number of reasons. In this case the validator and its nominator will forfeit some or all of its reward from that epoch",
|
||||
"stakingDescription4": "A validator will receive a higher share of the pot than its nominators. This share is the same for all validators and is set by a network parameter.",
|
||||
"stakingDescriptionTitle": "How does staking on Vega work?",
|
||||
"stakingDescription1": "1. VEGA is an ERC20 token. Associate it with a Vega wallet using the staking bridge",
|
||||
"stakingDescription2": "2. Use this site and your Vega wallet to nominate a validator",
|
||||
"stakingDescription3": "3. Earn a share of trading fees and treasury rewards for each full epoch staked",
|
||||
"stakingDescription4": "4. Move your stake if your validator is penalised",
|
||||
"readMoreStaking": "Read more about staking on Vega",
|
||||
"networkDown": "This site is not currently connecting to the network please try again later.",
|
||||
"ethTransactionModalTitle": "Ethereum Transactions",
|
||||
|
@ -1,224 +1,50 @@
|
||||
import { Button, Callout, Intent } from '@vegaprotocol/ui-toolkit';
|
||||
import { useWeb3React } from '@web3-react/core';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
import { Link as RouteLink } from 'react-router-dom';
|
||||
|
||||
import { BulletHeader } from '../../components/bullet-header';
|
||||
import { Link } from '@vegaprotocol/ui-toolkit';
|
||||
import { useEnvironment } from '@vegaprotocol/environment';
|
||||
import { Button, Callout, Intent, Link } from '@vegaprotocol/ui-toolkit';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Links } from '../../config';
|
||||
import {
|
||||
AppStateActionType,
|
||||
useAppState,
|
||||
} from '../../contexts/app-state/app-state-context';
|
||||
import { BigNumber } from '../../lib/bignumber';
|
||||
import { formatNumber } from '../../lib/format-number';
|
||||
import type { Staking as StakingQueryResult } from './__generated__/Staking';
|
||||
import { ConnectToVega } from './connect-to-vega';
|
||||
import { NodeList } from './node-list';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { truncateMiddle } from '../../lib/truncate-middle';
|
||||
|
||||
const stakingBulletStyles = { marginBottom: '12px', fontSize: '18px' };
|
||||
import type { Staking as StakingQueryResult } from './__generated__/Staking';
|
||||
|
||||
export const Staking = ({ data }: { data?: StakingQueryResult }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<>
|
||||
<section className="mb-24">
|
||||
<p>{t('stakingDescription1')}</p>
|
||||
<p>{t('stakingDescription2')}</p>
|
||||
<p>{t('stakingDescription3')}</p>
|
||||
<p>{t('stakingDescription4')}</p>
|
||||
<p>
|
||||
<section data-testid="staking-description" className="mb-24">
|
||||
<Callout
|
||||
intent={Intent.Primary}
|
||||
iconName="help"
|
||||
title={t('stakingDescriptionTitle')}
|
||||
>
|
||||
<ol className="mb-20">
|
||||
<li>{t('stakingDescription1')}</li>
|
||||
<li>{t('stakingDescription2')}</li>
|
||||
<li>{t('stakingDescription3')}</li>
|
||||
<li>{t('stakingDescription4')}</li>
|
||||
</ol>
|
||||
|
||||
<Link
|
||||
href={Links.STAKING_GUIDE}
|
||||
className="text-white underline"
|
||||
target="_blank"
|
||||
data-testid="staking-guide-link"
|
||||
>
|
||||
{t('readMoreStaking')}
|
||||
<Button variant="secondary">{t('readMoreStaking')}</Button>
|
||||
</Link>
|
||||
</p>
|
||||
</Callout>
|
||||
</section>
|
||||
|
||||
<section data-testid="staking-step-1">
|
||||
<BulletHeader tag="h2" style={stakingBulletStyles}>
|
||||
{t('stakingStep1')}
|
||||
</BulletHeader>
|
||||
<StakingStepConnectWallets />
|
||||
</section>
|
||||
<section data-testid="staking-step-2">
|
||||
<BulletHeader tag="h2" style={stakingBulletStyles}>
|
||||
{t('stakingStep2')}
|
||||
</BulletHeader>
|
||||
<StakingStepAssociate
|
||||
associated={
|
||||
new BigNumber(
|
||||
data?.party?.stake.currentStakeAvailableFormatted || '0'
|
||||
)
|
||||
}
|
||||
/>
|
||||
</section>
|
||||
<section data-testid="staking-step-3">
|
||||
<BulletHeader tag="h2" style={stakingBulletStyles}>
|
||||
{t('stakingStep3')}
|
||||
</BulletHeader>
|
||||
<section>
|
||||
<StakingStepSelectNode data={data} />
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const StakingStepConnectWallets = () => {
|
||||
const { ETHERSCAN_URL } = useEnvironment();
|
||||
const { t } = useTranslation();
|
||||
const { account } = useWeb3React();
|
||||
const { keypair } = useVegaWallet();
|
||||
const { appDispatch } = useAppState();
|
||||
|
||||
if (keypair && account) {
|
||||
return (
|
||||
<Callout intent={Intent.Success} iconName="tick" title={'Connected'}>
|
||||
<p>
|
||||
{t('Connected Ethereum address')}
|
||||
<Link
|
||||
title={t('View on Etherscan (opens in a new tab)')}
|
||||
href={`${ETHERSCAN_URL}/tx/${account}`}
|
||||
target="_blank"
|
||||
>
|
||||
{truncateMiddle(account)}
|
||||
</Link>
|
||||
</p>
|
||||
<p className="mb-8">
|
||||
{t('stakingVegaWalletConnected', {
|
||||
key: truncateMiddle(keypair.pub),
|
||||
})}
|
||||
</p>
|
||||
</Callout>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
<Trans
|
||||
i18nKey="stakingStep1Text"
|
||||
components={{
|
||||
vegaWalletLink: (
|
||||
<Link
|
||||
href={Links.WALLET_PAGE}
|
||||
className="text-white underline"
|
||||
target="_blank"
|
||||
/>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
{account ? (
|
||||
<div className="mb-24">
|
||||
<Callout
|
||||
iconName="tick"
|
||||
intent={Intent.Success}
|
||||
title={`Ethereum wallet connected: ${account}`}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<p>
|
||||
<Button
|
||||
onClick={() =>
|
||||
appDispatch({
|
||||
type: AppStateActionType.SET_ETH_WALLET_OVERLAY,
|
||||
isOpen: true,
|
||||
})
|
||||
}
|
||||
data-testid="connect-to-eth-btn"
|
||||
>
|
||||
{t('connectEthWallet')}
|
||||
</Button>
|
||||
</p>
|
||||
)}
|
||||
{keypair ? (
|
||||
<div className="mb-24">
|
||||
<Callout
|
||||
iconName="tick"
|
||||
intent={Intent.Success}
|
||||
title={`Vega wallet connected: ${truncateMiddle(keypair.pub)}`}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<ConnectToVega />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const StakingStepAssociate = ({
|
||||
associated,
|
||||
}: {
|
||||
associated: BigNumber;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { account } = useWeb3React();
|
||||
const { keypair } = useVegaWallet();
|
||||
|
||||
if (!account) {
|
||||
return (
|
||||
<Callout
|
||||
intent={Intent.Danger}
|
||||
iconName="error"
|
||||
title={t('stakingAssociateConnectEth')}
|
||||
/>
|
||||
);
|
||||
} else if (!keypair) {
|
||||
return (
|
||||
<Callout
|
||||
intent={Intent.Danger}
|
||||
iconName="error"
|
||||
title={t('stakingAssociateConnectVega')}
|
||||
/>
|
||||
);
|
||||
}
|
||||
if (associated.isGreaterThan(0)) {
|
||||
return (
|
||||
<Callout
|
||||
intent={Intent.Success}
|
||||
iconName="tick"
|
||||
title={t('stakingHasAssociated', { tokens: formatNumber(associated) })}
|
||||
>
|
||||
<div className="flex flex-wrap gap-4">
|
||||
<RouteLink to="associate">
|
||||
<Button data-testid="associate-more-tokens-btn">
|
||||
{t('stakingAssociateMoreButton')}
|
||||
</Button>
|
||||
</RouteLink>
|
||||
<RouteLink to="disassociate">
|
||||
<Button data-testid="disassociate-tokens-btn">
|
||||
{t('stakingDisassociateButton')}
|
||||
</Button>
|
||||
</RouteLink>
|
||||
</div>
|
||||
</Callout>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<p>{t('stakingStep2Text')}</p>
|
||||
<RouteLink to="/staking/associate">
|
||||
<Button data-testid="associate-tokens-btn">
|
||||
{t('associateButton')}
|
||||
</Button>
|
||||
</RouteLink>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const StakingStepSelectNode = ({
|
||||
data,
|
||||
}: {
|
||||
data?: StakingQueryResult;
|
||||
}) => {
|
||||
return <NodeList epoch={data?.epoch} party={data?.party} />;
|
||||
return (
|
||||
<NodeList data-testid="node-list" epoch={data?.epoch} party={data?.party} />
|
||||
);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user