test(governance): e2e rewards (#3190)

This commit is contained in:
Joe Tsang 2023-03-14 16:10:58 +00:00 committed by GitHub
parent 95280f5b26
commit 090d850647
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 378 additions and 15 deletions

View File

@ -0,0 +1,103 @@
const vegaAssetAddress = '0x67175Da1D5e966e40D11c4B2519392B2058373de';
const vegaWalletUnstakedBalance =
'[data-testid="vega-wallet-balance-unstaked"]';
const rewardsTable = 'epoch-total-rewards-table';
const txTimeout = Cypress.env('txTimeout');
const rewardsTimeOut = { timeout: 60000 };
context('rewards - flow', { tags: '@slow' }, function () {
before('set up environment to allow rewards', function () {
cy.visit('/');
cy.wait_for_spinner();
cy.deposit_asset(vegaAssetAddress, '1000');
cy.validatorsSelfDelegate();
cy.ethereum_wallet_connect();
cy.connectVegaWallet();
topUpRewardsPool();
cy.navigate_to('validators');
cy.vega_wallet_teardown();
cy.staking_page_associate_tokens('6000');
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
'6,000.0',
txTimeout
);
cy.get('button').contains('Select a validator to nominate').click();
cy.click_on_validator_from_list(0);
cy.staking_validator_page_add_stake('3000');
cy.close_staking_dialog();
cy.navigate_to('validators');
cy.click_on_validator_from_list(1);
cy.staking_validator_page_add_stake('3000');
cy.close_staking_dialog();
cy.navigate_to('rewards');
});
it('Should display rewards per epoch', function () {
cy.getByTestId(rewardsTable, rewardsTimeOut).should('exist');
cy.getByTestId(rewardsTable)
.first()
.within(() => {
cy.getByTestId('asset').should('have.text', 'Vega');
cy.getByTestId('ACCOUNT_TYPE_GLOBAL_REWARD').should('have.text', '1');
cy.getByTestId('ACCOUNT_TYPE_FEES_INFRASTRUCTURE').should(
'have.text',
'0'
);
cy.getByTestId('total').should('have.text', '1');
});
});
it('Should update when epoch starts', function () {
cy.getByTestId(rewardsTable)
.first()
.within(() => {
cy.get('h2').first().invoke('text').as('epochNumber');
});
cy.wait_for_beginning_of_epoch();
cy.get('@epochNumber').then((epochNumber) => {
cy.getByTestId(rewardsTable)
.first()
.within(() => {
cy.get('h2').first().invoke('text').should('not.equal', epochNumber);
});
});
});
// 2002-SINC-009 2002-SINC-010 2002-SINC-011 2002-SINC-012
it('Should display table of rewards earned by connected vega wallet', function () {
cy.getByTestId('epoch-reward-view-toggle-individual').click();
cy.getByTestId('connected-vega-key')
.find('span')
.should('have.text', Cypress.env('vegaWalletPublicKey'));
cy.getByTestId('epoch-individual-rewards-table')
.first()
.within(() => {
cy.get('h2').first().should('contain.text', 'EPOCH');
cy.getByTestId('individual-rewards-asset').should('have.text', 'Vega');
cy.getByTestId('ACCOUNT_TYPE_GLOBAL_REWARD')
.should('contain.text', '0.4415')
.and('contain.text', '(44.15%)');
cy.getByTestId('ACCOUNT_TYPE_FEES_INFRASTRUCTURE')
.should('contain.text', '0.0004')
.and('contain.text', '(44.15%)');
cy.getByTestId('total').should('have.text', '0.4419');
});
});
function topUpRewardsPool() {
// Must ensure that test wallet contains assets already and that the tests are within the start and end epochs
cy.exec(
`vega wallet transaction send --wallet ${Cypress.env(
'vegaWalletName'
)} --pubkey ${Cypress.env(
'vegaWalletPublicKey'
)} -p "./src/fixtures/wallet/passphrase" --network DV '{"transfer":{"fromAccountType":4,"toAccountType":12,"to":"0000000000000000000000000000000000000000000000000000000000000000","asset":"b4f2726571fbe8e33b442dc92ed2d7f0d810e21835b7371a7915a365f07ccd9b","amount":"1000000000000000000","recurring":{"startEpoch":30, "endEpoch": 200, "factor":"1"}}}' --home ${Cypress.env(
'vegaWalletLocation'
)}`,
{ failOnNonZeroExit: false }
)
.its('stderr')
.should('contain', '');
}
});

View File

@ -27,7 +27,7 @@ context(
function () {
before('visit withdrawals and connect vega wallet', function () {
cy.updateCapsuleMultiSig(); // When running tests locally, will fail if run without restarting capsule
cy.deposit_asset(usdcEthAddress);
cy.deposit_asset(usdcEthAddress, '100000000000000000000');
});
beforeEach('Navigate to withdrawal page', function () {

View File

@ -73,7 +73,7 @@ context(
.should('be.visible')
.and(
'have.text',
'Rewards are credited 5 minutes after the epoch ends.This delay is set by a network parameter'
'Rewards are credited less than a minute after the epoch ends.This delay is set by a network parameter'
);
});
it('should have toggle for seeing total vs individual rewards', () => {

View File

@ -83,6 +83,7 @@ context('Staking Page - verify elements on page', function () {
.should('contain', 'Normalised voting power: 0.10%');
});
// 2002-SINC-018
it('Should be able to see validator total penalties', function () {
cy.get('[col-id="totalPenalties"] > div > span > span')
.should('have.length.at.least', 1)

View File

@ -10,7 +10,7 @@ Cypress.Commands.add(
);
const navigation = {
section: 'nav',
section: '[data-testid="navigation"]',
vesting: '[href="/token/redeem"]',
validators: '[href="/validators"]',
rewards: '[href="/rewards"]',

View File

@ -47,13 +47,14 @@ beforeEach(function () {
cy.wrap(this.vestingContract).as('vestingContract');
});
Cypress.Commands.add('deposit_asset', function (assetEthAddress) {
Cypress.Commands.add('deposit_asset', function (assetEthAddress, amount) {
cy.highlight('Depositing asset into vegawallet');
cy.get('@signer', { log: false }).then((signer) => {
// Approve asset
cy.wrap(
new TokenFaucetable(assetEthAddress, signer).approve(
Erc20BridgeAddress,
'10000000000'
amount + '0'.repeat(19)
)
)
.then((tx) => {
@ -67,7 +68,7 @@ Cypress.Commands.add('deposit_asset', function (assetEthAddress) {
cy.wrap(
bridge.deposit_asset(
assetEthAddress,
'1000000000',
amount + '0'.repeat(18),
'0x' + vegaWalletPubKey
),
{ timeout: transactionTimeout, log: false }

View File

@ -43,7 +43,7 @@ export const EpochIndividualRewards = () => {
data={data}
render={() => (
<div>
<p className="mb-10">
<p data-testid="connected-vega-key" className="mb-10">
{t('Connected Vega key')}:{' '}
<span className="text-white">{pubKey}</span>
</p>

View File

@ -17,9 +17,11 @@ import {
import { addMockTransactionResponse } from './lib/commands/mock-transaction-response';
import { addCreateMarket } from './lib/commands/create-market';
import { addConnectPublicKey } from './lib/commands/add-connect-public-key';
import { addValidatorsSelfDelegate } from './lib/commands/validators-self-delegate';
import { addVegaWalletSubmitProposal } from './lib/commands/vega-wallet-submit-proposal';
import { addGetNodes } from './lib/commands/get-nodes';
import { addVegaWalletSubmitLiquidityProvision } from './lib/commands/vega-wallet-submit-liquidity-provision';
import { addImportNodeWallets } from './lib/commands/import-node-wallets';
addGetTestIdcommand();
addSlackCommand();
@ -39,8 +41,10 @@ addSetVegaWallet();
addMockTransactionResponse();
addCreateMarket();
addConnectPublicKey();
addValidatorsSelfDelegate();
addVegaWalletSubmitProposal();
addVegaWalletSubmitLiquidityProvision();
addImportNodeWallets();
export { mockConnectWallet } from './lib/commands/vega-wallet-connect';
export type { onMessage } from './lib/mock-ws';

View File

@ -44,7 +44,7 @@ export async function createMarket(cfg: {
// To participate in governance (in this case proposing and voting in a market)
// you need to have staked (associated) some Vega with a Vega public key
await stakeForVegaPublicKey(cfg.vegaPubKey);
await stakeForVegaPublicKey(cfg.vegaPubKey, '10000');
// Send some of the asset for the market to be proposed to the test pubkey
const result = await faucetAsset(

View File

@ -8,7 +8,10 @@ import { wallet } from './ethereum-wallet';
const log = createLog('ethereum-setup');
export async function stakeForVegaPublicKey(vegaPublicKey: string) {
export async function stakeForVegaPublicKey(
vegaPublicKey: string,
amount: string
) {
if (!wallet) {
throw new Error('ethereum wallet not initialized');
}
@ -29,7 +32,7 @@ export async function stakeForVegaPublicKey(vegaPublicKey: string) {
const approveTx = await promiseWithTimeout(
tokenContract.approve(
ethereumConfig.staking_bridge_contract.address,
'100000' + '0'.repeat(18)
amount + '0'.repeat(19)
),
1000,
'approve staking tx'
@ -47,12 +50,12 @@ export async function stakeForVegaPublicKey(vegaPublicKey: string) {
wallet
);
const amount = '10000' + '0'.repeat(18);
log(`sending stake tx of ${amount} to ${vegaPublicKey}`);
const realAmount = amount + '0'.repeat(18);
log(`sending stake tx of ${realAmount} to ${vegaPublicKey}`);
const stakeTx = await promiseWithTimeout(
stakingContract.stake(amount, vegaPublicKey),
stakingContract.stake(realAmount, vegaPublicKey),
14000,
'stakingContract.stake(amount, vegaPublicKey)'
'stakingContract.stake(realAmount, vegaPublicKey)'
);
await promiseWithTimeout(
stakeTx.wait(3),

View File

@ -0,0 +1,37 @@
import { setGraphQLEndpoint } from './request';
import { stakeForVegaPublicKey } from './ethereum-setup';
import { createWalletClient, sendVegaTx } from './wallet-client';
import { createEthereumWallet } from './ethereum-wallet';
export async function selfDelegate(
cfg: {
ethWalletMnemonic: string;
ethereumProviderUrl: string;
vegaWalletUrl: string;
vegaUrl: string;
faucetUrl: string;
},
vegaWalletPubKey: string,
apiToken: string,
nodeId: string
) {
// setup wallet client and graphql clients
setGraphQLEndpoint(cfg.vegaUrl);
createWalletClient(cfg.vegaWalletUrl, apiToken);
createEthereumWallet(cfg.ethWalletMnemonic, cfg.ethereumProviderUrl);
// Associate tokens to validator wallet
await stakeForVegaPublicKey(vegaWalletPubKey, '3000');
// Stake on validator
// By default 3000 vega is minimum amount of stake required for self-delegation
const stakeTx = {
delegateSubmission: {
nodeId: nodeId,
amount: '3000' + '0'.repeat(18),
},
};
const result = await sendVegaTx(vegaWalletPubKey, stakeTx);
return result;
}

View File

@ -0,0 +1,84 @@
declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace Cypress {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
interface Chainable<Subject> {
importNodeWallets(): void;
}
}
}
export const addImportNodeWallets = () => {
Cypress.Commands.add('importNodeWallets', () => {
// Get node wallet recovery phrases
cy.exec('vegacapsule nodes ls --home-path ~/.vegacapsule/testnet/')
.its('stdout')
.then((result) => {
const obj = JSON.parse(result);
console.log(obj);
cy.writeFile(
'./src/fixtures/wallet/node0RecoveryPhrase',
obj['testnet-nodeset-validators-0-validator'].Vega.NodeWalletInfo
.VegaWalletRecoveryPhrase
);
cy.writeFile(
'./src/fixtures/wallet/node1RecoveryPhrase',
obj['testnet-nodeset-validators-1-validator'].Vega.NodeWalletInfo
.VegaWalletRecoveryPhrase
);
cy.wrap(
obj['testnet-nodeset-validators-0-validator'].Vega.NodeWalletInfo
.VegaWalletPublicKey
).as('node0PubKey');
cy.wrap(
obj['testnet-nodeset-validators-1-validator'].Vega.NodeWalletInfo
.VegaWalletPublicKey
).as('node1PubKey');
cy.wrap(
obj['testnet-nodeset-validators-0-validator'].Vega.NodeWalletInfo
.VegaWalletID
).as('node0Id');
cy.wrap(
obj['testnet-nodeset-validators-1-validator'].Vega.NodeWalletInfo
.VegaWalletID
).as('node1Id');
});
// Import node wallets
cy.exec(
'vega wallet import -w node0_wallet --recovery-phrase-file ./src/fixtures/wallet/node0RecoveryPhrase -p ./src/fixtures/wallet/passphrase --home ~/.vegacapsule/testnet/wallet'
);
cy.exec(
'vega wallet import -w node1_wallet --recovery-phrase-file ./src/fixtures/wallet/node1RecoveryPhrase -p ./src/fixtures/wallet/passphrase --home ~/.vegacapsule/testnet/wallet'
);
// Initialise api token
cy.exec(
'vega wallet api-token init --home ~/.vegacapsule/testnet/wallet --passphrase-file ./src/fixtures/wallet/passphrase'
);
// Generate api tokens for wallets
cy.exec(
'vega wallet api-token generate --wallet-name node0_wallet --tokens-passphrase-file ./src/fixtures/wallet/passphrase --wallet-passphrase-file ./src/fixtures/wallet/passphrase --home ~/.vegacapsule/testnet/wallet'
)
.its('stdout')
.then((result) => {
const apiToken = result.match('[a-zA-Z0-9]{64}');
if (apiToken) {
cy.wrap(apiToken[0]).as('node0ApiToken');
}
});
cy.exec(
'vega wallet api-token generate --wallet-name node1_wallet --tokens-passphrase-file ./src/fixtures/wallet/passphrase --wallet-passphrase-file ./src/fixtures/wallet/passphrase --home ~/.vegacapsule/testnet/wallet'
)
.its('stdout')
.then((result) => {
const apiToken = result.match('[a-zA-Z0-9]{64}');
if (apiToken) {
cy.wrap(apiToken[0]).as('node1ApiToken');
}
});
});
};

View File

@ -0,0 +1,130 @@
import { selfDelegate } from '../capsule/self-delegate';
declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace Cypress {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
interface Chainable<Subject> {
validatorsSelfDelegate(): void;
}
}
}
export const addValidatorsSelfDelegate = () => {
Cypress.Commands.add('validatorsSelfDelegate', () => {
const config = {
ethWalletMnemonic: Cypress.env('ETH_WALLET_MNEMONIC'),
ethereumProviderUrl: Cypress.env('ETHEREUM_PROVIDER_URL'),
vegaWalletUrl: Cypress.env('VEGA_WALLET_URL'),
vegaUrl: Cypress.env('VEGA_URL'),
faucetUrl: Cypress.env('FAUCET_URL'),
};
// Get node wallet recovery phrases
cy.exec('vegacapsule nodes ls --home-path ~/.vegacapsule/testnet/')
.its('stdout')
.then((result) => {
const obj = JSON.parse(result);
console.log(obj);
cy.writeFile(
'./src/fixtures/wallet/node0RecoveryPhrase',
obj['testnet-nodeset-validators-0-validator'].Vega.NodeWalletInfo
.VegaWalletRecoveryPhrase
);
cy.writeFile(
'./src/fixtures/wallet/node1RecoveryPhrase',
obj['testnet-nodeset-validators-1-validator'].Vega.NodeWalletInfo
.VegaWalletRecoveryPhrase
);
cy.wrap(
obj['testnet-nodeset-validators-0-validator'].Vega.NodeWalletInfo
.VegaWalletPublicKey
).as('node0PubKey');
cy.wrap(
obj['testnet-nodeset-validators-1-validator'].Vega.NodeWalletInfo
.VegaWalletPublicKey
).as('node1PubKey');
cy.wrap(
obj['testnet-nodeset-validators-0-validator'].Vega.NodeWalletInfo
.VegaWalletID
).as('node0Id');
cy.wrap(
obj['testnet-nodeset-validators-1-validator'].Vega.NodeWalletInfo
.VegaWalletID
).as('node1Id');
});
// Import node wallets
cy.exec(
'vega wallet import -w node0_wallet --recovery-phrase-file ./src/fixtures/wallet/node0RecoveryPhrase -p ./src/fixtures/wallet/passphrase --home ~/.vegacapsule/testnet/wallet'
);
cy.exec(
'vega wallet import -w node1_wallet --recovery-phrase-file ./src/fixtures/wallet/node1RecoveryPhrase -p ./src/fixtures/wallet/passphrase --home ~/.vegacapsule/testnet/wallet'
);
// Initialise api token
cy.exec(
'vega wallet api-token init --home ~/.vegacapsule/testnet/wallet --passphrase-file ./src/fixtures/wallet/passphrase'
);
// Generate api tokens for wallets
cy.exec(
'vega wallet api-token generate --wallet-name node0_wallet --tokens-passphrase-file ./src/fixtures/wallet/passphrase --wallet-passphrase-file ./src/fixtures/wallet/passphrase --home ~/.vegacapsule/testnet/wallet'
)
.its('stdout')
.then((result) => {
const apiToken = result.match('[a-zA-Z0-9]{64}');
if (apiToken) {
cy.wrap(apiToken[0]).as('node0ApiToken');
}
});
cy.exec(
'vega wallet api-token generate --wallet-name node1_wallet --tokens-passphrase-file ./src/fixtures/wallet/passphrase --wallet-passphrase-file ./src/fixtures/wallet/passphrase --home ~/.vegacapsule/testnet/wallet'
)
.its('stdout')
.then((result) => {
const apiToken = result.match('[a-zA-Z0-9]{64}');
if (apiToken) {
cy.wrap(apiToken[0]).as('node1ApiToken');
}
});
cy.updateCapsuleMultiSig();
cy.highlight('Validators self-delegating');
// Self delegating Node 0 wallet
cy.get('@node0PubKey').then((node0PubKey) => {
cy.get('@node0ApiToken').then((node0ApiToken) => {
cy.get('@node0Id').then((node0Id) => {
cy.wrap(
selfDelegate(
config,
String(node0PubKey),
String(node0ApiToken),
String(node0Id)
),
{ timeout: 60000 }
);
// Self delegating Node 1 wallet
cy.get('@node1PubKey').then((node1PubKey) => {
cy.get('@node1ApiToken').then((node1ApiToken) => {
cy.get('@node1Id').then((node1Id) => {
cy.wrap(
selfDelegate(
config,
String(node1PubKey),
String(node1ApiToken),
String(node1Id)
),
{ timeout: 60000 }
);
});
});
});
});
});
});
});
};

View File

@ -201,7 +201,7 @@
"reward.staking.delegation.delegatorShare": "0.883",
"reward.staking.delegation.maxPayoutPerParticipant": "700000000000000000000",
"reward.staking.delegation.minimumValidatorStake": "3000000000000000000000",
"reward.staking.delegation.payoutDelay": "5m",
"reward.staking.delegation.payoutDelay": "10s",
"reward.staking.delegation.payoutFraction": "0.007",
"spam.protection.delegation.min.tokens": "1000000000000000000",
"spam.protection.max.delegations": "390",